From 15257a911db47f635067c205cc8a59223c759170 Mon Sep 17 00:00:00 2001 From: Laurence Withers Date: Tue, 10 Oct 2006 16:58:06 +0100 Subject: [PATCH] More WIP. Ready for 1.0.0 release. --- README | 29 ++++++++++++++++++ src/mini-at/TopSource.c | 4 +++ src/mini-at/build.monolithic | 2 +- src/mini-at/main.c | 33 ++++++++++++++++---- src/mini-at/socket.c | 39 ++++++++++++++++++++++++ src/mini-at/stdin.c | 58 ++++++++++++++++++++++++++++++++++++ src/mini-atd/main.c | 1 + src/mini-atd/setup.c | 3 ++ src/mini-atd/socket.c | 6 ++-- src/mini-atd/time.c | 26 +++++++++++++++- version | 2 +- 11 files changed, 192 insertions(+), 11 deletions(-) create mode 100644 src/mini-at/socket.c create mode 100644 src/mini-at/stdin.c diff --git a/README b/README index fa95696..86b4c63 100644 --- a/README +++ b/README @@ -23,3 +23,32 @@ Why this and not the standard `at' suite? deleted. 4) Flexible user control through use of Uinx sockets. +Instructions +------------ + +Run the programs with `--help' for a summary. + +The daemon, mini-atd, must be run in the background. It is responsible for keeping track of commands +to run and for running them at the appropriate time. The client, mini-at, uses a named socket to +communicate with the daemon. By default, the daemon creates this socket at ``~/.mini-atd''. + +The daemon can either run in the foreground (default) or in the background, with the `--daemon' or +`-d' option. You can change the name of the socket it uses, and the permissions on the socket. By +default, the permissions are 0600. This means that only the user who ran the daemon (or root) can +cause commands to be run. Commands are always run as the user who ran the daemon, so it is important +to ensure that only trusted users have access to the socket. + +The client uses a time specification in ISO8601. If you don't fully specify the time, it uses the +earliest possible interpretation (so `2006' would give `2006-01-01T00:00:00'). If no time zone is +specified, UTC is assumed, but it is best to explicitly indicate this with a Z. + +If you wish to provide stdin other than /dev/null for a process, then you can specify a file on the +client commandline using `-f' or `--file'. Note that this file will be deleted once the process is +run. Alternatively, you can use `-f -' and pipe the content you want to the stdin of the client, +which will store a copy in a temporary file. + +If you wish to run one program but pretend that you've run it as something else, you can specify the +argv0 option in the client. By default, this will just be a copy of the command name. + +The client will copy its commandline arguments from the shell, and performs no processing on them. +This means that it does not expand words or perform quoting. diff --git a/src/mini-at/TopSource.c b/src/mini-at/TopSource.c index 349f39f..f215c82 100644 --- a/src/mini-at/TopSource.c +++ b/src/mini-at/TopSource.c @@ -14,6 +14,10 @@ #include #include #include +#include +#include +#include +#include diff --git a/src/mini-at/build.monolithic b/src/mini-at/build.monolithic index 83ccae7..3504b4a 100644 --- a/src/mini-at/build.monolithic +++ b/src/mini-at/build.monolithic @@ -8,7 +8,7 @@ MONOLITHIC_TESTS="src/mini-at/build.app src/mini-at/build.monolithic" if [ -z "${mini_at_MONOLITHIC}" ] then MONOLITHIC_SOURCE="src/common/mini-at.h - $(echo src/mini-at/{TopSource,time,main}.c)" + $(echo src/mini-at/{TopSource,time,stdin,socket,main}.c)" make_monolithic ${SRC} C || return 1 mini_at_MONOLITHIC=1 diff --git a/src/mini-at/main.c b/src/mini-at/main.c index 432dad8..3f3b563 100644 --- a/src/mini-at/main.c +++ b/src/mini-at/main.c @@ -37,6 +37,7 @@ void usage(void) "-V, --version Display version.\n" "-f, --file Specify filename to read stdin from, - to copy stdin.\n" "-0, --argv0 Change argv[0] from `cmd' to `x'.\n" + "-s, --socket Name of mini-atd's socket (default: ~/.mini-atd).\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" @@ -58,14 +59,14 @@ struct option options[] = { int main(int argc, char* argv[]) { - const char* stdin_file = 0, * argv0 = 0; + const char* stdin_file = 0, * argv0 = 0, * socket = 0; struct at_msg a; - char msg[AT_MSG_SIZE]; + char msg[AT_MSG_SIZE], sockbuf[sizeof(struct sockaddr_un) - sizeof(int)]; int size, i, x; time_t t; while(1) { - switch(getopt_long(argc, argv, "hVf:0:", options, 0)) { + switch(getopt_long(argc, argv, "hVf:0:s:", options, 0)) { case -1: goto done; @@ -92,6 +93,14 @@ int main(int argc, char* argv[]) } argv0 = optarg; break; + + case 's': + if(socket) { + fprintf(stderr, "Socket can only be specified once.\n"); + return 1; + } + socket = optarg; + break; } } @@ -122,6 +131,7 @@ done: a.cmd_len = strlen(argv[0]); if(stdin_file) { stdin_file = do_stdin(stdin_file); + if(!stdin_file) return 1; a.in_fn_len = strlen(stdin_file); } a.num_args = argc; @@ -143,10 +153,21 @@ done: msg_add(msg, &size, argv[i], x); } - // send message - // TODO + a.magic = ~a.magic; + msg_add(msg, &size, (char*)&a.magic, sizeof(a.magic)); - return 0; + // send message + if(!socket) { + socket = getenv("HOME"); + if(!socket) { + fprintf(stderr, "$HOME not set, cannot find socket\n"); + return 1; + } + snprintf(sockbuf, sizeof(sockbuf) - 1, "%s/.mini-atd", socket); + sockbuf[sizeof(sockbuf) - 1] = 0; + socket = sockbuf; + } + return send_message(socket, msg, size); } diff --git a/src/mini-at/socket.c b/src/mini-at/socket.c new file mode 100644 index 0000000..686f60f --- /dev/null +++ b/src/mini-at/socket.c @@ -0,0 +1,39 @@ +/* mini-at/src/mini-at/TopSource.c + * + * (c)2006, Laurence Withers, . + * Released under the GNU GPLv2. See file COPYING or + * http://www.gnu.org/copyleft/gpl.html for details. +*/ + + + +/* send_message() + * + * Sends the message `msg' (of `size' bytes) to the unix socket `sockname'. Returns 0 on success. + */ +int send_message(const char* sockname, const char* msg, int size) +{ + int fd; + ssize_t wr; + struct sockaddr_un addr; + + fd = socket(PF_UNIX, SOCK_DGRAM, 0); + memset(&addr, 0, sizeof(addr)); + addr.sun_family = AF_UNIX; + strcpy(addr.sun_path, sockname); + + wr = sendto(fd, msg, size, 0, (struct sockaddr*)&addr, sizeof(addr)); + if(wr == -1) { + perror("sendto"); + return 1; + } + + return 0; +} + + + +/* options for text editors +kate: replace-trailing-space-save true; space-indent true; tab-width 4; +vim: expandtab:ts=4:sw=4 +*/ diff --git a/src/mini-at/stdin.c b/src/mini-at/stdin.c new file mode 100644 index 0000000..8f3e7f5 --- /dev/null +++ b/src/mini-at/stdin.c @@ -0,0 +1,58 @@ +/* mini-at/src/mini-at/stdin.c + * + * (c)2006, Laurence Withers, . + * Released under the GNU GPLv2. See file COPYING or + * http://www.gnu.org/copyleft/gpl.html for details. +*/ + + + +/* do_stdin() + * + * Copies data from the file specified in `filename' (or from stdin if `-'). At present, we don't + * create a copy of an existing file; we merely point at it. Perhaps an option could be added to + * do the copy, but `cat' could do the job just as easily. + */ +const char* do_stdin(const char* filename) +{ + ssize_t rd; + char buf[1024]; + static char fn[] = "/tmp/mini-at-stdin.XXXXXX"; + int tfd; + + // just point at existing file + if(strcmp(filename, "-")) return filename; + + // open temporary file (relies on libc opening it mode 0600) + tfd = mkstemp(fn); + if(tfd == -1) { + perror("mkstemp"); + return 0; + } + + // copy stdin to a temporary file + while(1) { + rd = read(0, buf, sizeof(buf)); + switch(rd) { + case -1: + perror("read"); + return 0; + + case 0: // EOF + return fn; + + default: + if(write(tfd, buf, rd) != rd) { + perror("write"); + return 0; + } + } + } +} + + + +/* options for text editors +kate: replace-trailing-space-save true; space-indent true; tab-width 4; +vim: expandtab:ts=4:sw=4 +*/ diff --git a/src/mini-atd/main.c b/src/mini-atd/main.c index 8edce04..1ae22cf 100644 --- a/src/mini-atd/main.c +++ b/src/mini-atd/main.c @@ -123,6 +123,7 @@ done: fd = setup_socket(fn_buf, perms); if(fd == -1) return 1; memset(&tdb, 0, sizeof(tdb)); + _debug_time_db = &tdb; // process while(!Quit) { diff --git a/src/mini-atd/setup.c b/src/mini-atd/setup.c index a041afe..0f20317 100644 --- a/src/mini-atd/setup.c +++ b/src/mini-atd/setup.c @@ -165,10 +165,13 @@ void signal_handler(int sig) signal(sig, SIG_DFL); } +void debug_handler(int sig); + void setup_signals(void) { signal(SIGINT, signal_handler); signal(SIGTERM, signal_handler); + signal(SIGUSR1, debug_handler); } diff --git a/src/mini-atd/socket.c b/src/mini-atd/socket.c index 3d21645..e4fa65e 100644 --- a/src/mini-atd/socket.c +++ b/src/mini-atd/socket.c @@ -17,7 +17,9 @@ 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; + int i, j, realsize; + + realsize = size; memset(&t, 0, sizeof(t)); @@ -91,7 +93,7 @@ void process_message(const char* buf, int size, struct time_db* tdb) return; bad: - LOG(LOG_WARNING, "bad message of %d bytes received through socket.", size); + LOG(LOG_WARNING, "bad message of %d bytes received through socket.", realsize); } diff --git a/src/mini-atd/time.c b/src/mini-atd/time.c index 84cba56..43b497c 100644 --- a/src/mini-atd/time.c +++ b/src/mini-atd/time.c @@ -151,7 +151,7 @@ void process_time_db(struct time_db* tdb) time(&now); iter = tdb->head; - while(iter && now <= iter->when) { + while(iter && now >= iter->when) { // run this command pid = process_time_db_entry(iter); if(pid != -1) { @@ -225,6 +225,30 @@ void add_time_db_entry(struct time_db* tdb, const struct time_db_entry* t) +struct time_db* _debug_time_db = 0; +void dump_time_db(struct time_db* tdb) +{ + int i; + struct tm tm; + struct time_db_entry* iter; + + for(i = 0; i < tdb->num_pids; ++i) LOG(LOG_DEBUG, "waiting on PID %lu", (long)tdb->pids[i]); + for(iter = tdb->head; iter; iter = iter->next) { + gmtime_r(&iter->when, &tm); + LOG(LOG_DEBUG, "time database has entry %s for %04d%02d%02dT%02d%02d%02d", + iter->path, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); + } +} + +void debug_handler(int sig) +{ + signal(sig, debug_handler); + if(_debug_time_db) dump_time_db(_debug_time_db); + else LOG(LOG_DEBUG, "no time database"); +} + + + /* options for text editors kate: replace-trailing-space-save true; space-indent true; tab-width 4; vim: expandtab:ts=4:sw=4 diff --git a/version b/version index 1d9906f..fafb486 100644 --- a/version +++ b/version @@ -10,7 +10,7 @@ # VERSION contains the full version number of the library, which is # expected to be in 'major.minor.micro' format. It can optionally be # suffixed with a string. -VERMAJOR=0 +VERMAJOR=1 VERMINOR=0 VERMICRO=0 VEREXTRA=""