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.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
// Below are all the includes used throughout the application.
|
||||
#include <stdio.h>
|
||||
#include <getopt.h>
|
||||
|
||||
|
||||
int main(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* options for text editors
|
||||
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}" ]
|
||||
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
|
||||
|
||||
mini_atd_MONOLITHIC=1
|
||||
|
|
|
@ -47,6 +47,7 @@ int main(int argc, char* argv[])
|
|||
char* endp;
|
||||
int perms = -1, daemon = 0, fd = -1;
|
||||
char fn_buf[sizeof(struct sockaddr_un) - sizeof(int)]; // not perfect, but solves build errors
|
||||
struct time_db tdb;
|
||||
|
||||
// process commandline options
|
||||
while(1) {
|
||||
|
@ -121,10 +122,12 @@ done:
|
|||
setup_signals();
|
||||
fd = setup_socket(fn_buf, perms);
|
||||
if(fd == -1) return 1;
|
||||
memset(&tdb, 0, sizeof(tdb));
|
||||
|
||||
// process
|
||||
while(!Quit) {
|
||||
// if(process_socket(fd)) return 1;
|
||||
if(process_socket(fd, &tdb)) return 1;
|
||||
process_time_db(&tdb);
|
||||
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()
|
||||
*
|
||||
* 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;
|
||||
iter = tdb->head;
|
||||
|
@ -214,10 +217,10 @@ void add_time_db_entry(struct time_db* tdb, struct time_db_entry* t)
|
|||
prev = iter;
|
||||
iter = iter->next;
|
||||
}
|
||||
t->next = iter;
|
||||
new->next = iter;
|
||||
|
||||
if(prev) prev->next = t;
|
||||
else tdb->head = t;
|
||||
if(prev) prev->next = new;
|
||||
else tdb->head = new;
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue