Further WIP
This commit is contained in:
parent
0867c8acab
commit
eaefdc0438
|
@ -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
|
||||||
|
*/
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
*/
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
*/
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue