Did some stuff master
authorSam Moore <[email protected]>
Sat, 23 Feb 2013 10:34:52 +0000 (18:34 +0800)
committerSam Moore <[email protected]>
Sat, 23 Feb 2013 10:34:52 +0000 (18:34 +0800)
I think I fixed a bug, and tried to document things
Basically things work, but I need to make the code nicer before I show it off to people

Would be nice to be able to DEABSORB/DETACH or something from remote instances, but I think that's getting carried away
Need to fix the log messages to show what host they come from though

src/main.c
src/master.c
src/master.h
src/options.c
src/options.h
src/slave.c
src/slave.h
src/ssh.c

index baab2b7..536f3c7 100644 (file)
@@ -1,46 +1,75 @@
+/**
+ * @file main.c
+ * @purpose Contains main function, definition of options global variable, and the general signal handler
+ * @author Sam Moore ([email protected])
+ */
+
+// --- external includes --- //
 #include <stdlib.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <stdio.h>
+#include <signal.h>
 
 
+
+// --- local includes --- //
 #include "options.h"
 #include "master.h"
 #include "slave.h"
 #include "daemon.h"
 #include "options.h"
 #include "master.h"
 #include "slave.h"
 #include "daemon.h"
-#include <signal.h>
 
 
 
 
-Options options;
+// --- variable definitions --- //
+Options options; // basically all global variables are contained in this structure
+
+
+// --- function declarations  --- //
+void signal_handler(int signal);
+
 
 
-void Cleanup();
 
 
-void Signal_handler(int signal);
+// --- function definitions --- //
 
 
+/**
+ * @funct main
+ * @purpose The main function; starts argument parsing function, 
+ *     starts appropriate main function based on the type of the instance (interactive, remote, daemon wrapper)
+ * @param argc - You should know what this is. But it's the size of the argv array. In case you didn't know.
+ * @param argv - You should also know what this is. It contains arguments passed to the program.
+ */
 
 int main(int argc, char ** argv)
 {
 
 int main(int argc, char ** argv)
 {
-       atexit(Cleanup);
-       Initialise(argc, argv, &options);
+       options_setup(argc, argv, &options); // fill in the options
 
 
-       if (signal(SIGTERM, Signal_handler) == SIG_ERR)
+       // Setup signal handlers
+       if (signal(SIGTERM, signal_handler) == SIG_ERR)
                error("main", "Setting signal handler");
                error("main", "Setting signal handler");
-       if (signal(SIGINT, Signal_handler) == SIG_ERR)
+       if (signal(SIGINT, signal_handler) == SIG_ERR)
                error("main", "Setting signal handler");
                error("main", "Setting signal handler");
-       if (signal(SIGHUP, Signal_handler) == SIG_ERR)
+       if (signal(SIGHUP, signal_handler) == SIG_ERR)
                error("main", "Setting signal handler");
                error("main", "Setting signal handler");
-       if (signal(SIGPIPE, Signal_handler) == SIG_ERR)
+       if (signal(SIGPIPE, signal_handler) == SIG_ERR)
                error("main", "Setting signal handler");
                error("main", "Setting signal handler");
-       //if (signal(SIGSEGV, Signal_handler) == SIG_ERR)
+       //if (signal(SIGSEGV, signal_handler) == SIG_ERR)
        //      error("main", "Setting signal handler");
 
        //      error("main", "Setting signal handler");
 
-       if (options.master_addr == NULL)
+
+       // Start the appropriate actual main function
+       if (options.master_addr == NULL) // This is not a "remote" instance
        {
                if (options.daemon_wrapper)
        {
                if (options.daemon_wrapper)
+               {
+                       // There is a daemon running; send commands to the daemon
                        Daemon_wrapper(&options);
                        Daemon_wrapper(&options);
+               }
                else
                else
+               {
+                       // Daemons and interactive instances run this function
                        Master_main(&options);
                        Master_main(&options);
+               }
        }
        else
        {
        }
        else
        {
-               fprintf(stderr, "%p %s", options.master_addr, options.master_addr);
+               // Remote instance
                Slave_main(&options);
        }
 
                Slave_main(&options);
        }
 
@@ -48,17 +77,20 @@ int main(int argc, char ** argv)
        return 0;       
 }
 
        return 0;       
 }
 
-void Signal_handler(int sig)
+/**
+ * @funct signal_handler
+ * @purpose Handle any signals that would cause the program to terminate
+ * @param sig - The signal number
+ */
+void signal_handler(int sig)
 {
 {
-       
-       signal(sig, SIG_IGN);
+       // There is a bit of a race condition with the SIGCHLD handler
+       // We can't be sure whether this handler gets called first, or SIGCHLD (due to a child getting the signal)
+       // We need to ignore SIGCHLD if this handler gets called first  
        signal(SIGCHLD, SIG_IGN);
        signal(SIGCHLD, SIG_IGN);
+       signal(sig, SIG_IGN); // I'm not sure why we need this? //TODO: Remove?
+
        log_print(2, "Signal_handler", "Got signal %d; exiting", sig);
        exit(EXIT_SUCCESS);
 }
 
        log_print(2, "Signal_handler", "Got signal %d; exiting", sig);
        exit(EXIT_SUCCESS);
 }
 
-
-void Cleanup()
-{
-
-}
index 2734d07..f5e17eb 100644 (file)
@@ -2,6 +2,7 @@
 #include "master.h"
 #include "log.h"
 
 #include "master.h"
 #include "log.h"
 
+#include <string.h>
 #include <sys/wait.h>
 #include "daemon.h"
 #include <stdlib.h>
 #include <sys/wait.h>
 #include "daemon.h"
 #include <stdlib.h>
@@ -101,7 +102,19 @@ void Master_setup(Options * o)
        // One slave per CPU
        for (int i = 0; i < master.nSlaves; ++i)
        {
        // One slave per CPU
        for (int i = 0; i < master.nSlaves; ++i)
        {
-               Make_slave(i);
+
+               
+               int sv[2];
+               // Possibly the best function ever
+               if (socketpair(AF_UNIX, SOCK_STREAM, 0, sv) != 0)
+               {
+                       error("Make_slave", "Setting up socketpair for slave %d : %s", i, strerror(errno));
+               }
+               master.slave[i].in = sv[1];
+               master.slave[i].out = sv[1];
+               master.slave[i].socket_child_end = sv[0];
+
+               Master_shell(i);
 
 
                
 
 
                
@@ -114,23 +127,16 @@ void Master_setup(Options * o)
        }
 }
 
        }
 }
 
-void Make_slave(int i)
-{
-       int sv[2];
-       if (socketpair(AF_UNIX, SOCK_STREAM, 0, sv) != 0)
-       {
-               error("Make_slave", "Setting up socketpair for slave %d : %s", i, strerror(errno));
-       }
-       
+void Master_shell(int i)
+{      
        master.slave[i].pid = fork();
        if (master.slave[i].pid == 0)
        {
        master.slave[i].pid = fork();
        if (master.slave[i].pid == 0)
        {
-               dup2(sv[0],fileno(stdin));
-               dup2(sv[0],fileno(stdout));
+               dup2(master.slave[i].socket_child_end,fileno(stdin));
+               dup2(master.slave[i].socket_child_end,fileno(stdout));
                execlp(master.o->shell, master.o->shell, NULL);
        }
                execlp(master.o->shell, master.o->shell, NULL);
        }
-       master.slave[i].in = sv[1];
-       master.slave[i].out = sv[1];
+
        master.slave[i].running = true;
 }
 
        master.slave[i].running = true;
 }
 
@@ -395,14 +401,19 @@ void Master_output(int i, char c)
                memset(t->output+(t->outlen), 0, sizeof(char) * t->outsiz - t->outlen);
                
        }
                memset(t->output+(t->outlen), 0, sizeof(char) * t->outsiz - t->outlen);
                
        }
-       if (c == EOF || (master.o->endlen > 0 && t->outlen >= master.o->endlen
-               && strcmp((t->output)+(t->outlen)-(master.o->endlen), master.o->end) == 0))
+       if (c == EOF 
+       #ifdef SHELL_OUTPUT_FINISHED
+               || (t->outlen >= SHELL_OUTPUT_FINISHED_LENGTH
+               && strcmp((t->output)+(t->outlen)-(SHELL_OUTPUT_FINISHED_LENGTH), SHELL_OUTPUT_FINISHED) == 0))
+       #else
+       ) // this is totally readable
+       #endif //SHELL_OUTPUT_FINISHED
        {
                
                if (c != EOF)
                {
        {
                
                if (c != EOF)
                {
-                       t->output[t->outlen - master.o->endlen] = '\0';
-                       t->outlen -= master.o->endlen;
+                       t->output[t->outlen - SHELL_OUTPUT_FINISHED_LENGTH] = '\0';
+                       t->outlen -= SHELL_OUTPUT_FINISHED_LENGTH;
                }
 
                master.slave[i].task = NULL;
                }
 
                master.slave[i].task = NULL;
@@ -571,7 +582,7 @@ void Master_loop()
                                if (errno != ENXIO)
                                        error("Master_loop", "Daemon trying to reopen fifo %s : %s", DAEMON_FIFO, strerror(errno));
                                else
                                if (errno != ENXIO)
                                        error("Master_loop", "Daemon trying to reopen fifo %s : %s", DAEMON_FIFO, strerror(errno));
                                else
-                                       log_print(2, "Master_loop", "Daemon couldn't reopen fifo %s : %s", DAEMON_FIFO, strerror(errno));
+                                       log_print(LOGWARN, "Master_loop", "Daemon couldn't reopen fifo %s : %s", DAEMON_FIFO, strerror(errno));
                        }
                        else
                        {
                        }
                        else
                        {
@@ -670,17 +681,18 @@ void Master_send()
                write(send_task.slave_fd, master.o->append, (len-1) * sizeof(char));
                //log_print(0, "Sent append %s\n",master.o->append); 
        }
                write(send_task.slave_fd, master.o->append, (len-1) * sizeof(char));
                //log_print(0, "Sent append %s\n",master.o->append); 
        }
-       if (master.o->end != NULL)
+       #ifdef SHELL_OUTPUT_FINISHED
        {
                static char * echo = ";echo -en \"";
                static int len = -1;
                if (len == -1) len = strlen(echo);
                write(send_task.slave_fd, echo, len*sizeof(char));
        {
                static char * echo = ";echo -en \"";
                static int len = -1;
                if (len == -1) len = strlen(echo);
                write(send_task.slave_fd, echo, len*sizeof(char));
-               write(send_task.slave_fd, master.o->end, (master.o->endlen) * sizeof(char));
-               write(send_task.slave_fd, "\"", 1*sizeof(char));
+               write(send_task.slave_fd, SHELL_OUTPUT_FINISHED, SHELL_OUTPUT_FINISHED_LENGTH * sizeof(char));
+               write(send_task.slave_fd, "\"", sizeof(char));
                //log_print(0, "Sent end\n"); 
        }
                //log_print(0, "Sent end\n"); 
        }
-       write(send_task.slave_fd, "\n", 1*sizeof(char));
+       #endif //SHELL_OUTPUT_FINISHED
+       write(send_task.slave_fd, "\n", sizeof(char));
        master.commands_active++;
        log_print(3, "Master_sender", "Sent task %d \"%s\" on socket %d - %d tasks active", send_task.task->number, send_task.task->message, send_task.slave_fd, master.commands_active);
 }
        master.commands_active++;
        log_print(3, "Master_sender", "Sent task %d \"%s\" on socket %d - %d tasks active", send_task.task->number, send_task.task->message, send_task.slave_fd, master.commands_active);
 }
@@ -741,7 +753,7 @@ void Master_cleanup()
        {
                FILE * f = fdopen(master.remote_err[i], "r+"); setbuf(f, NULL);
 
        {
                FILE * f = fdopen(master.remote_err[i], "r+"); setbuf(f, NULL);
 
-               fprintf(f, "exit\n");
+               fprintf(f, SHELL_EXIT_COMMAND);
        
                fclose(f);
        }
        
                fclose(f);
        }
@@ -750,8 +762,8 @@ void Master_cleanup()
        {
                
                static int exitlen = -1;
        {
                
                static int exitlen = -1;
-               if (exitlen == -1) exitlen = strlen(SHELL_EXIT_MESSAGE);
-               write(master.slave[i].in, SHELL_EXIT_MESSAGE, exitlen *sizeof(char));
+               if (exitlen == -1) exitlen = strlen(SHELL_EXIT_COMMAND);
+               write(master.slave[i].in, SHELL_EXIT_COMMAND, exitlen *sizeof(char));
                //usleep(0.5); //shouldn't matter too much
        }
 
                //usleep(0.5); //shouldn't matter too much
        }
 
@@ -876,7 +888,11 @@ void Master_absorb(char * addr, int np)
        }
        while (buffer[len-1] != '\n');
        buffer[len-1] = '\0';
        }
        while (buffer[len-1] != '\n');
        buffer[len-1] = '\0';
-       newSlaves = atoi(buffer);
+
+       while (newSlaves == 0 && strcmp(buffer, "0") != 0)
+       {
+               newSlaves = atoi(buffer);
+       }
 
        
 
 
        
 
@@ -986,34 +1002,21 @@ void sigchld_handler(int signal)
                return;
        }
 
                return;
        }
 
-       fprintf(stderr, "Unexpected exit of slave %s", master.slave[i].name);
-       if (WIFSIGNALED(s))
-       {
-               int sig = WTERMSIG(s);
-               fprintf(stderr, " due to %s", strsignal(sig));
-               if (sig == SIGKILL)
-               {
-                       printf(" - committing suicide\n");
-                       kill(getpid(), sig);
-               }
-       }
-       else
-       {               
-               fprintf(stderr, " return code %d.",s);
-       }
-       fprintf(stderr, " Starting replacement.\n");
 
 
-       Make_slave(i);
+       sigchld_respond(s, "local", i);
+
+       Master_shell(i);
 
 
-       if (master.o->end != NULL)
+       #ifdef SHELL_OUTPUT_FINISHED
        {
                //log_print(1, "sigchld_handler", "Trying to convince slave %d to be nice", i);
                char buffer[BUFSIZ];
        {
                //log_print(1, "sigchld_handler", "Trying to convince slave %d to be nice", i);
                char buffer[BUFSIZ];
-               sprintf(buffer, "name=%s;echo -en \"%s\"\n", master.slave[i].name, master.o->end);
-               if (write(master.slave[i].in, buffer, strlen(buffer)) <= 0)
+               int len = sprintf(buffer, "name=%s;echo -en \"%s\"\n", master.slave[i].name, SHELL_OUTPUT_FINISHED);
+               if (write(master.slave[i].in, buffer, len) <= 0)
                        error("sigchld_handler", "Couldn't restart slave %d; it is unresponsive", i);
 
        }
                        error("sigchld_handler", "Couldn't restart slave %d; it is unresponsive", i);
 
        }
+       #endif //SHELL_OUTPUT_FINISHED
 
        siglongjmp(env,1);
 
 
        siglongjmp(env,1);
 
index 3595e23..a3288ab 100644 (file)
@@ -15,7 +15,7 @@ extern void Master_cleanup();
 extern void Master_send();
 extern void Master_absorb(char * addr, int np);
 
 extern void Master_send();
 extern void Master_absorb(char * addr, int np);
 
-extern void Make_slave(int i);
+extern void Master_shell(int i);
 extern void sigchld_handler(int signal);
 
 
 extern void sigchld_handler(int signal);
 
 
index ddd2ddc..a230fa9 100644 (file)
-#include "options.h"
+#define _XOPEN_SOURCE 700
+
+/**
+ * @file options.c
+ * @purpose Implementations of functions for populating Options struct
+ *     Also implements helpers and minor cleanup functions
+ * @author Sam Moore ([email protected])
+ */
+
+// --- external includes --- //
 #include <string.h>
 #include <stdlib.h>
 #include <time.h>
 #include <unistd.h>
 #include <string.h>
 #include <stdlib.h>
 #include <time.h>
 #include <unistd.h>
-#include "log.h"
 #include <errno.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <fcntl.h>
 #include <errno.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <fcntl.h>
-#include "daemon.h"
 #include <signal.h>
 #include <signal.h>
+#include <sys/wait.h>
+
 
 
+// --- local includes --- //
+#include "options.h"
+#include "log.h"
+#include "daemon.h"
 
 
-void remove_command()
+/**
+ * @funct cleanup_command
+ * @purpose Removes the COMMAND_FILE used for one off command parsing
+ *     Added to exit table only if needed
+ */
+void cleanup_command() 
 {
        remove(COMMAND_FILE);
 {
        remove(COMMAND_FILE);
-
 }
 
 }
 
-void remove_daemon()
+/**
+ * @funct cleanup_daemon
+ * @purpose Removes files and fifo's used by daemon
+ *     Added to exit table only if needed
+ */
+void cleanup_daemon()
 {
        remove(DAEMON_PID_FILE);
        remove(DAEMON_FIFO);
        remove(DAEMON_BARRIER_FIFO);
 }
 
 {
        remove(DAEMON_PID_FILE);
        remove(DAEMON_FIFO);
        remove(DAEMON_BARRIER_FIFO);
 }
 
-void close_err()
-{
-       fclose(stderr);
-}
 
 
-void close_out()
+/**
+ * @funct Initialise
+ * @purpose Setup default options, call parse_args, do basic setup and initialisation
+ * @param argc - From main
+ * @param argv - From main
+ * @param o - Options struct to setup
+ */
+void options_setup(int argc, char ** argv, Options * o)
 {
 {
-       fclose(stdout);
-}
-
-char name[BUFSIZ];
+       srand(time(NULL)); // rand is used in a few places, so seed the RNG
 
 
-void Initialise(int argc, char ** argv, Options * o)
-{
-       srand(time(NULL));
+       // Setup default options
        o->program = argv[0];
        o->master_addr = NULL;
        o->program = argv[0];
        o->master_addr = NULL;
-       o->shell = "bash"; // choosing other shells seems to not work... for some reason
+       o->shell = "bash"; // choosing other shells will not end well
        o->logfile = NULL;
        o->outfile = NULL;
        o->logfile = NULL;
        o->outfile = NULL;
-       o->verbosity = 2;
+       o->verbosity = LOGNOTE; // default log level
        o->port = 0;
        o->append = NULL;
        o->prepend = NULL;
        o->port = 0;
        o->append = NULL;
        o->prepend = NULL;
-       o->end = "\a\a\a";
        o->nCPU = sysconf( _SC_NPROCESSORS_ONLN );
        o->daemon = false;
        o->nCPU = sysconf( _SC_NPROCESSORS_ONLN );
        o->daemon = false;
-       o->encrypt = true;
        o->interactive = true;
        o->interactive = true;
+       o->encrypt = true;
 
 
-       gethostname(name, sizeof(name));
-       o->name = strdup(name);
+       // Parse arguments      
+       options_parse_args(argc, argv, o);
 
 
-       o->master_pid = getpid();
+       // Initialisation behaviour that depends on option values
        
        
-       ParseArguments(argc, argv, o);
-
-       o->endlen = (o->end != NULL) ? strlen(o->end) : 0;
-
-       if (!o->daemon)
+       if (!o->daemon) // if we are not a daemon...
        {
                FILE * f = fopen(DAEMON_PID_FILE, "r"); 
                if (f != NULL)
                {
        {
                FILE * f = fopen(DAEMON_PID_FILE, "r"); 
                if (f != NULL)
                {
+                       //... but the DAEMON_PID_FILE exists ...
                        int daemon_pid;
                        int daemon_pid;
-                       fscanf(f, "%d", &daemon_pid);
+                       fscanf(f, "%d", &daemon_pid); // get its PID
                        fclose(f);
                        fclose(f);
-                       if (kill(daemon_pid, 0) != 0)
+                       if (kill(daemon_pid, 0) != 0) // Check it's running
                        {
                                error("Initialise", "There was a daemon [%d] running here, but it's gone for some reason.", daemon_pid);
                        }
                        {
                                error("Initialise", "There was a daemon [%d] running here, but it's gone for some reason.", daemon_pid);
                        }
+                       // We are a daemon wrapper
                        o->daemon_wrapper = true;
 
                }
        }
        else
                        o->daemon_wrapper = true;
 
                }
        }
        else
+       {
+               // We are not a daemon wrapper
                o->daemon_wrapper = false;
                o->daemon_wrapper = false;
+       }
 
        if (o->logfile != NULL)
        {
 
        if (o->logfile != NULL)
        {
-               if (o->logfile[0] == '+')
+               // A logfile was given; freopen on stderr
+               if (o->logfile[0] == '+') // option to append
                        freopen(o->logfile+1, "a", stderr);
                else
                        freopen(o->logfile, "w", stderr);
 
                setbuf(stderr, NULL);
                        freopen(o->logfile+1, "a", stderr);
                else
                        freopen(o->logfile, "w", stderr);
 
                setbuf(stderr, NULL);
-               atexit(close_err);
        }
        if (o->outfile != NULL)
        {
        }
        if (o->outfile != NULL)
        {
-               if (o->outfile[0] == '+')
+               // An outfile was given; freopen on stdout
+               if (o->outfile[0] == '+') // option to append
                        freopen(o->outfile+1, "a", stdout);
                else
                        freopen(o->outfile, "w", stdout);
                        freopen(o->outfile+1, "a", stdout);
                else
                        freopen(o->outfile, "w", stdout);
-               atexit(close_out);
        }
 
        }
 
-       if (o->verbosity >= 3)
+       // If the verbosity is high enough, display a welcome message
+       if (o->verbosity >= LOGINFO)
        {
                char buffer[BUFSIZ]; getcwd(buffer, BUFSIZ);
                char * type = (o->daemon) ? "daemon" : (o->daemon_wrapper) ? "wrapper" : (o->master_addr != NULL) ? "slave" : "interactive";
        {
                char buffer[BUFSIZ]; getcwd(buffer, BUFSIZ);
                char * type = (o->daemon) ? "daemon" : (o->daemon_wrapper) ? "wrapper" : (o->master_addr != NULL) ? "slave" : "interactive";
-               log_print(3, "Initialise", "Directory %s; type of instance: %s", buffer, type);
+               log_print(LOGINFO, "options_setup", "Directory %s; type of instance: %s", buffer, type);
        }
        }
+       
+       // If we are a daemon wrapper, we can't be interactive
+       // This is purely to avoid confusing people; it is trivial to be both a daemon wrapper and interactive
+       //      but they'll never see any outputs
        if (o->daemon_wrapper && o->interactive)
        {
        if (o->daemon_wrapper && o->interactive)
        {
-               log_print(1, "Initialise", "There is a daemonised swarm [%d] running in this directory.");
-               log_print(1, "Initialise", "You can only pass commands to the daemon by invoking %s -c [command]", options.program);
-               log_print(1, "Initialise", "Running `swarm -c \"#EXIT#\"' will quit the daemon, unless it is waiting on a BARRIER");
-               error("Initialise", "Can't run an interactive wrapper to a daemon");
+               log_print(LOGWARN, "options_setup", "There is a daemonised swarm [%d] running in this directory.");
+               log_print(LOGWARN, "options_setup", "You can only pass commands to the daemon by invoking %s -c [command]", o->program);
+               log_print(LOGWARN, "options_setup", "Running `swarm -c \"#EXIT#\"' will quit the daemon, unless it is waiting on a BARRIER");
+               error("options_setup", "Can't run an interactive wrapper to a daemon");
        }
 
 }
 
        }
 
 }
 
-void ParseArguments(int argc, char ** argv, Options * o)
+/**
+ * @funct options_parse_args
+ * @purpose Parse arguments and setup options accordingly
+ * @param argc - From main via Initialise
+ * @param argv - From main via Initialise
+ * @param o - Options struct to setup
+ */
+void options_parse_args(int argc, char ** argv, Options * o)
 {
 
 {
 
+       // Go through all arguments
        for (int i = 1; i < argc; ++i)
        {
        for (int i = 1; i < argc; ++i)
        {
+               // Most switches always start with '-' and have a single character
                if (argv[i][0] == '-' && argv[i][2] == '\0')
                {
                if (argv[i][0] == '-' && argv[i][2] == '\0')
                {
-
-
-
-                       
-
-                       if (argv[i][1] == 'p')
-                       {
-                               if (i >= argc-1)
-                                       error("ParseArguments", "No argument following %s switch", argv[i]);
-                               o->port = atoi(argv[++i]);
-                       }
-                       else if (argv[i][1] == 'n')
+                       // Set the number of local shells
+                       if (argv[i][1] == 'n')
                        {
                                if (i >= argc-1)
                                        error("ParseArguments", "No argument following %s switch", argv[i]);
                        {
                                if (i >= argc-1)
                                        error("ParseArguments", "No argument following %s switch", argv[i]);
+
                                o->nCPU = atoi(argv[++i]);
                                o->nCPU = atoi(argv[++i]);
+                               fprintf(stderr, "nCPU is %s (%d)\n", argv[i], o->nCPU);
                        }
                        }
-                       else if (argv[i][1] == 'r')
+                       else if (argv[i][1] == 'r') // specify that this instance is remote
                        {
                                if (i >= argc-1)
                                        error("ParseArguments", "No argument following %s switch", argv[i]);
                        {
                                if (i >= argc-1)
                                        error("ParseArguments", "No argument following %s switch", argv[i]);
@@ -154,7 +180,7 @@ void ParseArguments(int argc, char ** argv, Options * o)
                                        o->port = atoi(p);
                                }
                        }
                                        o->port = atoi(p);
                                }
                        }
-                       else if (argv[i][1] == 'c')
+                       else if (argv[i][1] == 'c') // Give a one off command
                        {
 
                                if (i >= argc-1)
                        {
 
                                if (i >= argc-1)
@@ -169,16 +195,16 @@ void ParseArguments(int argc, char ** argv, Options * o)
                                fprintf(f, "%s\n", argv[++i]);
                                fclose(f);
                                dup2(open(COMMAND_FILE, O_RDONLY), fileno(stdin));
                                fprintf(f, "%s\n", argv[++i]);
                                fclose(f);
                                dup2(open(COMMAND_FILE, O_RDONLY), fileno(stdin));
-                               atexit(remove_command);
+                               atexit(cleanup_command);
                        }
                        }
-                       else if (argv[i][1] == 's')
+                       else if (argv[i][1] == 's') // Specify the shell... TODO: Remove?
                        {
                                if (i >= argc-1)
                                        error("ParseArguments", "No argument following %s switch", argv[i]);
 
                                o->shell = argv[++i]; // obviously this breaks things
                        }
                        {
                                if (i >= argc-1)
                                        error("ParseArguments", "No argument following %s switch", argv[i]);
 
                                o->shell = argv[++i]; // obviously this breaks things
                        }
-                       else if (argv[i][1] == 'l')
+                       else if (argv[i][1] == 'l')  // Specify logfile and/or level
                        {
                                if (i >= argc-1)
                                        error("ParseArguments", "No argument following %s switch", argv[i]);
                        {
                                if (i >= argc-1)
                                        error("ParseArguments", "No argument following %s switch", argv[i]);
@@ -194,17 +220,13 @@ void ParseArguments(int argc, char ** argv, Options * o)
                                        o->logfile = argv[i];
        
                        }
                                        o->logfile = argv[i];
        
                        }
-                       else if (argv[i][1] == 'o')
+                       else if (argv[i][1] == 'o') // Specify output file
                        {
                                if (i >= argc-1)
                                        error("ParseArguments", "No argument following %s switch", argv[i]);
 
                                o->outfile = argv[++i];
                        }
                        {
                                if (i >= argc-1)
                                        error("ParseArguments", "No argument following %s switch", argv[i]);
 
                                o->outfile = argv[++i];
                        }
-                       else if (argv[i][1] == 'e')
-                               o->encrypt = true;
-                       else if (argv[i][1] == 'u')
-                               o->encrypt = false;
                        else
                        {
                                fprintf(stderr, "%s : Unrecognised switch \"%s\"\n", argv[0], argv[i]);
                        else
                        {
                                fprintf(stderr, "%s : Unrecognised switch \"%s\"\n", argv[0], argv[i]);
@@ -213,18 +235,22 @@ void ParseArguments(int argc, char ** argv, Options * o)
                }
                else if (strcmp(argv[i], "--daemon") == 0)
                {
                }
                else if (strcmp(argv[i], "--daemon") == 0)
                {
+                       // The --daemon switch is special because we want people to know exactly what it does
+                       // Except it isn't really a "true" daemon, but whatever
+
+                       // First check if there is already a daemon
                        FILE * f = fopen(DAEMON_PID_FILE, "r"); 
                        if (f != NULL)
                        {
                                int daemon_pid; fscanf(f, "%d\n", &daemon_pid);
                                fclose(f);
                        FILE * f = fopen(DAEMON_PID_FILE, "r"); 
                        if (f != NULL)
                        {
                                int daemon_pid; fscanf(f, "%d\n", &daemon_pid);
                                fclose(f);
-                               
-                               if (kill(daemon_pid, 0) != 0)
+                               // There is already a daemon...
+                               if (kill(daemon_pid, 0) != 0) // is it running?
                                {
                                        if (errno == ESRCH)
                                        {
                                {
                                        if (errno == ESRCH)
                                        {
-                                               log_print(0, "ParseArguments", "It looks like a daemon [%d] failed to exit cleanly. Starting a new daemon.", daemon_pid);
-                                               remove_daemon();
+                                               log_print(LOGERR, "ParseArguments", "It looks like a daemon [%d] failed to exit cleanly. Starting a new daemon.", daemon_pid);
+                                               cleanup_daemon(); //TODO: Exit and leave it up to the user to remove files instead?
                                        }
                                        else
                                        {
                                        }
                                        else
                                        {
@@ -232,41 +258,46 @@ void ParseArguments(int argc, char ** argv, Options * o)
                                        }
                                }
                                else
                                        }
                                }
                                else
+                               {
+                                       // Don't rain on the existing daemon's parade
                                        error("ParseArguments", "A daemon is already running!");
                                        error("ParseArguments", "A daemon is already running!");
+                               }
                        }
                        
                        int pid = fork();
                        if (pid != 0)
                        {
                        }
                        
                        int pid = fork();
                        if (pid != 0)
                        {
-                               //setbuf(stdout, NULL);
-                               //fprintf(stdout, "%d\n", pid);
                                exit(EXIT_SUCCESS); // fork off into daemon
                        }
                                exit(EXIT_SUCCESS); // fork off into daemon
                        }
-                       atexit(remove_daemon);
+                       atexit(cleanup_daemon);
 
                        f = fopen(DAEMON_PID_FILE, "w");
                        if (f == NULL)
                                error("ParseArguments", "Couldn't open %s : %s", DAEMON_PID_FILE, strerror(errno));
 
                        f = fopen(DAEMON_PID_FILE, "w");
                        if (f == NULL)
                                error("ParseArguments", "Couldn't open %s : %s", DAEMON_PID_FILE, strerror(errno));
-                       fprintf(f, "%d", getpid()); fclose(f);
+                       fprintf(f, "%d", getpid()); fclose(f); // print daemon's PID to file
        
        
-                       fprintf(stdout, "%d\n", getpid());
-                       freopen("/dev/null", "w", stdout);              
+                       fprintf(stdout, "%d\n", getpid()); // ... and to stdout, because this is helpful for bash scripting
+                                                          // (in case you didn't realise, this program is meant to be used in bash scripts)
+                       freopen("/dev/null", "w", stdout); // freopen to a dark void
                        freopen("/dev/null", "w", stderr);
                        freopen("/dev/null", "w", stderr);
+                       // NOTE: If the user manually specified output and log files, these streams get freopen'd again later
+                       // Slightly inefficient to do twice, but I don't care
 
 
+                       // Create a fifo to use for stdin
                        mkfifo(DAEMON_FIFO, 0600);
                        mkfifo(DAEMON_BARRIER_FIFO, 0600);
                        mkfifo(DAEMON_FIFO, 0600);
                        mkfifo(DAEMON_BARRIER_FIFO, 0600);
-                       freopen(DAEMON_FIFO, "r", stdin);
-
+                       freopen(DAEMON_FIFO, "r", stdin); // NOTE: Daemon will actually block here 
+                                                       // until a daemon wrapper is run, and opens the fifo for writing
                        o->daemon = true;
                        
                        
                }
                        o->daemon = true;
                        
                        
                }
-               else if (o->interactive)
+               else if (o->interactive) // a script was given and we can run it
                {
                        o->interactive = false;
                        dup2(open(argv[i], O_RDONLY), fileno(stdin)); // replace stdin
                }
                {
                        o->interactive = false;
                        dup2(open(argv[i], O_RDONLY), fileno(stdin)); // replace stdin
                }
-               else
+               else // Too many arguments were given
                {
                        fprintf(stderr, "%s : Usage %s [options] [script]\n", argv[0], argv[0]);
                        fprintf(stderr, "%s : (extra argv[%d] %s)\n", argv[0], i, argv[i]);
                {
                        fprintf(stderr, "%s : Usage %s [options] [script]\n", argv[0], argv[0]);
                        fprintf(stderr, "%s : (extra argv[%d] %s)\n", argv[0], i, argv[i]);
@@ -275,7 +306,15 @@ void ParseArguments(int argc, char ** argv, Options * o)
        }
 }
 
        }
 }
 
-
+/**
+ * @funct strdup
+ * @purpose Implement the stdlib function strdup
+ *     Because I couldn't get things to compile without this
+ * @param str - The string to copy
+ * @returns char* to allocated memory containing a copy of str
+ *     NOTE: The memory needs to be free(3)'d
+ */
+// TODO: Remove?
 char * strdup(const char * str)
 {
        int n = strlen(str) + 1;
 char * strdup(const char * str)
 {
        int n = strlen(str) + 1;
@@ -287,4 +326,27 @@ char * strdup(const char * str)
        return dup;
 }
 
        return dup;
 }
 
+/**
+ * @funct sigchld_respond
+ * @purpose Print messages in response to SIGCHLD... also may SIGKILL the program
+ */
+void sigchld_respond(int s, char * name, int id)
+{
+       fprintf(stderr, "Unexpected exit of slave %s:%d", name, id);
+       if (WIFSIGNALED(s))
+       {
+               int sig = WTERMSIG(s);
+               fprintf(stderr, " due to signal %s", strsignal(sig));
+               if (sig == SIGKILL)
+               {
+                       fprintf(stderr," - committing suicide\n");
+                       kill(getpid(), sig);
+               }
+       }
+       else
+       {               
+               fprintf(stderr, " return code %d.",s);
+       }
+       fprintf(stderr, " Starting replacement.\n");
+}
 
 
index 24f35eb..66fb4ef 100644 (file)
@@ -1,3 +1,11 @@
+/**
+ * @file options.h
+ * @purpose Defines struct that is basically a container for global variables
+ *     Also contains definitions for functions that initialise the struct
+ *     Contains a few other clobal definitions
+ * @author Sam Moore ([email protected])
+ */
+
 #ifndef _OPTIONS_H
 #define _OPTIONS_H
 
 #ifndef _OPTIONS_H
 #define _OPTIONS_H
 
 #include <stdbool.h>
 #include <sys/select.h>
 
 #include <stdbool.h>
 #include <sys/select.h>
 
+// One off commands are written to this file and then read back through a freopen of stdin
 #define COMMAND_FILE ".swarm.command"
 
 #define COMMAND_FILE ".swarm.command"
 
-#define SHELL_EXIT_MESSAGE "\nexit 666\n"
-#define SHELL_EXIT_CODE 666 // make sure this matches the above
+#define SHELL_EXIT_COMMAND "exit\n"
+#define SHELL_OUTPUT_FINISHED "\a\a\a" // No one ever uses bell characters... right?
+#define SHELL_OUTPUT_FINISHED_LENGTH 3 // WARNING: Make sure this is consistent with the above!
 
 
+/**
+ * @struct Options
+ * @purpose Container for "options" (ie: arguments) to the program, as well as other global variables
+ */
 typedef struct
 {
 typedef struct
 {
-       char * program;
-       char * name;
-       char * shell;
-       char * master_addr;
-       char * logfile;
-       char * outfile;
-       int verbosity;
-       int port;
-       char * prepend;
-       char * append;
-       char * end;
-       int endlen;
-       int nCPU;
-       int master_pid;
-       bool daemon;
-       bool daemon_wrapper;
-       bool encrypt;
-       bool interactive;
-       bool handle_signals;
+       char * program; // program name
+       char * name; // name of machine the program is running on
+                    // Is populated by gethostname(2) but may be changed on remote instances
+       char * shell; // The shell to start; default "bash"
+       char * master_addr; // Name of master swarm. If this swarm *is* the master, it is NULL.
+       char * logfile; // Name of file to be opened after option parsing for logging messages and errors
+       char * outfile; // Name of file to be opened after option parsing for stdout
+       int verbosity; // Level at which to print log messages (see log.h)
+       int port; // Port for remote instance to connect to master on; has no effect if ssh tunneling is used
+       char * prepend; // Command to prepend to every other command //TODO: Not fully implemented
+       char * append; // Command to append to every other command  //TODO: Not fully implemented
+       int nCPU; // Number of local shells to spawn; defaults to the number of cores/CPU on the machine
+       bool daemon; // indicates whether this instance is a daemon or not
+       bool daemon_wrapper; // indicates whether this instance is a daemon wrapper
+       bool interactive; // indicates whether this instance is interactive
+       bool encrypt; // indicates whether ssh tunnels will be used when absorbing remote instances
+                       // NOTE: This cannot be set by the user
+                       // It will automatically be set to true when #ABSORB# is used, and false when #ABSORB UNSECURE# is used.
 
 } Options;
 
 
 
 } Options;
 
 
-extern Options options;
+extern Options options; // single global variable
+
+extern void options_setup(int argc, char ** argv, Options * o); // fill options with default values, call ParseArguments
+extern void options_parse_args(int argc, char ** argv, Options * o); // parse arguments and change option values
 
 
-extern void Initialise(int argc, char ** argv, Options * o);
-extern void ParseArguments(int argc, char ** argv, Options * o);
+extern char * strdup(); //HACK: For some reason I couldn't use stdlib's strdup and wrote my own.
 
 
-extern char * strdup();
+extern void sigchld_respond(int s, char * name, int id); // I don't know why this is here, but it is
 
 
 #endif //_OPTIONS_H
 
 
 #endif //_OPTIONS_H
index 65e11c8..622bc7b 100644 (file)
@@ -35,13 +35,15 @@ void Slave_cleanup();
 
 void Slave_main(Options * o)
 {
 
 void Slave_main(Options * o)
 {
+       //fprintf(stderr, "%d\n", o->nCPU);
+
 
        
        setbuf(stdin, NULL); setbuf(stdout, NULL); setbuf(stderr, NULL);
 
        dup2(fileno(stdout), fileno(stderr)); // yes, this works, apparently
 
 
        
        setbuf(stdin, NULL); setbuf(stdout, NULL); setbuf(stderr, NULL);
 
        dup2(fileno(stdout), fileno(stderr)); // yes, this works, apparently
 
-       slave = (Slave*)(calloc(o->nCPU, sizeof(slave)));       
+       slave = (Slave*)(calloc(o->nCPU, sizeof(Slave)));       
        atexit(Slave_cleanup);
 
 
        atexit(Slave_cleanup);
 
 
@@ -68,7 +70,8 @@ void Slave_main(Options * o)
 
        fgets(name, sizeof(name), stdin);
        name[strlen(name)-1] = '\0';
 
        fgets(name, sizeof(name), stdin);
        name[strlen(name)-1] = '\0';
-       //log_print(2, "Slave_main", "Got name %s", name);
+       //log_print(LOGINFO, "Slave_main", "Started remote swarm \"%s\"", name);
+
 
        fprintf(stdout, "%d\n", o->nCPU);
        //log_print(2, "Slave_main", "Wrote nCPU %d", o->nCPU);
 
        fprintf(stdout, "%d\n", o->nCPU);
        //log_print(2, "Slave_main", "Wrote nCPU %d", o->nCPU);
@@ -160,30 +163,12 @@ void Slave_loop(Options * o)
                if (i >= o->nCPU)
                        error("Slave_loop", "No child matches pid %d", p);
 
                if (i >= o->nCPU)
                        error("Slave_loop", "No child matches pid %d", p);
 
-
-               
-               fprintf(stderr,"Unexpected exit of slave %s:%d", name, i);
-               if (WIFSIGNALED(s))
-               {
-                       int sig = WTERMSIG(s);
-                       fprintf(stderr," due to %s", strsignal(sig));
-                       if (sig == SIGKILL)
-                       {
-                               fprintf(stderr," - %s committing suicide\n", name);
-                               kill(getpid(), sig);
-                       }
-               }
-               else
-               {               
-                       fprintf(stderr," return code %d.", s);
-               }
+               sigchld_respond(s, name, i);
                
 
                // cancel any tasks at the master for this slave
                
 
                // cancel any tasks at the master for this slave
-               static int len = -1;
-               if (len < 0)
-                       len = strlen(o->end);
-               write(slave[i].out, o->end, len);
+               
+               write(slave[i].out, SHELL_OUTPUT_FINISHED, SHELL_OUTPUT_FINISHED_LENGTH);
 
                Slave_shell(i, o->shell);
 
 
                Slave_shell(i, o->shell);
 
index bf4db8f..6b66214 100644 (file)
@@ -10,6 +10,7 @@ typedef struct
 {
        int in;
        int out;
 {
        int in;
        int out;
+       int socket_child_end; // the child's end of the socket
        int pid; // pid of the process running the slave; == 0 for network slaves
        char * name;
        char * addr;
        int pid; // pid of the process running the slave; == 0 for network slaves
        char * name;
        char * addr;
index 0e1e197..4089e59 100644 (file)
--- a/src/ssh.c
+++ b/src/ssh.c
@@ -444,15 +444,17 @@ void ssh_exec_swarm(ssh * s, int * port, int * socket, int np)
        // connect secure
        if (port == NULL && socket != NULL)
        {
        // connect secure
        if (port == NULL && socket != NULL)
        {
-               sprintf(buffer, "%s -r -", options.program);
+               int len = sprintf(buffer, "%s -r - -l :%d", options.program, options.verbosity);
                if (np != 0)
                if (np != 0)
-                       sprintf(buffer, " -n %d", np);
+                       len += sprintf(buffer+len, " -n %d", np);
+               
        }
        else if (port != NULL && socket == NULL)
        {
        }
        else if (port != NULL && socket == NULL)
        {
-               sprintf(buffer, "%s -r $(echo $SSH_CONNECTION | awk \'{print $1}\'):%d", options.program, *port);
+               int len = sprintf(buffer, "%s -r $(echo $SSH_CONNECTION | awk \'{print $1}\'):%d -l :%d", options.program, *port);
                if (np != 0)
                if (np != 0)
-                       sprintf(buffer, " -n %d", np);
+                       len += sprintf(buffer+len, " -n %d", np);
+               
 
        }
        else
 
        }
        else

UCC git Repository :: git.ucc.asn.au