Add signal handler to clean up if we are killed
[qi-bootmenu.git] / qi-bootmenu.c
blob2ea71e53fe3701b43a3cc2c33160dbb3271af2bb
1 /*
2 * qi-bootmenu - A kexec based bootloader with an elementary based GUI
4 * Copyright (c) 2009-2010 Marc Andre Tanner <mat@brain-dump.org>
6 * qi-bootmenu shares the basic idea with kexecboot which is written by:
8 * Copyright (c) 2008-2009 Yuri Bushmelev <jay4mail@gmail.com>
9 * Copyright (c) 2008 Thomas Kunze <thommycheck@gmx.de>
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2, or (at your option)
14 * any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
23 #include <stdbool.h>
24 #include <stdio.h>
25 #include <string.h>
26 #include <Eina.h>
27 #include <Evas.h>
28 #include <Ecore.h>
29 #include <Ecore_Evas.h>
31 #define countof(arr) (sizeof(arr) / sizeof((arr)[0]))
32 #define sstrlen(str) (sizeof(str) - 1)
34 static void eprint(const char *errstr, ...);
36 #ifdef NDEBUG
37 #define debug(format, args...)
38 #else
39 #define debug eprint
40 #endif
42 #define RGB(r, g, b) r,g,b
44 typedef struct {
45 const char *fs;
46 const char *dev;
47 const char *kernel;
48 const char *cmdline;
49 const char *logo;
50 } BootItem;
52 typedef struct {
53 const char *text;
54 const char *logo;
55 void(*callback)(void *data);
56 void *data;
57 } MenuItem;
59 /* menu actions */
60 static void boot_nand(void *data);
61 static void poweroff(void *data);
63 /* drawing related stuff */
64 static Ecore_Evas *ee;
65 static Evas *evas;
67 typedef struct {
68 char option;
69 void(*add)(MenuItem *item);
70 void(*select)(Evas_Object *item);
71 void(*deselect)(Evas_Object *item);
72 void(*error)(const char *errstr, va_list ap);
73 } Gui;
75 /* functions available to gui modules */
76 static void gui_item_clicked(void *data, Evas *evas, Evas_Object *item, void *event);
77 static void gui_show_error(const char *errstr, ...);
79 #include "config.h"
81 /* will be used to search the kernel as in {u,z}Image-$MACHINE.bin */
82 static const char *machine = DEFAULT_MACHINE;
84 /* if no option is passed in then use the first entry */
85 static Gui *gui = &guis[0];
87 #include "kexec.c"
88 #include "gui.c"
90 static void cleanup(int sig) {
91 umount_all();
92 ecore_main_loop_quit();
95 static void eprint(const char *errstr, ...) {
96 va_list ap;
97 va_start(ap, errstr);
98 vfprintf(stderr, errstr, ap);
99 va_end(ap);
102 static void usage() {
103 eprint("usage: qi-bootmenu [-d] [-m ...] [-i ...]\n");
104 exit(1);
107 int main(int argc, char **argv) {
109 BootItem *s;
110 Eina_List *l, *systems, *dev_ignore = NULL; /* partitions to ignore */
111 bool diag = false;
112 int arg;
113 unsigned int i;
115 if (!eina_init())
116 return 1;
118 for (arg = 1; arg < argc; arg++) {
119 if (argv[arg][0] != '-')
120 usage();
122 switch (argv[arg][1]) {
123 case 'd':
124 diag = true;
125 break;
126 case 'm':
127 if (arg + 1 >= argc)
128 usage();
129 machine = argv[++arg];
130 break;
131 case 'i':
132 if (arg + 1 >= argc)
133 usage();
134 dev_ignore = eina_list_append(dev_ignore, argv[++arg]);
135 break;
136 default:
137 for (i = 0; i < countof(guis); i++) {
138 if (argv[arg][1] == guis[i].option)
139 gui = &guis[i];
141 break;
145 if (diag) {
146 gui->error = NULL;
147 diagnostics(dev_ignore);
148 return 0;
151 if (!gui_init()) {
152 eprint("Couldn't init GUI\n");
153 return 1;
156 /* search for system images to boot and display them */
157 systems = scan_system(dev_ignore);
158 signal(SIGINT, cleanup);
159 signal(SIGTERM, cleanup);
161 EINA_LIST_FOREACH(systems, l, s) {
162 for (i = 0; i < countof(menu); i++) {
163 if (menu[i].data && !strcmp(menu[i].data, s->dev)) {
164 menu[i].text = NULL;
165 break;
168 MenuItem item = {
169 .text = s->dev,
170 .logo = s->logo,
171 .callback = gui_bootitem_clicked,
172 .data = s,
174 gui->add(&item);
177 /* add pre defined menu entries */
178 for (i = 0; i < countof(menu); i++) {
179 if (!menu[i].text)
180 continue;
181 gui->add(&menu[i]);
184 ecore_main_loop_begin();
186 return 0;