More WIP. Ready for 1.0.0 release.
This commit is contained in:
parent
b2739c367a
commit
15257a911d
29
README
29
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.
|
||||
|
|
|
@ -14,6 +14,10 @@
|
|||
#include <getopt.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/un.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -37,6 +37,7 @@ void usage(void)
|
|||
"-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"
|
||||
"-s, --socket <x> 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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
/* mini-at/src/mini-at/TopSource.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.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/* 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
|
||||
*/
|
|
@ -0,0 +1,58 @@
|
|||
/* mini-at/src/mini-at/stdin.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.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/* 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
|
||||
*/
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue