set guest-specific kernel parameters
[strongswan.git] / src / dumm / main.c
1 /*
2 * Copyright (C) 2008 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 #include "dumm.h"
17
18 #include <utils/linked_list.h>
19
20 #include <sys/types.h>
21 #include <unistd.h>
22
23 #include <glib.h>
24 #include <gtk/gtk.h>
25 #include <vte/vte.h>
26 #include <vte/reaper.h>
27
28 /**
29 * notebook page with vte and guest
30 */
31 typedef struct {
32 gint num;
33 GtkWidget *vte;
34 guest_t *guest;
35 } page_t;
36
37 /**
38 * Main window
39 */
40 GtkWidget *window;
41
42 /**
43 * notebook with guests, vtes
44 */
45 GtkWidget *notebook;
46
47 /**
48 * dumm context
49 */
50 dumm_t *dumm;
51
52 /**
53 * pages in notebook, page_t
54 */
55 linked_list_t *pages;
56
57 /**
58 * handle guest termination, SIGCHILD
59 */
60 static void child_exited(VteReaper *vtereaper, gint pid, gint status)
61 {
62 enumerator_t *enumerator;
63 page_t *page;
64
65 enumerator = pages->create_enumerator(pages);
66 while (enumerator->enumerate(enumerator, (void**)&page))
67 {
68 if (page->guest->get_pid(page->guest) == pid)
69 {
70 page->guest->sigchild(page->guest);
71 vte_terminal_feed(VTE_TERMINAL(page->vte),
72 "\n\r--- guest terminated ---\n\r", -1);
73 break;
74 }
75 }
76 enumerator->destroy(enumerator);
77 }
78
79 static page_t* get_page(int num)
80 {
81 enumerator_t *enumerator;
82 page_t *page, *found = NULL;
83
84 enumerator = pages->create_enumerator(pages);
85 while (enumerator->enumerate(enumerator, (void**)&page))
86 {
87 if (page->num == num)
88 {
89 found = page;
90 break;
91 }
92 }
93 enumerator->destroy(enumerator);
94 return found;
95 }
96
97 /**
98 * Guest invocation callback
99 */
100 static pid_t invoke(void *vte, guest_t *guest,
101 char *args[], int argc)
102 {
103 return vte_terminal_fork_command(VTE_TERMINAL(vte), args[0], args, NULL,
104 NULL, FALSE, FALSE, FALSE);
105 }
106
107 void idle(void)
108 {
109 gtk_main_iteration_do(FALSE);
110 sched_yield();
111 }
112
113 static void start_guest()
114 {
115 page_t *page;
116
117 page = get_page(gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook)));
118 if (page && page->guest->get_state(page->guest) == GUEST_STOPPED)
119 {
120 vte_terminal_feed(VTE_TERMINAL(page->vte),
121 "--- starting guest ---\n\r", -1);
122 page->guest->start(page->guest, invoke, VTE_TERMINAL(page->vte), idle);
123 }
124 }
125
126 static void start_all_guests()
127 {
128 enumerator_t *enumerator;
129 page_t *page;
130
131 enumerator = pages->create_enumerator(pages);
132 while (enumerator->enumerate(enumerator, (void**)&page))
133 {
134 if (page->guest->get_state(page->guest) == GUEST_STOPPED)
135 {
136 vte_terminal_feed(VTE_TERMINAL(page->vte),
137 "--- starting all guests ---\n\r", -1);
138 page->guest->start(page->guest, invoke,
139 VTE_TERMINAL(page->vte), idle);
140 }
141 }
142 enumerator->destroy(enumerator);
143 }
144
145 static void stop_guest()
146 {
147 page_t *page;
148
149 page = get_page(gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook)));
150 if (page && page->guest->get_state(page->guest) == GUEST_RUNNING)
151 {
152 page->guest->stop(page->guest, idle);
153 }
154 }
155
156 /**
157 * quit signal handler
158 */
159 static void quit()
160 {
161 enumerator_t *enumerator;
162 page_t *page;
163
164 dumm->load_template(dumm, NULL);
165
166 enumerator = pages->create_enumerator(pages);
167 while (enumerator->enumerate(enumerator, &page))
168 {
169 if (page->guest->get_state(page->guest) != GUEST_STOPPED)
170 {
171 page->guest->stop(page->guest, idle);
172 }
173 }
174 enumerator->destroy(enumerator);
175 gtk_main_quit();
176 }
177
178 static void error_dialog(char *msg)
179 {
180 GtkWidget *error;
181
182 error = gtk_message_dialog_new(GTK_WINDOW(window),
183 GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR,
184 GTK_BUTTONS_CLOSE, msg);
185 gtk_dialog_run(GTK_DIALOG(error));
186 gtk_widget_destroy(error);
187 }
188
189 static void create_switch()
190 {
191 GtkWidget *dialog, *table, *label, *name;
192 bridge_t *bridge;
193
194 dialog = gtk_dialog_new_with_buttons("Create new switch", GTK_WINDOW(window),
195 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
196 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
197 GTK_STOCK_NEW, GTK_RESPONSE_ACCEPT, NULL);
198
199 table = gtk_table_new(1, 2, TRUE);
200 gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), table);
201
202 label = gtk_label_new("Switch name");
203 gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, 0, 0, 0, 0);
204 gtk_widget_show(label);
205
206 name = gtk_entry_new();
207 gtk_table_attach(GTK_TABLE(table), name, 1, 2, 0, 1,
208 GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 0, 0);
209 gtk_widget_show(name);
210
211 gtk_widget_show(table);
212
213 while (TRUE)
214 {
215 switch (gtk_dialog_run(GTK_DIALOG(dialog)))
216 {
217 case GTK_RESPONSE_ACCEPT:
218 {
219 if (streq(gtk_entry_get_text(GTK_ENTRY(name)), ""))
220 {
221 continue;
222 }
223 bridge = dumm->create_bridge(dumm,
224 (char*)gtk_entry_get_text(GTK_ENTRY(name)));
225 if (!bridge)
226 {
227 error_dialog("creating bridge failed!");
228 continue;
229 }
230 break;
231 }
232 default:
233 break;
234 }
235 break;
236 }
237 gtk_widget_destroy(dialog);
238 }
239
240 static void delete_switch()
241 {
242
243 }
244
245 static void connect_guest()
246 {
247 page_t *page;
248 GtkWidget *dialog, *table, *label, *name, *box;
249 bridge_t *bridge;
250 iface_t *iface;
251 enumerator_t *enumerator;
252
253 page = get_page(gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook)));
254 if (!page || page->guest->get_state(page->guest) != GUEST_RUNNING)
255 {
256 return;
257 }
258
259 dialog = gtk_dialog_new_with_buttons("Connect guest", GTK_WINDOW(window),
260 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
261 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
262 GTK_STOCK_NEW, GTK_RESPONSE_ACCEPT, NULL);
263
264 table = gtk_table_new(2, 2, TRUE);
265 gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), table);
266
267 label = gtk_label_new("Interface name");
268 gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, 0, 0, 0, 0);
269 gtk_widget_show(label);
270
271 name = gtk_entry_new();
272 gtk_table_attach(GTK_TABLE(table), name, 1, 2, 0, 1,
273 GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 0, 0);
274 gtk_widget_show(name);
275
276 label = gtk_label_new("Connected switch");
277 gtk_table_attach(GTK_TABLE(table), label, 0, 1, 1, 2, 0, 0, 0, 0);
278 gtk_widget_show(label);
279
280 box = gtk_combo_box_new_text();
281 gtk_table_attach(GTK_TABLE(table), box, 1, 2, 1, 2,
282 GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 0, 0);
283 enumerator = dumm->create_bridge_enumerator(dumm);
284 while (enumerator->enumerate(enumerator, &bridge))
285 {
286 gtk_combo_box_append_text(GTK_COMBO_BOX(box), bridge->get_name(bridge));
287 }
288 enumerator->destroy(enumerator);
289 gtk_widget_show(box);
290
291 gtk_widget_show(table);
292
293 while (TRUE)
294 {
295 switch (gtk_dialog_run(GTK_DIALOG(dialog)))
296 {
297 case GTK_RESPONSE_ACCEPT:
298 {
299 if (streq(gtk_entry_get_text(GTK_ENTRY(name)), ""))
300 {
301 continue;
302 }
303
304 iface = page->guest->create_iface(page->guest,
305 (char*)gtk_entry_get_text(GTK_ENTRY(name)));
306 if (!iface)
307 {
308 error_dialog("creating interface failed!");
309 continue;
310 }
311 enumerator = dumm->create_bridge_enumerator(dumm);
312 while (enumerator->enumerate(enumerator, &bridge))
313 {
314 if (!bridge->connect_iface(bridge, iface))
315 {
316 error_dialog("connecting interface failed!");
317 }
318 break;
319 }
320 enumerator->destroy(enumerator);
321 break;
322 }
323 default:
324 break;
325 }
326 break;
327 }
328 gtk_widget_destroy(dialog);
329 }
330
331 static void disconnect_guest()
332 {
333
334 }
335
336 static void delete_guest()
337 {
338 page_t *page;
339
340 page = get_page(gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook)));
341 if (page)
342 {
343 page->guest->stop(page->guest, idle);
344 dumm->delete_guest(dumm, page->guest);
345 gtk_notebook_remove_page(GTK_NOTEBOOK(notebook), page->num);
346 pages->remove(pages, page, NULL);
347 g_free(page);
348 }
349 }
350
351 /**
352 * create a new page for a guest
353 */
354 static page_t* create_page(guest_t *guest)
355 {
356 GtkWidget *label;
357 page_t *page;
358
359 page = g_new(page_t, 1);
360 page->guest = guest;
361 page->vte = vte_terminal_new();
362 label = gtk_label_new(guest->get_name(guest));
363 page->num = gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
364 page->vte, label);
365 gtk_widget_show(page->vte);
366 pages->insert_last(pages, page);
367 return page;
368 }
369
370 /**
371 * create a new guest
372 */
373 static void create_guest()
374 {
375 guest_t *guest;
376 GtkWidget *dialog, *table, *label, *name, *kernel, *master, *args;
377
378 dialog = gtk_dialog_new_with_buttons("Create new guest", GTK_WINDOW(window),
379 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
380 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
381 GTK_STOCK_NEW, GTK_RESPONSE_ACCEPT, NULL);
382
383 table = gtk_table_new(4, 2, TRUE);
384 gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), table);
385
386 label = gtk_label_new("Guest name");
387 gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, 0, 0, 0, 0);
388 gtk_widget_show(label);
389
390 label = gtk_label_new("UML kernel");
391 gtk_table_attach(GTK_TABLE(table), label, 0, 1, 1, 2, 0, 0, 0, 0);
392 gtk_widget_show(label);
393
394 label = gtk_label_new("Master filesystem");
395 gtk_table_attach(GTK_TABLE(table), label, 0, 1, 2, 3, 0, 0, 0, 0);
396 gtk_widget_show(label);
397
398 label = gtk_label_new("Kernel arguments");
399 gtk_table_attach(GTK_TABLE(table), label, 0, 1, 3, 4, 0, 0, 0, 0);
400 gtk_widget_show(label);
401
402 name = gtk_entry_new();
403 gtk_table_attach(GTK_TABLE(table), name, 1, 2, 0, 1,
404 GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 0, 0);
405 gtk_widget_show(name);
406
407 kernel = gtk_file_chooser_button_new("Select UML kernel image",
408 GTK_FILE_CHOOSER_ACTION_OPEN);
409 gtk_table_attach(GTK_TABLE(table), kernel, 1, 2, 1, 2,
410 GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 0, 0);
411 gtk_widget_show(kernel);
412
413 master = gtk_file_chooser_button_new("Select master filesystem",
414 GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER);
415 gtk_table_attach(GTK_TABLE(table), master, 1, 2, 2, 3,
416 GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 0, 0);
417 gtk_widget_show(master);
418
419 args = gtk_entry_new();
420 gtk_table_attach(GTK_TABLE(table), args, 1, 2, 3, 4,
421 GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 0, 0);
422 gtk_widget_show(args);
423
424 gtk_widget_show(table);
425
426 while (TRUE)
427 {
428 switch (gtk_dialog_run(GTK_DIALOG(dialog)))
429 {
430 case GTK_RESPONSE_ACCEPT:
431 {
432 char *sname, *skernel, *smaster, *sargs;
433 page_t *page;
434
435 sname = (char*)gtk_entry_get_text(GTK_ENTRY(name));
436 skernel = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(kernel));
437 smaster = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(master));
438 sargs = (char*)gtk_entry_get_text(GTK_ENTRY(args));
439
440 if (!sname[0] || !skernel || !smaster)
441 {
442 continue;
443 }
444 guest = dumm->create_guest(dumm, sname, skernel, smaster, sargs);
445 if (!guest)
446 {
447 error_dialog("creating guest failed!");
448 continue;
449 }
450 page = create_page(guest);
451 gtk_notebook_set_current_page(GTK_NOTEBOOK(notebook), page->num);
452 break;
453 }
454 default:
455 break;
456 }
457 break;
458 }
459 gtk_widget_destroy(dialog);
460 }
461
462 /**
463 * main routine, parses args and reads from console
464 */
465 int main(int argc, char *argv[])
466 {
467 GtkWidget *menubar, *menu, *menuitem, *vbox;
468 GtkWidget *dummMenu, *guestMenu, *switchMenu;
469 enumerator_t *enumerator;
470 guest_t *guest;
471
472 library_init(NULL);
473 gtk_init(&argc, &argv);
474
475 pages = linked_list_create();
476 dumm = dumm_create(NULL);
477
478 /* setup window */
479 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
480 g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(quit), NULL);
481 gtk_window_set_title(GTK_WINDOW (window), "Dumm");
482 gtk_window_set_default_size(GTK_WINDOW (window), 1000, 500);
483 g_signal_connect(G_OBJECT(vte_reaper_get()), "child-exited",
484 G_CALLBACK(child_exited), NULL);
485
486 /* add vbox with menubar, notebook */
487 vbox = gtk_vbox_new(FALSE, 0);
488 gtk_container_add(GTK_CONTAINER(window), vbox);
489 menubar = gtk_menu_bar_new();
490 gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, TRUE, 0);
491 notebook = gtk_notebook_new();
492 g_object_set(G_OBJECT(notebook), "homogeneous", TRUE, NULL);
493 gtk_notebook_set_tab_pos(GTK_NOTEBOOK(notebook), GTK_POS_BOTTOM);
494 gtk_container_add(GTK_CONTAINER(vbox), notebook);
495
496 /* Dumm menu */
497 menu = gtk_menu_new();
498 dummMenu = gtk_menu_item_new_with_mnemonic("_Dumm");
499 gtk_menu_bar_append(GTK_MENU_BAR(menubar), dummMenu);
500 gtk_widget_show(dummMenu);
501 gtk_menu_item_set_submenu(GTK_MENU_ITEM(dummMenu), menu);
502
503 /* Dumm -> exit */
504 menuitem = gtk_image_menu_item_new_from_stock(GTK_STOCK_QUIT, NULL);
505 g_signal_connect(G_OBJECT(menuitem), "activate",
506 G_CALLBACK(quit), NULL);
507 gtk_menu_append(GTK_MENU(menu), menuitem);
508 gtk_widget_show(menuitem);
509
510 /* Guest menu */
511 menu = gtk_menu_new();
512 guestMenu = gtk_menu_item_new_with_mnemonic("_Guest");
513 gtk_menu_bar_append(GTK_MENU_BAR(menubar), guestMenu);
514 gtk_widget_show(guestMenu);
515 gtk_menu_item_set_submenu(GTK_MENU_ITEM(guestMenu), menu);
516
517 /* Guest -> new */
518 menuitem = gtk_image_menu_item_new_from_stock(GTK_STOCK_NEW, NULL);
519 g_signal_connect(G_OBJECT(menuitem), "activate",
520 G_CALLBACK(create_guest), NULL);
521 gtk_menu_append(GTK_MENU(menu), menuitem);
522 gtk_widget_show(menuitem);
523
524 /* Guest -> delete */
525 menuitem = gtk_image_menu_item_new_from_stock(GTK_STOCK_DELETE, NULL);
526 g_signal_connect(G_OBJECT(menuitem), "activate",
527 G_CALLBACK(delete_guest), NULL);
528 gtk_menu_append(GTK_MENU(menu), menuitem);
529 gtk_widget_show(menuitem);
530
531 menuitem = gtk_separator_menu_item_new();
532 gtk_menu_append(GTK_MENU(menu), menuitem);
533 gtk_widget_show(menuitem);
534
535 /* Guest -> start */
536 menuitem = gtk_menu_item_new_with_mnemonic("_Start");
537 g_signal_connect(G_OBJECT(menuitem), "activate",
538 G_CALLBACK(start_guest), NULL);
539 gtk_menu_append(GTK_MENU(menu), menuitem);
540 gtk_widget_show(menuitem);
541
542 /* Guest -> startall */
543 menuitem = gtk_menu_item_new_with_mnemonic("Start _all");
544 g_signal_connect(G_OBJECT(menuitem), "activate",
545 G_CALLBACK(start_all_guests), NULL);
546 gtk_menu_append(GTK_MENU(menu), menuitem);
547 gtk_widget_show(menuitem);
548
549 /* Guest -> stop */
550 menuitem = gtk_image_menu_item_new_from_stock(GTK_STOCK_STOP, NULL);
551 g_signal_connect(G_OBJECT(menuitem), "activate",
552 G_CALLBACK(stop_guest), NULL);
553 gtk_menu_append(GTK_MENU(menu), menuitem);
554 gtk_widget_show(menuitem);
555
556 menuitem = gtk_separator_menu_item_new();
557 gtk_menu_append(GTK_MENU(menu), menuitem);
558 gtk_widget_show(menuitem);
559
560 /* Guest -> connect */
561 menuitem = gtk_image_menu_item_new_from_stock(GTK_STOCK_CONNECT, NULL);
562 g_signal_connect(G_OBJECT(menuitem), "activate",
563 G_CALLBACK(connect_guest), NULL);
564 gtk_menu_append(GTK_MENU(menu), menuitem);
565 gtk_widget_show(menuitem);
566
567 /* Guest -> disconnect */
568 menuitem = gtk_image_menu_item_new_from_stock(GTK_STOCK_DISCONNECT, NULL);
569 g_signal_connect(G_OBJECT(menuitem), "activate",
570 G_CALLBACK(disconnect_guest), NULL);
571 gtk_menu_append(GTK_MENU(menu), menuitem);
572 gtk_widget_set_sensitive(menuitem, FALSE);
573 gtk_widget_show(menuitem);
574
575 /* Switch menu */
576 menu = gtk_menu_new();
577 switchMenu = gtk_menu_item_new_with_mnemonic("_Switch");
578 gtk_menu_bar_append(GTK_MENU_BAR(menubar), switchMenu);
579 gtk_widget_show(switchMenu);
580 gtk_menu_item_set_submenu(GTK_MENU_ITEM(switchMenu), menu);
581
582 /* Switch -> new */
583 menuitem = gtk_image_menu_item_new_from_stock(GTK_STOCK_NEW, NULL);
584 g_signal_connect(G_OBJECT(menuitem), "activate",
585 G_CALLBACK(create_switch), NULL);
586 gtk_menu_append(GTK_MENU(menu), menuitem);
587 gtk_widget_show(menuitem);
588
589 /* Switch -> delete */
590 menuitem = gtk_image_menu_item_new_from_stock(GTK_STOCK_DELETE, NULL);
591 g_signal_connect(G_OBJECT(menuitem), "activate",
592 G_CALLBACK(delete_switch), NULL);
593 gtk_menu_append(GTK_MENU(menu), menuitem);
594 gtk_widget_set_sensitive(menuitem, FALSE);
595 gtk_widget_show(menuitem);
596
597 /* show widgets */
598 gtk_widget_show(menubar);
599 gtk_widget_show(notebook);
600 gtk_widget_show(vbox);
601 gtk_widget_show(window);
602
603 /* fill notebook with guests */
604 enumerator = dumm->create_guest_enumerator(dumm);
605 while (enumerator->enumerate(enumerator, (void**)&guest))
606 {
607 create_page(guest);
608 }
609 enumerator->destroy(enumerator);
610
611 gtk_main();
612
613 dumm->destroy(dumm);
614 pages->destroy_function(pages, g_free);
615
616 library_deinit();
617 return 0;
618 }
619