ui/ncurses: Interpret left/right keys as up/down
[petitboot] / ui / ncurses / generic-main.c
1 /*
2  * Petitboot generic ncurses bootloader UI
3  *
4  *  Copyright (C) 2009 Sony Computer Entertainment Inc.
5  *  Copyright 2009 Sony Corp.
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License as published by
9  *  the Free Software Foundation; version 2 of the License.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #if defined(HAVE_CONFIG_H)
22 #include "config.h"
23 #endif
24
25 #include <assert.h>
26 #include <errno.h>
27 #include <getopt.h>
28 #include <signal.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <limits.h>
32 #include <sys/time.h>
33 #include <libintl.h>
34 #include <locale.h>
35
36 #include "log/log.h"
37 #include "talloc/talloc.h"
38 #include "waiter/waiter.h"
39 #include "i18n/i18n.h"
40 #include "ui/common/discover-client.h"
41 #include "nc-cui.h"
42
43 static void print_version(void)
44 {
45         printf("petitboot-nc (" PACKAGE_NAME ") " PACKAGE_VERSION "\n");
46 }
47
48 static void print_usage(void)
49 {
50         print_version();
51         printf(
52 "%s: petitboot-nc [-h, --help] [-l, --log log-file] [-s, --start-daemon]\n"
53 "                    [-t, --timeout] [-v, --verbose] [-V, --version]\n",
54                         _("Usage"));
55 }
56
57 /**
58  * enum opt_value - Tri-state options variables.
59  */
60
61 enum opt_value {opt_undef = 0, opt_yes, opt_no};
62
63 /**
64  * struct opts - Values from command line options.
65  */
66
67 struct opts {
68         enum opt_value show_help;
69         const char *log_file;
70         enum opt_value start_daemon;
71         enum opt_value timeout;
72         enum opt_value verbose;
73         enum opt_value show_version;
74 };
75
76 /**
77  * opts_parse - Parse the command line options.
78  */
79
80 static int opts_parse(struct opts *opts, int argc, char *argv[])
81 {
82         static const struct option long_options[] = {
83                 {"help",         no_argument,       NULL, 'h'},
84                 {"log",          required_argument, NULL, 'l'},
85                 {"start-daemon", no_argument,       NULL, 's'},
86                 {"timeout",      no_argument,       NULL, 't'},
87                 {"verbose",      no_argument,       NULL, 'v'},
88                 {"version",      no_argument,       NULL, 'V'},
89                 { NULL,          0,                 NULL, 0},
90         };
91         static const char short_options[] = "dhl:stvV";
92         static const struct opts default_values = { 0 };
93
94         *opts = default_values;
95
96         while (1) {
97                 int c = getopt_long(argc, argv, short_options, long_options,
98                         NULL);
99
100                 if (c == EOF)
101                         break;
102
103                 switch (c) {
104                 case 'h':
105                         opts->show_help = opt_yes;
106                         break;
107                 case 'l':
108                         opts->log_file = optarg;
109                         break;
110                 case 's':
111                         opts->start_daemon = opt_yes;
112                         break;
113                 case 't':
114                         opts->timeout = opt_yes;
115                         break;
116                 case 'v':
117                         opts->verbose = opt_yes;
118                         break;
119                 case 'V':
120                         opts->show_version = opt_yes;
121                         break;
122                 default:
123                         opts->show_help = opt_yes;
124                         return -1;
125                 }
126         }
127
128         return 0;
129 }
130
131 static char *default_log_filename(void)
132 {
133         const char *base = "/var/log/petitboot/petitboot-nc";
134         static char name[PATH_MAX];
135         char *tty;
136         int i;
137
138         tty = ttyname(STDIN_FILENO);
139
140         /* strip /dev/ */
141         if (tty && !strncmp(tty, "/dev/", 5))
142                 tty += 5;
143
144         /* change slashes to hyphens */
145         for (i = 0; tty && tty[i]; i++)
146                 if (tty[i] == '/')
147                         tty[i] = '-';
148
149         if (!tty || !*tty)
150                 tty = "unknown";
151
152         snprintf(name, sizeof(name), "%s.%s.log", base, tty);
153
154         return name;
155 }
156
157 static struct cui *cui;
158
159 /*
160  * struct pb_cui - Main cui program instance.
161  * @mm: Main menu.
162  * @svm: Set video mode menu.
163  */
164
165 static void sig_handler(int signum)
166 {
167         DBGS("%d\n", signum);
168
169         switch (signum) {
170         case SIGWINCH:
171                 if (cui)
172                         cui_resize(cui);
173                 break;
174         default:
175                 assert(0 && "unknown sig");
176                 /* fall through */
177         case SIGINT:
178         case SIGHUP:
179         case SIGTERM:
180                 if (cui)
181                         cui_abort(cui);
182                 break;
183         }
184 }
185
186 /**
187  * main - cui bootloader main routine.
188  */
189
190 int main(int argc, char *argv[])
191 {
192         static struct sigaction sa;
193         const char *log_filename;
194         int result;
195         int cui_result;
196         struct opts opts;
197         FILE *log;
198
199         result = opts_parse(&opts, argc, argv);
200
201         setlocale(LC_ALL, "");
202         bindtextdomain(PACKAGE, LOCALEDIR);
203         textdomain(PACKAGE);
204
205         if (result) {
206                 print_usage();
207                 return EXIT_FAILURE;
208         }
209
210         if (opts.show_help == opt_yes) {
211                 print_usage();
212                 return EXIT_SUCCESS;
213         }
214
215         if (opts.show_version == opt_yes) {
216                 print_version();
217                 return EXIT_SUCCESS;
218         }
219
220         if (opts.log_file)
221                 log_filename = opts.log_file;
222         else
223                 log_filename = default_log_filename();
224
225         log = stderr;
226         if (strcmp(log_filename, "-")) {
227                 log = fopen(log_filename, "a");
228
229                 if (!log)
230                         log = fopen("/dev/null", "a");
231         }
232
233         pb_log_init(log);
234
235         if (opts.verbose == opt_yes)
236                 pb_log_set_debug(true);
237
238         pb_log("--- petitboot-nc ---\n");
239
240         sa.sa_handler = sig_handler;
241         result = sigaction(SIGALRM, &sa, NULL);
242         result += sigaction(SIGHUP, &sa, NULL);
243         result += sigaction(SIGINT, &sa, NULL);
244         result += sigaction(SIGTERM, &sa, NULL);
245         result += sigaction(SIGWINCH, &sa, NULL);
246
247         if (result) {
248                 pb_log("%s sigaction failed.\n", __func__);
249                 return EXIT_FAILURE;
250         }
251
252         cui = cui_init(NULL, NULL, opts.start_daemon, opts.timeout);
253         if (!cui)
254                 return EXIT_FAILURE;
255
256         cui_result = cui_run(cui);
257
258         talloc_free(cui);
259
260         pb_log("--- end ---\n");
261
262         return cui_result ? EXIT_FAILURE : EXIT_SUCCESS;
263 }