bridging using libbridge
[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 /**
297 * create an bridge
298 */
299 static void create_bridge(char *name)
300 {
301 dumm->create_bridge(dumm, name);
302
303 }
304
305 /**
306 * create an UML guest
307 */
308 static void create_guest(char *line)
309 {
310 enum {
311 NAME = 0,
312 KERNEL,
313 MASTER,
314 MEMORY,
315 };
316 char *const opts[] = {
317 [NAME] = "name",
318 [KERNEL] = "kernel",
319 [MASTER] = "master",
320 [MEMORY] = "memory",
321 NULL
322 };
323 char *value;
324 char *name = NULL;
325 char *master = NULL;
326 char *kernel = NULL;
327 int mem = 128;
328
329 while (TRUE)
330 {
331 switch (getsubopt(&line, opts, &value))
332 {
333 case NAME:
334 name = value;
335 continue;
336 case KERNEL:
337 kernel = value;
338 continue;
339 case MASTER:
340 master = value;
341 continue;
342 case MEMORY:
343 if (value)
344 {
345 mem = atoi(value);
346 }
347 continue;
348 default:
349 break;
350 }
351 break;
352 }
353 if (name == NULL || master == NULL || kernel == NULL)
354 {
355 printf("too few arguments!\n");
356 help();
357 return;
358 }
359 if (mem == 0)
360 {
361 mem = 128;
362 }
363 if (dumm->create_guest(dumm, name, kernel, master, mem))
364 {
365 printf("guest '%s' created\n", name);
366 guest(name);
367 }
368 else
369 {
370 printf("failed to create guest '%s'!\n", name);
371 }
372 }
373
374 /**
375 * list running UML guests
376 */
377 static void list()
378 {
379 iterator_t *guests, *ifaces;
380 guest_t *guest;
381 iface_t *iface;
382
383 guests = dumm->create_guest_iterator(dumm);
384 while (guests->iterate(guests, (void**)&guest))
385 {
386 printf("%s (%N)\n", guest->get_name(guest),
387 guest_state_names, guest->get_state(guest));
388 ifaces = guest->create_iface_iterator(guest);
389 while (ifaces->iterate(ifaces, (void**)&iface))
390 {
391 printf(" '%s' => '%s'\n",
392 iface->get_guestif(iface), iface->get_hostif(iface));
393 }
394 ifaces->destroy(ifaces);
395 }
396 guests->destroy(guests);
397 }
398
399 /**
400 * Signal handler
401 */
402 void signal_action(int sig, siginfo_t *info, void *ucontext)
403 {
404 if (sig == SIGCHLD)
405 {
406 dumm->sigchild_handler(dumm, info);
407 }
408 else
409 {
410 printf("\nuse 'quit'\ndumm# ");
411 }
412 }
413
414 /**
415 * main routine, parses args and reads from console
416 */
417 int main(int argc, char *argv[])
418 {
419 char *line = NULL;
420 struct sigaction action;
421 char *dir = ".";
422
423 while (TRUE)
424 {
425 struct option options[] = {
426 {"dir", 1, 0, 0},
427 {"help", 0, 0, 0},
428 {0, 0, 0, 0}
429 };
430
431 switch (getopt_long(argc, argv, "d:h", options, NULL))
432 {
433 case -1:
434 break;
435 case 'd':
436 dir = optarg;
437 continue;
438 case 'h':
439 usage();
440 return 0;
441 default:
442 usage();
443 return 1;
444 }
445 break;
446 }
447
448 dumm = dumm_create(dir);
449
450 memset(&action, 0, sizeof(action));
451 action.sa_sigaction = signal_action;
452 action.sa_flags = SA_SIGINFO;
453 if (sigaction(SIGCHLD, &action, NULL) != 0 ||
454 sigaction(SIGINT, &action, NULL) != 0 ||
455 sigaction(SIGQUIT, &action, NULL) != 0 ||
456 sigaction(SIGTERM, &action, NULL) != 0)
457 {
458 printf("signal handler setup failed: %m.\n");
459 return 1;
460 }
461
462 while (TRUE)
463 {
464 enum {
465 QUIT = 0,
466 HELP,
467 CREATE,
468 BRIDGE,
469 LIST,
470 GUEST,
471 };
472 char *const opts[] = {
473 [QUIT] = "quit",
474 [HELP] = "help",
475 [CREATE] = "create",
476 [BRIDGE] = "bridge",
477 [LIST] = "list",
478 [GUEST] = "guest",
479 NULL
480 };
481 char *pos, *value;
482
483 free(line);
484 line = readline("dumm# ");
485 if (line == NULL || *line == '\0')
486 {
487 continue;
488 }
489
490 add_history(line);
491 pos = line;
492 while (*pos != '\0')
493 {
494 if (*pos == ' ')
495 {
496 *pos = ',';
497 }
498 pos++;
499 }
500 pos = line;
501 switch (getsubopt(&pos, opts, &value))
502 {
503 case QUIT:
504 free(line);
505 break;
506 case HELP:
507 help();
508 continue;
509 case CREATE:
510 create_guest(pos);
511 continue;
512 case BRIDGE:
513 create_bridge(pos);
514 continue;
515 case LIST:
516 list();
517 continue;
518 case GUEST:
519 guest(pos);
520 continue;
521 default:
522 printf("command unknown: '%s'\n", line);
523 continue;
524 }
525 break;
526 }
527 dumm->destroy(dumm);
528 clear_history();
529 return 0;
530 }
531