Further WIP

This commit is contained in:
Laurence Withers 2006-10-09 17:55:18 +01:00
parent 0867c8acab
commit eaefdc0438
7 changed files with 333 additions and 12 deletions

48
src/common/mini-at.h Normal file
View File

@ -0,0 +1,48 @@
/* mini-at/src/mini-atd/time.c
*
* (c)2006, Laurence Withers, <l@lwithers.me.uk>.
* Released under the GNU GPLv2. See file COPYING or
* http://www.gnu.org/copyleft/gpl.html for details.
*/
/* AT_MAGIC
*
* This number, "MNAT" in ASCII, is prepended to the message (and its complement concatenated).
* This stops random writes to the socket from being interpreted.
*/
#define AT_MAGIC 0x4D4E4154
/* AT_MSG_SIZE
*
* The biggest packet we read/write from the socket. This limits the length of the commandline,
* so we ideally want it to be as large as possible.
*/
#define AT_MSG_SIZE 0x8000
/* struct at_msg
*
* The header of any message written to the socket. After the header, we find the path and input
* filename path data, followed by num_args * [int arg_len, arg]. The structure ends with
* ~AT_MAGIC.
*/
struct at_msg {
int magic; // must be AT_MAGIC
int version; // (major << 20) | (minor << 10) | micro
int when; // time_t
int cmd_len; // length of path, in bytes, excluding \0
int in_fn_len; // for stdin filename, 0 if no redirection
int num_args; // number of commandline arguments, always > 0
};
/* options for text editors
kate: replace-trailing-space-save true; space-indent true; tab-width 4;
vim: expandtab:ts=4:sw=4
*/

View File

@ -5,13 +5,13 @@
* http://www.gnu.org/copyleft/gpl.html for details. * http://www.gnu.org/copyleft/gpl.html for details.
*/ */
// Below are all the includes used throughout the application. // Below are all the includes used throughout the application.
#include <stdio.h>
#include <getopt.h>
int main(void)
{
return 0;
}
/* options for text editors /* options for text editors
kate: replace-trailing-space-save true; space-indent true; tab-width 4; kate: replace-trailing-space-save true; space-indent true; tab-width 4;

138
src/mini-at/main.c Normal file
View File

@ -0,0 +1,138 @@
/* mini-at/src/mini-at/main.c
*
* (c)2006, Laurence Withers, <l@lwithers.me.uk>.
* Released under the GNU GPLv2. See file COPYING or
* http://www.gnu.org/copyleft/gpl.html for details.
*/
void version(void)
{
printf("mini-at " VERSION "\n"
"(c)2006, Laurence Withers.\n");
}
void usage(void)
{
printf("Usage:\n\n"
" mini-at [options] time cmd [args ...]\n\n"
"Options:\n"
"-h, --help Display this screen.\n"
"-V, --version Display version.\n"
"-f, --file <x> Specify filename to read stdin from, - to copy stdin.\n",
"-0, --argv0 <x> Change argv[0] from `cmd' to `x'.\n"
"\n"
"'time' is an ISO8601 time. If you specify an incomplete time, e.g. '2010', we simply\n"
"take the earliest time it could represent (i.e. 2010-01-01T00:00:00).\n"
"\n");
version();
}
struct option options[] = {
{ "help", no_argument, 0, 'h' },
{ "version", no_argument, 0, 'V' },
{ "file", required_argument, 0, 'f' },
{ "argv0", required_argument, 0, '0' },
{ 0, 0, 0, 0 }
}
int main(int argc, char* argv[])
{
const char* stdin_file = 0, * argv0 = 0;
struct at_msg a;
char msg[AT_MSG_SIZE];
int size, i, x;
while(1) {
switch(getopt_long(argc, argv, "hVf:0:", options, 0)) {
case -1:
goto done;
case 'h':
usage();
return 0;
case 'V':
version();
return 0;
case 'f':
if(stdin_file) {
fprintf(stderr, "Input file can only be specified once.\n");
return 1;
}
stdin_file = optarg;
break;
case '0':
if(argv0) {
fprintf(stderr, "argv[0] can only be specified once.\n");
return 1;
}
argv0 = optarg;
break;
}
}
done:
argv += optind;
argc -= optind;
if(argc < 2) {
usage();
return 1;
}
// parse time
t = parse_time(argv[0]);
if(t == (time_t)-1) return 1;
++argv;
--argc;
// set up message header
memset(&a, 0, sizeof(a));
a.magic = AT_MAGIC;
a.version = (VERMAJOR << 20) | (VERMINOR << 10) | VERMICRO;
a.when = t;
a.cmd_len = strlen(argv[0]);
if(stdin_file) {
stdin_file = do_stdin(stdin_file);
a.in_fn_len = strlen(stdin_file);
}
a.num_args = argc;
// set up message
size = 0;
msg_add(msg, &size, &a, sizeof(a));
msg_add(msg, &size, argv[0], a.cmd_len);
if(stdin_file) msg_add(msg, &size, stdin_file, a.in_fn_len);
if(!argv0) argv0 = argv[0];
x = strlen(argv0);
msg_add(msg, &size, &x, sizeof(x));
msg_add(msg, &size, argv0, x);
for(i = 1; i < argc; ++i) {
x = strlen(argv[i]);
msg_add(msg, &size, &x, sizeof(x));
msg_add(msg, &size, argv[i], x);
}
// send message
// TODO
return 0;
}
/* options for text editors
kate: replace-trailing-space-save true; space-indent true; tab-width 4;
vim: expandtab:ts=4:sw=4
*/

View File

@ -7,7 +7,8 @@ MONOLITHIC_TESTS="src/mini-atd/build.app src/mini-atd/build.monolithic"
if [ -z "${mini_atd_MONOLITHIC}" ] if [ -z "${mini_atd_MONOLITHIC}" ]
then then
MONOLITHIC_SOURCE="$(echo src/mini-atd/{TopSource,setup,util,time,main}.c)" MONOLITHIC_SOURCE="src/common/mini-at.h
$(echo src/mini-atd/{TopSource,setup,util,time,socket,main}.c)"
make_monolithic ${SRC} C || return 1 make_monolithic ${SRC} C || return 1
mini_atd_MONOLITHIC=1 mini_atd_MONOLITHIC=1

View File

@ -47,6 +47,7 @@ int main(int argc, char* argv[])
char* endp; char* endp;
int perms = -1, daemon = 0, fd = -1; int perms = -1, daemon = 0, fd = -1;
char fn_buf[sizeof(struct sockaddr_un) - sizeof(int)]; // not perfect, but solves build errors char fn_buf[sizeof(struct sockaddr_un) - sizeof(int)]; // not perfect, but solves build errors
struct time_db tdb;
// process commandline options // process commandline options
while(1) { while(1) {
@ -121,10 +122,12 @@ done:
setup_signals(); setup_signals();
fd = setup_socket(fn_buf, perms); fd = setup_socket(fn_buf, perms);
if(fd == -1) return 1; if(fd == -1) return 1;
memset(&tdb, 0, sizeof(tdb));
// process // process
while(!Quit) { while(!Quit) {
// if(process_socket(fd)) return 1; if(process_socket(fd, &tdb)) return 1;
process_time_db(&tdb);
sleep(1); sleep(1);
} }

128
src/mini-atd/socket.c Normal file
View File

@ -0,0 +1,128 @@
/* mini-at/src/mini-atd/socket.c
*
* (c)2006, Laurence Withers, <l@lwithers.me.uk>.
* Released under the GNU GPLv2. See file COPYING or
* http://www.gnu.org/copyleft/gpl.html for details.
*/
/* process_message()
*
* This is called whenever we receive a single message. It should decode the message and add an
* entry to the time database `tdb'.
*/
void process_message(const char* buf, int size, struct time_db* tdb)
{
struct at_msg a;
struct time_db_entry t;
struct tm* tm;
int i, j;
memset(&t, 0, sizeof(t));
// sanity checking
if(size < (int)sizeof(struct at_msg)) goto bad;
memcpy(&a, buf, sizeof(a));
if(a.magic != AT_MAGIC) {
LOG(LOG_WARNING, "bad message received through socket (magic was 0x%X, should be 0x%X).",
a.magic, AT_MAGIC);
return;
}
if(a.version != ((VERMAJOR << 20) | (VERMINOR << 10) | VERMICRO)) {
LOG(LOG_WARNING, "version mismatch (got %d.%d.%d, expected " VERSION ").",
a.version >> 20, (a.version >> 10) & 0x3FF, a.version & 0x3FF);
return;
}
t.when = a.when;
t.num_args = a.num_args;
buf += sizeof(struct at_msg);
size -= sizeof(struct at_msg);
// sanity check
if(a.cmd_len < 1 || a.in_fn_len < 0 || a.num_args < 1
|| size < a.cmd_len + a.in_fn_len) goto bad;
// read in the command path
t.path = safe_malloc(a.cmd_len + 1);
memcpy(t.path, buf, a.cmd_len);
buf += a.cmd_len;
size -= a.cmd_len;
// read in (optional) input filename
if(a.in_fn_len) {
t.in = safe_malloc(a.in_fn_len + 1);
memcpy(t.in, buf, a.in_fn_len);
buf += a.in_fn_len;
size -= a.in_fn_len;
}
// now read in arguments
t.args = safe_malloc(sizeof(char*) * (t.num_args + 1)); // extra +1 for NULL for execve
for(i = 0; i < t.num_args; ++i) {
if(size < (int)sizeof(int)) goto bad;
memcpy(&j, buf, sizeof(int));
if(j < 0) goto bad;
buf += sizeof(int);
size -= sizeof(int);
if(size < j) goto bad;
t.args[i] = safe_malloc(j + 1);
if(j) {
memcpy(t.args[i], buf, j);
buf += j;
size -= j;
}
}
// check for end
if(size != sizeof(int)) goto bad;
memcpy(&j, buf, sizeof(int));
if(j != ~AT_MAGIC) goto bad;
// done -- insert our new entry
tm = gmtime(&t.when);
LOG(LOG_INFO, "Command ``%s'' scheduled for %04d-%02d-%02dT%02d:%02d:%02d",
t.path, tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
add_time_db_entry(tdb, &t);
return;
bad:
LOG(LOG_WARNING, "bad message of %d bytes received through socket.", size);
}
/* process_socket()
*
* Checks the socket for input; if some is available, processes it.
*/
int process_socket(int fd, struct time_db* tdb)
{
ssize_t rd;
char buf[AT_MSG_SIZE];
while(1) {
rd = read(fd, buf, sizeof(buf));
if(rd == -1) {
if(errno == EINTR) continue;
if(errno == EAGAIN) return 0;
LOG(LOG_CRIT, "read() on socket fd %d failed - %s (%d).",
fd, strerror(errno), errno);
return -1;
}
process_message(buf, rd, tdb);
}
}
/* options for text editors
kate: replace-trailing-space-save true; space-indent true; tab-width 4;
vim: expandtab:ts=4:sw=4
*/

View File

@ -201,11 +201,14 @@ void free_time_db(struct time_db* tdb)
/* add_time_db_entry() /* add_time_db_entry()
* *
* Adds an entry `t' into the time database `tdb'. Does a sorted list insert. * Adds an entry `t' into the time database `tdb'. Bitwise copies `t'. Does a sorted list insert.
*/ */
void add_time_db_entry(struct time_db* tdb, struct time_db_entry* t) void add_time_db_entry(struct time_db* tdb, const struct time_db_entry* t)
{ {
struct time_db_entry* iter, * prev; struct time_db_entry* iter, * prev, * new;
new = safe_malloc(sizeof(struct time_db_entry));
memcpy(new, t, sizeof(struct time_db_entry));
prev = 0; prev = 0;
iter = tdb->head; iter = tdb->head;
@ -214,10 +217,10 @@ void add_time_db_entry(struct time_db* tdb, struct time_db_entry* t)
prev = iter; prev = iter;
iter = iter->next; iter = iter->next;
} }
t->next = iter; new->next = iter;
if(prev) prev->next = t; if(prev) prev->next = new;
else tdb->head = t; else tdb->head = new;
} }