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

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