support for killing guests properly
[strongswan.git] / src / dumm / main.c
1 /*
2 * Copyright (C) 2007 Martin Willi
3 * Hochschule fuer Technik Rapperswil
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 */
15
16 #define _GNU_SOURCE
17
18 #include <stdio.h>
19 #include <unistd.h>
20 #include <getopt.h>
21 #include <library.h>
22 #include <readline/readline.h>
23 #include <readline/history.h>
24
25 #include "dumm.h"
26
27 /**
28 * global set of UMLs guests
29 */
30 dumm_t *dumm;
31
32 /**
33 * show usage information (program arguments)
34 */
35 static void usage()
36 {
37 printf("Usage:\n");
38 printf(" --dir|-d <path> set working dir to <path>\n");
39 printf(" --help|-h show this help\n");
40 }
41
42 /**
43 * help for dumm root shell
44 */
45 static void help()
46 {
47 printf("create name=<name> start a guest named <name>\n");
48 printf(" [master=<dir>] read only master root filesystem\n");
49 printf(" [memory=<MB>] guest main memory in megabyte\n");
50 printf("list list running guests\n");
51 printf("guest <name> open guest menu for <name>\n");
52 printf("help show this help\n");
53 printf("quit kill quests and exit\n");
54 }
55
56 /**
57 * help for guest shell
58 */
59 static void help_guest()
60 {
61 printf("start [kernel=<uml-kernel>] start a stopped guest\n");
62 printf("stop stop a started guest\n");
63 printf("addif <name> add an interface to the guest\n");
64 printf("delif <name> remove the interface\n");
65 printf("listif list guests interfaces\n");
66 printf("help show this help\n");
67 printf("quit quit the guest menu\n");
68 }
69
70 /**
71 * add an iface to a guest
72 */
73 static void add_if(guest_t *guest, char *name)
74 {
75 iface_t *iface;
76
77 iface = guest->create_iface(guest, name);
78 if (iface)
79 {
80 printf("created guest interface '%s' connected to '%s'\n",
81 iface->get_guestif(iface), iface->get_hostif(iface));
82 }
83 else
84 {
85 printf("failed to create guest interface\n");
86 }
87 }
88
89 /**
90 * delete an iface from a guest
91 */
92 static void del_if(guest_t *guest, char *name)
93 {
94 iface_t *iface;
95 iterator_t *iterator;
96 bool found = FALSE;
97
98 iterator = guest->create_iface_iterator(guest);
99 while (iterator->iterate(iterator, (void**)&iface))
100 {
101 if (streq(name, iface->get_guestif(iface)))
102 {
103 iterator->remove(iterator);
104 printf("removing interface '%s' ('%s') from %s\n",
105 iface->get_guestif(iface), iface->get_hostif(iface),
106 guest->get_name(guest));
107 iface->destroy(iface);
108 found = TRUE;
109 break;
110 }
111 }
112 iterator->destroy(iterator);
113 if (!found)
114 {
115 printf("guest '%s' has no interface named '%s'\n",
116 guest->get_name(guest), name);
117 }
118 }
119
120 /**
121 * list interfaces on a guest
122 */
123 static void list_if(guest_t *guest)
124 {
125 iface_t *iface;
126 iterator_t *iterator;
127
128 iterator = guest->create_iface_iterator(guest);
129 while (iterator->iterate(iterator, (void**)&iface))
130 {
131 printf("'%s' => '%s'\n", iface->get_guestif(iface), iface->get_hostif(iface));
132
133 }
134 iterator->destroy(iterator);
135 }
136
137 /**
138 * start an UML guest
139 */
140 static void start_guest(guest_t *guest, char *line)
141 {
142 enum {
143 KERNEL = 0,
144 };
145 char *const opts[] = {
146 [KERNEL] = "kernel",
147 NULL
148 };
149 char *value;
150 char *kernel = NULL;
151
152 while (TRUE)
153 {
154 switch (getsubopt(&line, opts, &value))
155 {
156 case KERNEL:
157 kernel = value;
158 continue;
159 default:
160 break;
161 }
162 break;
163 }
164 if (kernel == NULL)
165 {
166 kernel = "./linux";
167 }
168
169 printf("starting guest '%s'... \n", guest->get_name(guest));
170 if (guest->start(guest, kernel))
171 {
172 printf("guest '%s' is up\n", guest->get_name(guest));
173 }
174 else
175 {
176 printf("failed to start guest '%s'!\n", guest->get_name(guest));
177 }
178 }
179
180 /**
181 * stop (kill) an UML guest
182 */
183 static void stop_guest(guest_t *guest, char *line)
184 {
185 printf("stopping guest '%s'...\n", guest->get_name(guest));
186 guest->stop(guest);
187 printf("guest '%s' is down\n", guest->get_name(guest));
188 }
189
190 /**
191 * subshell for guests
192 */
193 static void guest(char *name)
194 {
195 char *line = NULL;
196 char prompt[32];
197 int len;
198 iterator_t *iterator;
199 guest_t *guest;
200 bool found = FALSE;
201
202 iterator = dumm->create_guest_iterator(dumm);
203 while (iterator->iterate(iterator, (void**)&guest))
204 {
205 if (streq(name, guest->get_name(guest)))
206 {
207 found = TRUE;
208 break;
209 }
210 }
211 iterator->destroy(iterator);
212 if (!found)
213 {
214 printf("guest '%s' not found\n", name);
215 return;
216 }
217
218 len = snprintf(prompt, sizeof(prompt), "dumm@%s# ", name);
219 if (len < 0 || len >= sizeof(prompt))
220 {
221 return;
222 }
223
224 while (TRUE)
225 {
226 enum {
227 QUIT = 0,
228 HELP,
229 START,
230 STOP,
231 ADDIF,
232 DELIF,
233 LISTIF,
234 };
235 char *const opts[] = {
236 [QUIT] = "quit",
237 [HELP] = "help",
238 [START] = "start",
239 [STOP] = "stop",
240 [ADDIF] = "addif",
241 [DELIF] = "delif",
242 [LISTIF] = "listif",
243 NULL
244 };
245 char *pos, *value;
246
247 free(line);
248 line = readline(prompt);
249 if (line == NULL || *line == '\0')
250 {
251 continue;
252 }
253 add_history(line);
254 pos = line;
255 while (*pos != '\0')
256 {
257 if (*pos == ' ')
258 {
259 *pos = ',';
260 }
261 pos++;
262 }
263 pos = line;
264 switch (getsubopt(&pos, opts, &value))
265 {
266 case QUIT:
267 free(line);
268 break;
269 case HELP:
270 help_guest();
271 continue;
272 case START:
273 start_guest(guest, pos);
274 continue;
275 case STOP:
276 stop_guest(guest, pos);
277 continue;
278 case ADDIF:
279 add_if(guest, pos);
280 continue;
281 case DELIF:
282 del_if(guest, pos);
283 continue;
284 case LISTIF:
285 list_if(guest);
286 continue;
287 default:
288 printf("command unknown: '%s'\n", line);
289 continue;
290 }
291 break;
292 }
293 }
294
295 /**
296 * create an UML guest
297 */
298 static void create_guest(char *line)
299 {
300 enum {
301 NAME = 0,
302 MASTER,
303 MEMORY,
304 };
305 char *const opts[] = {
306 [NAME] = "name",
307 [MASTER] = "master",
308 [MEMORY] = "memory",
309 NULL
310 };
311 char *value;
312 char *name = NULL;
313 char *master = NULL;
314 int mem = 0;
315
316 while (TRUE)
317 {
318 switch (getsubopt(&line, opts, &value))
319 {
320 case NAME:
321 name = value;
322 continue;
323 case MASTER:
324 master = value;
325 continue;
326 case MEMORY:
327 if (value)
328 {
329 mem = atoi(value);
330 }
331 continue;
332 default:
333 break;
334 }
335 break;
336 }
337 if (name == NULL)
338 {
339 printf("option 'name' is required.\n");
340 help();
341 return;
342 }
343 if (master == NULL)
344 {
345 master = "master";
346 }
347 if (mem == 0)
348 {
349 mem = 128;
350 }
351 if (dumm->create_guest(dumm, name, master, mem))
352 {
353 printf("guest '%s' created\n", name);
354 guest(name);
355 }
356 else
357 {
358 printf("failed to create guest '%s'!\n", name);
359 }
360 }
361
362 /**
363 * list running UML guests
364 */
365 static void list()
366 {
367 iterator_t *guests, *ifaces;
368 guest_t *guest;
369 iface_t *iface;
370
371 guests = dumm->create_guest_iterator(dumm);
372 while (guests->iterate(guests, (void**)&guest))
373 {
374 printf("%s (%N)\n", guest->get_name(guest),
375 guest_state_names, guest->get_state(guest));
376 ifaces = guest->create_iface_iterator(guest);
377 while (ifaces->iterate(ifaces, (void**)&iface))
378 {
379 printf(" '%s' => '%s'\n",
380 iface->get_guestif(iface), iface->get_hostif(iface));
381 }
382 ifaces->destroy(ifaces);
383 }
384 guests->destroy(guests);
385 }
386
387 /**
388 * Signal handler
389 */
390 void signal_action(int sig, siginfo_t *info, void *ucontext)
391 {
392 if (sig == SIGCHLD)
393 {
394 dumm->sigchild_handler(dumm, info);
395 }
396 else
397 {
398 dumm->destroy(dumm);
399 clear_history();
400 printf("\n");
401 exit(0);
402 }
403 }
404
405 /**
406 * main routine, parses args and reads from console
407 */
408 int main(int argc, char *argv[])
409 {
410 char *line = NULL;
411 struct sigaction action;
412
413 while (TRUE)
414 {
415 struct option options[] = {
416 {"dir", 1, 0, 0},
417 {"help", 0, 0, 0},
418 {0, 0, 0, 0}
419 };
420
421 switch (getopt_long(argc, argv, "d:h", options, NULL))
422 {
423 case -1:
424 break;
425 case 'd':
426 if (chdir(optarg))
427 {
428 printf("changing to directory '%s' failed.\n", optarg);
429 return 1;
430 }
431 continue;
432 case 'h':
433 usage();
434 return 0;
435 default:
436 usage();
437 return 1;
438 }
439 break;
440 }
441
442 dumm = dumm_create();
443
444 memset(&action, 0, sizeof(action));
445 action.sa_sigaction = signal_action;
446 action.sa_flags = SA_SIGINFO;
447 if (sigaction(SIGCHLD, &action, NULL) != 0 ||
448 sigaction(SIGINT, &action, NULL) != 0 ||
449 sigaction(SIGQUIT, &action, NULL) != 0 ||
450 sigaction(SIGTERM, &action, NULL) != 0)
451 {
452 printf("signal handler setup failed: %m.\n");
453 return 1;
454 }
455
456 while (TRUE)
457 {
458 enum {
459 QUIT = 0,
460 HELP,
461 CREATE,
462 LIST,
463 GUEST,
464 };
465 char *const opts[] = {
466 [QUIT] = "quit",
467 [HELP] = "help",
468 [CREATE] = "create",
469 [LIST] = "list",
470 [GUEST] = "guest",
471 NULL
472 };
473 char *pos, *value;
474
475 free(line);
476 line = readline("dumm# ");
477 if (line == NULL || *line == '\0')
478 {
479 continue;
480 }
481
482 add_history(line);
483 pos = line;
484 while (*pos != '\0')
485 {
486 if (*pos == ' ')
487 {
488 *pos = ',';
489 }
490 pos++;
491 }
492 pos = line;
493 switch (getsubopt(&pos, opts, &value))
494 {
495 case QUIT:
496 free(line);
497 break;
498 case HELP:
499 help();
500 continue;
501 case CREATE:
502 create_guest(pos);
503 continue;
504 case LIST:
505 list();
506 continue;
507 case GUEST:
508 guest(pos);
509 continue;
510 default:
511 printf("command unknown: '%s'\n", line);
512 continue;
513 }
514 break;
515 }
516 dumm->destroy(dumm);
517 clear_history();
518 return 0;
519 }
520