Initial commit (sort of)
[matches/swarm.git] / src / options.c
1 #include "options.h"
2 #include <string.h>
3 #include <stdlib.h>
4 #include <time.h>
5 #include <unistd.h>
6 #include "log.h"
7 #include <errno.h>
8 #include <sys/types.h>
9 #include <sys/stat.h>
10 #include <fcntl.h>
11 #include "daemon.h"
12 #include <signal.h>
13
14
15 void remove_command()
16 {
17         remove(COMMAND_FILE);
18
19 }
20
21 void remove_daemon()
22 {
23         remove(DAEMON_PID_FILE);
24         remove(DAEMON_FIFO);
25         remove(DAEMON_BARRIER_FIFO);
26 }
27
28 void close_err()
29 {
30         fclose(stderr);
31 }
32
33 void close_out()
34 {
35         fclose(stdout);
36 }
37
38 void Initialise(int argc, char ** argv, Options * o)
39 {
40         srand(time(NULL));
41         o->program = argv[0];
42         o->master_addr = NULL;
43         o->shell = "bash"; // choosing other shells seems to not work... for some reason
44         o->logfile = NULL;
45         o->outfile = NULL;
46         o->verbosity = 2;
47         o->port = 4000 + rand() % 1000;
48         o->slavefile = "slaves.swarm";
49         o->dummy_shell = false;
50         o->append = NULL;
51         o->prepend = NULL;
52         o->end = "\a\a\a";
53         o->nCPU = sysconf( _SC_NPROCESSORS_ONLN );
54         o->daemon = false;
55         o->encrypt = true;
56         o->interactive = true;
57         
58
59         o->master_pid = getpid();
60         
61         ParseArguments(argc, argv, o);
62
63         o->endlen = (o->end != NULL) ? strlen(o->end) : 0;
64
65         if (!o->daemon)
66         {
67                 FILE * f = fopen(DAEMON_PID_FILE, "r"); 
68                 if (f != NULL)
69                 {
70                         int daemon_pid;
71                         fscanf(f, "%d", &daemon_pid);
72                         fclose(f);
73                         if (kill(daemon_pid, 0) != 0)
74                         {
75                                 error("Initialise", "There was a daemon [%d] running here, but it's gone for some reason.", daemon_pid);
76                         }
77                         o->daemon_wrapper = true;
78
79                 }
80         }
81         else
82                 o->daemon_wrapper = false;
83
84         if (o->logfile != NULL)
85         {
86                 if (o->logfile[0] == '+')
87                         freopen(o->logfile+1, "a", stderr);
88                 else
89                         freopen(o->logfile, "w", stderr);
90
91                 setbuf(stderr, NULL);
92                 atexit(close_err);
93         }
94         if (o->outfile != NULL)
95         {
96                 if (o->outfile[0] == '+')
97                         freopen(o->outfile+1, "a", stdout);
98                 else
99                         freopen(o->outfile, "w", stdout);
100                 atexit(close_out);
101         }
102
103         if (o->verbosity >= 3)
104         {
105                 char buffer[BUFSIZ]; getcwd(buffer, BUFSIZ);
106                 char * type = (o->daemon) ? "daemon" : (o->daemon_wrapper) ? "wrapper" : (o->master_addr != NULL) ? "slave" : "interactive";
107                 log_print(3, "Initialise", "Directory %s; type of instance: %s", buffer, type);
108         }
109         if (o->daemon_wrapper && o->interactive)
110         {
111                 log_print(1, "Initialise", "There is a daemonised swarm [%d] running in this directory.");
112                 log_print(1, "Initialise", "You can only pass commands to the daemon by invoking %s -c [command]", options.program);
113                 log_print(1, "Initialise", "Running `swarm -c \"#EXIT#\"' will quit the daemon, unless it is waiting on a BARRIER");
114                 error("Initialise", "Can't run an interactive wrapper to a daemon");
115         }
116
117 }
118
119 void ParseArguments(int argc, char ** argv, Options * o)
120 {
121
122         for (int i = 1; i < argc; ++i)
123         {
124                 if (argv[i][0] == '-' && argv[i][2] == '\0')
125                 {
126
127
128
129                         
130
131                         if (argv[i][1] == 'p')
132                         {
133                                 if (i >= argc-1)
134                                         error("ParseArguments", "No argument following %s switch", argv[i]);
135                                 o->port = atoi(argv[++i]);
136                         }
137                         else if (argv[i][1] == 'n')
138                         {
139                                 if (i >= argc-1)
140                                         error("ParseArguments", "No argument following %s switch", argv[i]);
141                                 o->nCPU = atoi(argv[++i]);
142                         }
143                         else if (argv[i][1] == 'm')
144                         {
145                                 if (i >= argc-1)
146                                         error("ParseArguments", "No argument following %s switch", argv[i]);
147                                 o->master_addr = argv[++i];
148                         }
149                         else if (argv[i][1] == 'c')
150                         {
151
152                                 if (i >= argc-1)
153                                         error("ParseArguments", "No argument following %s switch", argv[i]);
154                                 
155                                 if (!o->interactive)
156                                         error("ParseArguments", "Can't use %s switch in combination with a script", argv[i]);
157
158                                 // insert terrible hack here
159                                 o->interactive = false;
160                                 FILE * f = fopen(COMMAND_FILE, "a");
161                                 fprintf(f, "%s\n", argv[++i]);
162                                 fclose(f);
163                                 dup2(open(COMMAND_FILE, O_RDONLY), fileno(stdin));
164                                 atexit(remove_command);
165                         }
166                         else if (argv[i][1] == 's')
167                         {
168                                 if (i >= argc-1)
169                                         error("ParseArguments", "No argument following %s switch", argv[i]);
170
171                                 o->shell = argv[++i]; // obviously this breaks things
172                         }
173                         else if (argv[i][1] == 'l')
174                         {
175                                 if (i >= argc-1)
176                                         error("ParseArguments", "No argument following %s switch", argv[i]);
177
178                                 char * l = argv[++i];
179                                 while (*l != '\0') if (*(l++) == ':') break;
180                                 if (*l != '\0')
181                                 {
182                                         o->verbosity = atoi(l);
183                                         *(l-1) = 0;
184                                 }
185                                 if (argv[i][0] != '\0')
186                                         o->logfile = argv[i];
187         
188                         }
189                         else if (argv[i][1] == 'o')
190                         {
191                                 if (i >= argc-1)
192                                         error("ParseArguments", "No argument following %s switch", argv[i]);
193
194                                 o->outfile = argv[++i];
195                         }
196                         else if (argv[i][1] == 'e')
197                                 o->encrypt = true;
198                         else if (argv[i][1] == 'u')
199                                 o->encrypt = false;
200                         else
201                         {
202                                 fprintf(stderr, "%s : Unrecognised switch \"%s\"\n", argv[0], argv[i]);
203                                 exit(EXIT_FAILURE);
204                         }
205                 }
206                 else if (strcmp(argv[i], "--daemon") == 0)
207                 {
208                         FILE * f = fopen(DAEMON_PID_FILE, "r"); 
209                         if (f != NULL)
210                         {
211                                 int daemon_pid; fscanf(f, "%d\n", &daemon_pid);
212                                 fclose(f);
213                                 
214                                 if (kill(daemon_pid, 0) != 0)
215                                 {
216                                         if (errno == ESRCH)
217                                         {
218                                                 log_print(0, "ParseArguments", "It looks like a daemon [%d] failed to exit cleanly. Starting a new daemon.", daemon_pid);
219                                                 remove_daemon();
220                                         }
221                                         else
222                                         {
223                                                 error("ParseArguments", "Couldn't determine whether a daemon [%d] was already running : %s", daemon_pid, strerror(errno));
224                                         }
225                                 }
226                                 else
227                                         error("ParseArguments", "A daemon is already running!");
228                         }
229                         
230                         int pid = fork();
231                         if (pid != 0)
232                         {
233                                 //setbuf(stdout, NULL);
234                                 //fprintf(stdout, "%d\n", pid);
235                                 exit(EXIT_SUCCESS); // fork off into daemon
236                         }
237                         atexit(remove_daemon);
238
239                         f = fopen(DAEMON_PID_FILE, "w");
240                         if (f == NULL)
241                                 error("ParseArguments", "Couldn't open %s : %s", DAEMON_PID_FILE, strerror(errno));
242                         fprintf(f, "%d", getpid()); fclose(f);
243         
244                         fprintf(stdout, "%d\n", getpid());
245                         freopen("/dev/null", "w", stdout);              
246                         freopen("/dev/null", "w", stderr);
247
248                         mkfifo(DAEMON_FIFO, 0600);
249                         mkfifo(DAEMON_BARRIER_FIFO, 0600);
250                         freopen(DAEMON_FIFO, "r", stdin);
251
252                         o->daemon = true;
253                         
254                         
255                 }
256                 else if (o->interactive)
257                 {
258                         o->interactive = false;
259                         dup2(open(argv[i], O_RDONLY), fileno(stdin)); // replace stdin
260                 }
261                 else
262                 {
263                         fprintf(stderr, "%s : Usage %s [options] [script]\n", argv[0], argv[0]);
264                         fprintf(stderr, "%s : (extra argv[%d] %s)\n", argv[0], i, argv[i]);
265                         exit(EXIT_FAILURE);
266                 }
267         }
268 }
269
270
271 char * strdup(const char * str)
272 {
273         int n = strlen(str) + 1;
274         char * dup = (char*)(calloc(n, sizeof(char)));
275         if (dup != NULL)
276         {
277                 strcpy(dup, str);
278         }
279         return dup;
280 }
281
282

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