[package] update aoetools to 30 (#5523)
[openwrt/svn-archive/archive.git] / utils / petitboot / patches / 010-petitboot-fixups.diff
1 34 files changed, 1687 insertions(+), 235 deletions(-)
2
3 diff --git a/Makefile.in b/Makefile.in
4 index 01771db..23135aa 100644
5 --- a/Makefile.in
6 +++ b/Makefile.in
7 @@ -21,7 +21,12 @@ ENABLE_PS3 = @ENABLE_PS3@
8
9 # other programs
10 INSTALL = @INSTALL@
11 +INSTALL_DATA = @INSTALL_DATA@
12 +INSTALL_PROGRAM = @INSTALL_PROGRAM@
13 +INSTALL_SCRIPT = @INSTALL_SCRIPT@
14 +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
15 SHELL = @SHELL@
16 +STRIP = @STRIP@
17
18 # paths
19 prefix = @prefix@
20 @@ -34,5 +39,6 @@ localstatedir = @localstatedir@
21 builddir = @builddir@
22 srcdir = @srcdir@
23 top_srcdir = @top_srcdir@
24 +mandir = @mandir@
25
26 include $(top_srcdir)/rules.mk
27 diff --git a/configure.ac b/configure.ac
28 index cb43f8c..fa40f34 100644
29 --- a/configure.ac
30 +++ b/configure.ac
31 @@ -35,9 +35,7 @@ AC_ARG_ENABLE([ps3],
32 [],
33 [enable_ps3=check])
34
35 -AS_IF([test "x$enable_ps3" != xno],
36 - [AC_SUBST([ENABLE_PS3], ["y"])],
37 - [AC_SUBST([ENABLE_PS3], ["n"])])
38 +AS_IF([test "x$enable_ps3" != xno], [AC_SUBST([ENABLE_PS3], ["y"])], [])
39
40 AC_ARG_WITH([twin],
41 [AS_HELP_STRING([--with-twin],
42 diff --git a/discover/kboot-parser.c b/discover/kboot-parser.c
43 index e688c22..7c7cb5d 100644
44 --- a/discover/kboot-parser.c
45 +++ b/discover/kboot-parser.c
46 @@ -133,10 +133,11 @@ static int kboot_parse(struct discover_context *dc)
47 conf = talloc_zero(dc, struct conf_context);
48
49 if (!conf)
50 - return -1;
51 + return 0;
52
53 conf->dc = dc;
54 conf->global_options = kboot_global_options,
55 + conf_init_global_options(conf);
56 conf->conf_files = kboot_conf_files,
57 conf->process_pair = kboot_process_pair;
58 conf->parser_info = (void *)kboot_ignored_names,
59 diff --git a/discover/parser-conf.c b/discover/parser-conf.c
60 index 14f847d..88e96b7 100644
61 --- a/discover/parser-conf.c
62 +++ b/discover/parser-conf.c
63 @@ -121,6 +121,18 @@ int conf_param_in_list(const char *const *list, const char *param)
64 }
65
66 /**
67 + * conf_init_global_options - Zero the global option table.
68 + */
69 +
70 +void conf_init_global_options(struct conf_context *conf)
71 +{
72 + int i;
73 +
74 + for (i = 0; conf->global_options[i].name; i++)
75 + conf->global_options[i].value = NULL;
76 +}
77 +
78 +/**
79 * conf_set_global_option - Set a value in the global option table.
80 *
81 * Check if an option (name=value) is a global option. If so, store it in
82 @@ -136,7 +148,7 @@ int conf_set_global_option(struct conf_context *conf, const char *name,
83 if (streq(name, conf->global_options[i].name)) {
84 conf->global_options[i].value
85 = talloc_strdup(conf, value);
86 - pb_log("%s: %s:%s\n", __func__, name, value);
87 + pb_log("%s: @%s@%s@\n", __func__, name, value);
88 return 1;
89 }
90 }
91 @@ -158,8 +170,11 @@ const char *conf_get_global_option(struct conf_context *conf,
92 int i;
93
94 for (i = 0; conf->global_options[i].name ;i++)
95 - if (streq(name, conf->global_options[i].name))
96 + if (streq(name, conf->global_options[i].name)) {
97 + pb_log("%s: @%s@%s@\n", __func__, name,
98 + conf->global_options[i].value);
99 return conf->global_options[i].value;
100 + }
101
102 assert(0 && "unknown global name");
103 return NULL;
104 diff --git a/discover/parser-conf.h b/discover/parser-conf.h
105 index 09015d1..3325faf 100644
106 --- a/discover/parser-conf.h
107 +++ b/discover/parser-conf.h
108 @@ -41,6 +41,7 @@ struct conf_context {
109 int conf_parse(struct conf_context *conf);
110 char *conf_get_param_pair(char *str, char **name_out, char **value_out,
111 char terminator);
112 +void conf_init_global_options(struct conf_context *conf);
113 const char *conf_get_global_option(struct conf_context *conf,
114 const char *name);
115 int conf_set_global_option(struct conf_context *conf, const char *name,
116 diff --git a/discover/parser.c b/discover/parser.c
117 index 2b4ddd2..8f2735c 100644
118 --- a/discover/parser.c
119 +++ b/discover/parser.c
120 @@ -13,16 +13,16 @@ extern struct parser __start_parsers[], __stop_parsers[];
121 void iterate_parsers(struct discover_context *ctx)
122 {
123 struct parser *parser;
124 + unsigned int count = 0;
125
126 pb_log("trying parsers for %s\n", ctx->device_path);
127
128 for (parser = __start_parsers; parser < __stop_parsers; parser++) {
129 pb_log("\ttrying parser '%s'\n", parser->name);
130 - /* just use a dummy device path for now */
131 - if (parser->parse(ctx))
132 - return;
133 + count += parser->parse(ctx);
134 }
135 - pb_log("\tno boot_options found\n");
136 + if (!count)
137 + pb_log("\tno boot_options found\n");
138 }
139
140 static int compare_parsers(const void *a, const void *b)
141 diff --git a/discover/paths.c b/discover/paths.c
142 index 8e2a361..fe7a876 100644
143 --- a/discover/paths.c
144 +++ b/discover/paths.c
145 @@ -81,14 +81,6 @@ char *parse_device_path(void *alloc_ctx,
146 if (is_prefix(dev_str, "/dev/"))
147 dev_str += strlen("/dev/");
148
149 - /* PS3 hack: if we're reading from a ps3dx device, and we refer to
150 - * a sdx device, remap to ps3dx */
151 - if (cur_dev && is_prefix(cur_dev, "/dev/ps3d")
152 - && is_prefix(dev_str, "sd")) {
153 - snprintf(tmp, 255, "ps3d%s", dev_str + 2);
154 - dev_str = tmp;
155 - }
156 -
157 return join_paths(alloc_ctx, "/dev", dev_str);
158 }
159
160 diff --git a/discover/pb-discover.c b/discover/pb-discover.c
161 index d7ea0ca..bd515e3 100644
162 --- a/discover/pb-discover.c
163 +++ b/discover/pb-discover.c
164 @@ -1,5 +1,10 @@
165
166 +#if defined(HAVE_CONFIG_H)
167 +#include "config.h"
168 +#endif
169 +
170 #include <assert.h>
171 +#include <getopt.h>
172 #include <stdlib.h>
173 #include <signal.h>
174
175 @@ -11,6 +16,79 @@
176 #include "discover-server.h"
177 #include "device-handler.h"
178
179 +static void print_version(void)
180 +{
181 + printf("pb-discover (" PACKAGE_NAME ") " PACKAGE_VERSION "\n");
182 +}
183 +
184 +static void print_usage(void)
185 +{
186 + print_version();
187 + printf(
188 +"Usage: pb-discover [-h, --help] [-l, --log log-file] [-V, --version]\n");
189 +}
190 +
191 +/**
192 + * enum opt_value - Tri-state options variables.
193 + */
194 +
195 +enum opt_value {opt_undef = 0, opt_yes, opt_no};
196 +
197 +/**
198 + * struct opts - Values from command line options.
199 + */
200 +
201 +struct opts {
202 + enum opt_value show_help;
203 + const char *log_file;
204 + enum opt_value show_version;
205 +};
206 +
207 +/**
208 + * opts_parse - Parse the command line options.
209 + */
210 +
211 +static int opts_parse(struct opts *opts, int argc, char *argv[])
212 +{
213 + static const struct option long_options[] = {
214 + {"help", no_argument, NULL, 'h'},
215 + {"log", required_argument, NULL, 'l'},
216 + {"version", no_argument, NULL, 'V'},
217 + { NULL, 0, NULL, 0},
218 + };
219 + static const char short_options[] = "hl:V";
220 + static const struct opts default_values = {
221 + .log_file = "pb-discover.log",
222 + };
223 +
224 + *opts = default_values;
225 +
226 + while (1) {
227 + int c = getopt_long(argc, argv, short_options, long_options,
228 + NULL);
229 +
230 + if (c == EOF)
231 + break;
232 +
233 + switch (c) {
234 + case 'h':
235 + opts->show_help = opt_yes;
236 + break;
237 + case 'l':
238 + opts->log_file = optarg;
239 + break;
240 + case 'V':
241 + opts->show_version = opt_yes;
242 + break;
243 + default:
244 + opts->show_help = opt_yes;
245 + return -1;
246 + }
247 + }
248 +
249 + return optind != argc;
250 +}
251 +
252 static int running;
253
254 static void sigint_handler(int __attribute__((unused)) signum)
255 @@ -18,15 +96,31 @@ static void sigint_handler(int __attribute__((unused)) signum)
256 running = 0;
257 }
258
259 -int main(void)
260 +int main(int argc, char *argv[])
261 {
262 struct device_handler *handler;
263 struct discover_server *server;
264 + struct opts opts;
265 struct udev *udev;
266 struct user_event *uev;
267 FILE *log;
268
269 - log = fopen("pb-discover.log", "a");
270 + if (opts_parse(&opts, argc, argv)) {
271 + print_usage();
272 + return EXIT_FAILURE;
273 + }
274 +
275 + if (opts.show_help == opt_yes) {
276 + print_usage();
277 + return EXIT_SUCCESS;
278 + }
279 +
280 + if (opts.show_version == opt_yes) {
281 + print_version();
282 + return EXIT_SUCCESS;
283 + }
284 +
285 + log = fopen(opts.log_file, "a");
286 assert(log);
287 pb_log_set_stream(log);
288
289 diff --git a/discover/yaboot-parser.c b/discover/yaboot-parser.c
290 index d9f2aff..6101cd8 100644
291 --- a/discover/yaboot-parser.c
292 +++ b/discover/yaboot-parser.c
293 @@ -15,7 +15,6 @@ struct yaboot_state {
294 struct boot_option *opt;
295 const char *desc_image;
296 char *desc_initrd;
297 - int found_suse;
298 int globals_done;
299 const char *const *known_names;
300 };
301 @@ -56,6 +55,19 @@ static void yaboot_process_pair(struct conf_context *conf, const char *name,
302 char *value)
303 {
304 struct yaboot_state *state = conf->parser_info;
305 + struct fixed_pair {
306 + const char *image;
307 + const char *initrd;
308 + };
309 + static const struct fixed_pair suse_fp32 = {
310 + .image = "/suseboot/vmlinux32",
311 + .initrd = "/suseboot/initrd32",
312 + };
313 + static const struct fixed_pair suse_fp64 = {
314 + .image = "/suseboot/vmlinux64",
315 + .initrd = "/suseboot/initrd64",
316 + };
317 + const struct fixed_pair *suse_fp;
318
319 /* fixup for bare values */
320
321 @@ -73,32 +85,70 @@ static void yaboot_process_pair(struct conf_context *conf, const char *name,
322 /* image */
323
324 if (streq(name, "image")) {
325 + const char *g_boot = conf_get_global_option(conf, "boot");
326 + const char *g_part = conf_get_global_option(conf, "partition");
327 +
328 + /* First finish any previous image. */
329 +
330 if (state->opt->boot_image_file)
331 yaboot_finish(conf);
332
333 - state->opt->boot_image_file = resolve_path(state->opt, value,
334 - conf->dc->device_path);
335 - state->desc_image = talloc_strdup(state->opt, value);
336 + /* Then start the new image. */
337 +
338 + if (g_boot && g_part) {
339 + char* dev = talloc_asprintf(NULL, "%s%s", g_boot,
340 + g_part);
341 +
342 + state->opt->boot_image_file = resolve_path(state->opt,
343 + value, dev);
344 + state->desc_image = talloc_asprintf(state->opt,
345 + "%s%s", dev, value);
346 + talloc_free(dev);
347 + } else if (g_boot) {
348 + state->opt->boot_image_file = resolve_path(state->opt,
349 + value, g_boot);
350 + state->desc_image = talloc_asprintf(state->opt,
351 + "%s%s", g_boot, value);
352 + } else {
353 + state->opt->boot_image_file = resolve_path(state->opt,
354 + value, conf->dc->device_path);
355 + state->desc_image = talloc_strdup(state->opt, value);
356 + }
357 +
358 return;
359 }
360
361 - if (streq(name, "image[32bit]") || streq(name, "image[64bit]")) {
362 - state->found_suse = 1;
363 + /* Special processing for SUSE install CD. */
364 +
365 + if (streq(name, "image[32bit]"))
366 + suse_fp = &suse_fp32;
367 + else if (streq(name, "image[64bit]"))
368 + suse_fp = &suse_fp64;
369 + else
370 + suse_fp = NULL;
371 +
372 + if (suse_fp) {
373 + /* First finish any previous image. */
374
375 if (state->opt->boot_image_file)
376 yaboot_finish(conf);
377
378 + /* Then start the new image. */
379 +
380 if (*value == '/') {
381 state->opt->boot_image_file = resolve_path(state->opt,
382 value, conf->dc->device_path);
383 state->desc_image = talloc_strdup(state->opt, value);
384 } else {
385 - char *s;
386 - asprintf(&s, "/suseboot/%s", value);
387 state->opt->boot_image_file = resolve_path(state->opt,
388 - s, conf->dc->device_path);
389 - state->desc_image = talloc_strdup(state->opt, s);
390 - free(s);
391 + suse_fp->image, conf->dc->device_path);
392 + state->desc_image = talloc_strdup(state->opt,
393 + suse_fp->image);
394 +
395 + state->opt->initrd_file = resolve_path(state->opt,
396 + suse_fp->initrd, conf->dc->device_path);
397 + state->desc_initrd = talloc_asprintf(state, "initrd=%s",
398 + suse_fp->initrd);
399 }
400
401 return;
402 @@ -112,19 +162,28 @@ static void yaboot_process_pair(struct conf_context *conf, const char *name,
403 /* initrd */
404
405 if (streq(name, "initrd")) {
406 - if (!state->found_suse || (*value == '/')) {
407 + const char *g_boot = conf_get_global_option(conf, "boot");
408 + const char *g_part = conf_get_global_option(conf, "partition");
409 +
410 + if (g_boot && g_part) {
411 + char* dev = talloc_asprintf(NULL, "%s%s", g_boot,
412 + g_part);
413 +
414 state->opt->initrd_file = resolve_path(state->opt,
415 - value, conf->dc->device_path);
416 - state->desc_initrd = talloc_asprintf(state, "initrd=%s",
417 - value);
418 + value, dev);
419 + state->desc_initrd = talloc_asprintf(state,
420 + "initrd=%s%s", dev, value);
421 + talloc_free(dev);
422 + } else if (g_boot) {
423 + state->opt->initrd_file = resolve_path(state->opt,
424 + value, g_boot);
425 + state->desc_initrd = talloc_asprintf(state,
426 + "initrd=%s%s", g_boot, value);
427 } else {
428 - char *s;
429 - asprintf(&s, "/suseboot/%s", value);
430 state->opt->initrd_file = resolve_path(state->opt,
431 - s, conf->dc->device_path);
432 + value, conf->dc->device_path);
433 state->desc_initrd = talloc_asprintf(state, "initrd=%s",
434 - s);
435 - free(s);
436 + value);
437 }
438 return;
439 }
440 @@ -236,10 +295,11 @@ static int yaboot_parse(struct discover_context *dc)
441 conf = talloc_zero(dc, struct conf_context);
442
443 if (!conf)
444 - return -1;
445 + return 0;
446
447 conf->dc = dc;
448 conf->global_options = yaboot_global_options,
449 + conf_init_global_options(conf);
450 conf->conf_files = yaboot_conf_files,
451 conf->process_pair = yaboot_process_pair;
452 conf->finish = yaboot_finish;
453 diff --git a/lib/system/system.c b/lib/system/system.c
454 index 380dded..7371445 100644
455 --- a/lib/system/system.c
456 +++ b/lib/system/system.c
457 @@ -3,6 +3,7 @@
458 #include "config.h"
459 #endif
460
461 +#include <assert.h>
462 #include <errno.h>
463 #include <stdlib.h>
464 #include <string.h>
465 @@ -19,6 +20,7 @@ const struct pb_system_apps pb_system_apps = {
466 .cp = "/bin/cp",
467 .kexec = "/sbin/kexec",
468 .mount = "/bin/mount",
469 + .shutdown = "/sbin/shutdown",
470 .sftp = "/usr/bin/sftp",
471 .tftp = "/usr/bin/tftp",
472 .umount = "/bin/umount",
473 @@ -104,13 +106,13 @@ int pb_rmdir_recursive(const char *base, const char *dir)
474
475 int pb_run_cmd(const char *const *cmd_argv)
476 {
477 - int status;
478 - pid_t pid;
479 #if defined(DEBUG)
480 enum {do_debug = 1};
481 #else
482 enum {do_debug = 0};
483 #endif
484 + int status;
485 + pid_t pid;
486
487 if (do_debug) {
488 const char *const *p = cmd_argv;
489 @@ -125,12 +127,23 @@ int pb_run_cmd(const char *const *cmd_argv)
490 pb_log("%s: %s\n", __func__, cmd_argv[0]);
491
492 pid = fork();
493 +
494 if (pid == -1) {
495 pb_log("%s: fork failed: %s\n", __func__, strerror(errno));
496 return -1;
497 }
498
499 if (pid == 0) {
500 + int log = fileno(pb_log_get_stream());
501 +
502 + /* Redirect child output to log. */
503 +
504 + status = dup2(log, STDOUT_FILENO);
505 + assert(status != -1);
506 +
507 + status = dup2(log, STDERR_FILENO);
508 + assert(status != -1);
509 +
510 execvp(cmd_argv[0], (char *const *)cmd_argv);
511 pb_log("%s: exec failed: %s\n", __func__, strerror(errno));
512 exit(EXIT_FAILURE);
513 diff --git a/lib/system/system.h b/lib/system/system.h
514 index 47c7c02..1918309 100644
515 --- a/lib/system/system.h
516 +++ b/lib/system/system.h
517 @@ -5,6 +5,7 @@ struct pb_system_apps {
518 const char *cp;
519 const char *kexec;
520 const char *mount;
521 + const char *shutdown;
522 const char *sftp;
523 const char *tftp;
524 const char *umount;
525 diff --git a/man/pb-cui.8 b/man/pb-cui.8
526 new file mode 100644
527 index 0000000..e671c20
528 --- /dev/null
529 +++ b/man/pb-cui.8
530 @@ -0,0 +1,67 @@
531 +.\" Copyright (C) 2009 Sony Computer Entertainment Inc.
532 +.\" Copyright 2009 Sony Corp.
533 +.\"
534 +.\" This program is free software; you can redistribute it and/or modify
535 +.\" it under the terms of the GNU General Public License as published by
536 +.\" the Free Software Foundation; version 2 of the License.
537 +.\"
538 +.\" This program is distributed in the hope that it will be useful,
539 +.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
540 +.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
541 +.\" GNU General Public License for more details.
542 +.\"
543 +.\" You should have received a copy of the GNU General Public License
544 +.\" along with this program; if not, write to the Free Software
545 +.\" Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
546 +.\"
547 +.\" Maintainer's Notes:
548 +.\" * For syntax help see the man pages for 'mdoc' and 'mdoc.samples'.
549 +.\" * To check syntax use this:
550 +.\" 'groff -C -mtty-char -Tutf8 -man pb-cui.8'.
551 +.\" * To check format use this: 'less pb-cui.8'.
552 +.\"
553 +.Dd ""
554 +.Dt pb-cui 8
555 +.Os
556 +.\"
557 +.Sh NAME
558 +.\" ====
559 +.Nm pb-cui
560 +.Nd Petitboot ncurses bootloader UI
561 +.\"
562 +.Sh SYNOPSIS
563 +.\" ========
564 +.Nm
565 +.Op Fl h, -help
566 +.Op Fl l, -log Ar log-file
567 +.Op Fl V, -version
568 +.\"
569 +.Sh DESCRIPTION
570 +.\" ===========
571 +pb-cui is an ncurses based interface to the Petitboot bootloader.
572 +.Pp
573 +Petitboot is a Linux kexec based bootloader that supports loading Linux
574 +kernel and initrd images from any device that can be mounted by Linux.
575 +It can also load images from the network using the
576 +HTTP, HTTPS, NFS, SFTP, and TFTP
577 +protocols.
578 +.\"
579 +.Sh OPTIONS
580 +.\" =======
581 +.Bl -tag -width indent
582 +.\"
583 +.It Fl h, -help
584 +Print a help message.
585 +.\"
586 +.It Fl l, -log Ar log-file
587 +Log messages to the file
588 +.Ar log-file .
589 +The default log is a file pb-cui.log in the directory where pb-cui
590 +is started. New messages are appended to an existing log file.
591 +.\"
592 +.It Fl V, -version
593 +Display the program version number.
594 +.El
595 +.Sh SEE ALSO
596 +.\" ========
597 +.Xr petitboot 8 , Xr pb-discover 8 , Xr pb-event 8
598 diff --git a/man/pb-discover.8 b/man/pb-discover.8
599 new file mode 100644
600 index 0000000..9123e0f
601 --- /dev/null
602 +++ b/man/pb-discover.8
603 @@ -0,0 +1,44 @@
604 +.\" Copyright (C) 2009 Sony Computer Entertainment Inc.
605 +.\" Copyright 2009 Sony Corp.
606 +.\"
607 +.\" This program is free software; you can redistribute it and/or modify
608 +.\" it under the terms of the GNU General Public License as published by
609 +.\" the Free Software Foundation; version 2 of the License.
610 +.\"
611 +.\" This program is distributed in the hope that it will be useful,
612 +.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
613 +.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
614 +.\" GNU General Public License for more details.
615 +.\"
616 +.\" You should have received a copy of the GNU General Public License
617 +.\" along with this program; if not, write to the Free Software
618 +.\" Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
619 +.\"
620 +.\" Maintainer's Notes:
621 +.\" * For syntax help see the man pages for 'mdoc' and 'mdoc.samples'.
622 +.\" * To check syntax use this:
623 +.\" 'groff -C -mtty-char -Tutf8 -man pb-discover.8'.
624 +.\" * To check format use this: 'less pb-discover.8'.
625 +.\"
626 +.Dd ""
627 +.Dt pb-discover 8
628 +.Os
629 +.\"
630 +.Sh NAME
631 +.\" ====
632 +.Nm pb-discover
633 +.Nd The dynamic device discovery daemon of the Petitboot bootloader
634 +.\"
635 +.Sh SYNOPSIS
636 +.\" ========
637 +.Nm
638 +.\"
639 +.Sh DESCRIPTION
640 +.\" ===========
641 +pb-discover maintains a dynamic list of boot options available to
642 +the system. On startup, the petitboot user interface clients connect to
643 +pb-discover daemon and receive boot option information.
644 +.\"
645 +.Sh SEE ALSO
646 +.\" ========
647 +.Xr petitboot 8 , Xr pb-cui 8 , Xr pb-event 8
648 diff --git a/man/pb-event.8 b/man/pb-event.8
649 new file mode 100644
650 index 0000000..dc123e1
651 --- /dev/null
652 +++ b/man/pb-event.8
653 @@ -0,0 +1,43 @@
654 +.\" Copyright (C) 2009 Sony Computer Entertainment Inc.
655 +.\" Copyright 2009 Sony Corp.
656 +.\"
657 +.\" This program is free software; you can redistribute it and/or modify
658 +.\" it under the terms of the GNU General Public License as published by
659 +.\" the Free Software Foundation; version 2 of the License.
660 +.\"
661 +.\" This program is distributed in the hope that it will be useful,
662 +.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
663 +.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
664 +.\" GNU General Public License for more details.
665 +.\"
666 +.\" You should have received a copy of the GNU General Public License
667 +.\" along with this program; if not, write to the Free Software
668 +.\" Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
669 +.\"
670 +.\" Maintainer's Notes:
671 +.\" * For syntax help see the man pages for 'mdoc' and 'mdoc.samples'.
672 +.\" * To check syntax use this:
673 +.\" 'groff -C -mtty-char -Tutf8 -man pb-event.8'.
674 +.\" * To check format use this: 'less pb-event.8'.
675 +.\"
676 +.Dd ""
677 +.Dt pb-event 8
678 +.Os
679 +.\"
680 +.Sh NAME
681 +.\" ====
682 +.Nm pb-event
683 +.Nd Event helper for the Petitboot bootloader
684 +.\"
685 +.Sh SYNOPSIS
686 +.\" ========
687 +.Nm
688 +.\"
689 +.Sh DESCRIPTION
690 +.\" ===========
691 +The pb-event utility is used to send user mode events to pb-discover, the
692 +petitboot device discovery daemon.
693 +.\"
694 +.Sh SEE ALSO
695 +.\" ========
696 +.Xr petitboot 8 , Xr pb-cui 8 , Xr pb-discover 8
697 diff --git a/man/petitboot.8 b/man/petitboot.8
698 new file mode 100644
699 index 0000000..9dc2222
700 --- /dev/null
701 +++ b/man/petitboot.8
702 @@ -0,0 +1,47 @@
703 +.\" Copyright (C) 2009 Sony Computer Entertainment Inc.
704 +.\" Copyright 2009 Sony Corp.
705 +.\"
706 +.\" This program is free software; you can redistribute it and/or modify
707 +.\" it under the terms of the GNU General Public License as published by
708 +.\" the Free Software Foundation; version 2 of the License.
709 +.\"
710 +.\" This program is distributed in the hope that it will be useful,
711 +.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
712 +.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
713 +.\" GNU General Public License for more details.
714 +.\"
715 +.\" You should have received a copy of the GNU General Public License
716 +.\" along with this program; if not, write to the Free Software
717 +.\" Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
718 +.\"
719 +.\" Maintainer's Notes:
720 +.\" * For syntax help see the man pages for 'mdoc' and 'mdoc.samples'.
721 +.\" * To check syntax use this:
722 +.\" 'groff -C -mtty-char -Tutf8 -man petitboot.8'.
723 +.\" * To check format use this: 'less petitboot.8'.
724 +.\"
725 +.Dd ""
726 +.Dt petitboot 8
727 +.Os
728 +.\"
729 +.Sh NAME
730 +.\" ====
731 +.Nm petitboot
732 +.Nd The Petitboot bootloader
733 +.\"
734 +.Sh DESCRIPTION
735 +.\" ===========
736 +Petitboot is a platform independent bootloader based on Linux kexec.
737 +Petitboot can load Linux kernel and initrd images from any device that
738 +can be mounted by Linux, and can also load images from the network
739 +using the
740 +HTTP, HTTPS, NFS, SFTP, and TFTP
741 +protocols.
742 +.Pp
743 +Petitboot looks for bootloader configuration files on mountable devices
744 +in the system, and can also be configured to use boot information
745 +from a DHCP server.
746 +.\"
747 +.Sh SEE ALSO
748 +.\" ========
749 +.Xr pb-cui 8 , Xr pb-discover 8 , Xr pb-event 8
750 diff --git a/rules.mk b/rules.mk
751 index e743338..3b1dcfe 100644
752 --- a/rules.mk
753 +++ b/rules.mk
754 @@ -19,8 +19,8 @@ parser_test = test/parser-test
755 # install targets and components
756 daemons = $(pb_discover)
757 parsers = event kboot yaboot
758 -uis = $(pb_cui) $(pb_test)
759 -tests = $(parser_test)
760 +uis = $(pb_cui)
761 +tests = $(parser_test) $(pb_test)
762 utils = $(pb_event)
763
764 ifeq ($(PBTWIN),y)
765 @@ -29,6 +29,7 @@ endif
766
767 # other to install
768 artwork = background.jpg cdrom.png hdd.png usbpen.png tux.png cursor.gz
769 +man8 = pb-cui.8 pb-discover.8 pb-event.8 petitboot.8
770 rules = utils/99-petitboot.rules
771 udhcpc = utils/udhcpc
772
773 @@ -48,10 +49,11 @@ discover_objs = discover/event.o discover/user-event.o discover/udev.o \
774 discover/parser-utils.o
775
776 # client objs
777 -ui_common_objs = ui/common/discover-client.o ui/common/loader.o \
778 - ui/common/ui-system.o ui/common/url.o
779 -ncurses_objs = ui/ncurses/nc-scr.o ui/ncurses/nc-menu.o \
780 - ui/ncurses/nc-ked.o ui/ncurses/nc-cui.o
781 +ui_common_objs = ui/common/discover-client.o ui/common/joystick.o \
782 + ui/common/loader.o ui/common/ui-system.o ui/common/timer.o \
783 + ui/common/url.o
784 +ncurses_objs = ui/ncurses/nc-scr.o ui/ncurses/nc-menu.o ui/ncurses/nc-ked.o \
785 + ui/ncurses/nc-cui.o
786 twin_objs = ui/twin/pb-twin.o
787
788 # Makefiles
789 @@ -68,6 +70,7 @@ client_objs = $(lib_objs) $(ui_common_objs)
790 all: $(uis) $(daemons) $(utils)
791
792 # ncurses cui
793 +pb_cui_objs-y$(ENABLE_PS3) += ui/ncurses/pb-cui.o
794 pb_cui_objs-$(ENABLE_PS3) += ui/ncurses/ps3-cui.o ui/common/ps3.o
795 pb_cui_ldflags-$(ENABLE_PS3) += -lps3-utils
796
797 @@ -120,13 +123,16 @@ parser-test: $(parser_test)
798
799 install: all $(rules) $(udhcpc)
800 $(INSTALL) -d $(DESTDIR)$(sbindir)/
801 - $(INSTALL) $(daemons) $(uis) $(utils) $(DESTDIR)$(sbindir)/
802 + $(INSTALL_PROGRAM) $(daemons) $(uis) $(utils) $(DESTDIR)$(sbindir)/
803 $(INSTALL) -d $(DESTDIR)$(pkgdatadir)/artwork/
804 - $(INSTALL) $(addprefix $(top_srcdir)/ui/twin/artwork/,$(artwork)) \
805 + $(INSTALL_DATA) $(addprefix $(top_srcdir)/ui/twin/artwork/,$(artwork)) \
806 $(DESTDIR)$(pkgdatadir)/artwork/
807 $(INSTALL) -d $(DESTDIR)$(pkgdatadir)/utils
808 - $(INSTALL) -m 644 $(top_srcdir)/$(rules) $(DESTDIR)$(pkgdatadir)/utils
809 - $(INSTALL) -m 644 $(top_srcdir)/$(udhcpc) $(DESTDIR)$(pkgdatadir)/utils
810 + $(INSTALL_DATA) $(top_srcdir)/$(rules) $(DESTDIR)$(pkgdatadir)/utils
811 + $(INSTALL_DATA) $(top_srcdir)/$(udhcpc) $(DESTDIR)$(pkgdatadir)/utils
812 + $(INSTALL) -d $(DESTDIR)$(mandir)/man8/
813 + $(INSTALL_DATA) $(addprefix $(top_srcdir)/man/, $(man8)) \
814 + $(DESTDIR)$(mandir)/man8/
815
816 dist: $(PACKAGE)-$(VERSION).tar.gz
817
818 diff --git a/ui/common/joystick.c b/ui/common/joystick.c
819 new file mode 100644
820 index 0000000..94c85fe
821 --- /dev/null
822 +++ b/ui/common/joystick.c
823 @@ -0,0 +1,106 @@
824 +/*
825 + * Copyright (C) 2009 Sony Computer Entertainment Inc.
826 + * Copyright 2009 Sony Corp.
827 + *
828 + * This program is free software; you can redistribute it and/or modify
829 + * it under the terms of the GNU General Public License as published by
830 + * the Free Software Foundation; version 2 of the License.
831 + *
832 + * This program is distributed in the hope that it will be useful,
833 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
834 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
835 + * GNU General Public License for more details.
836 + *
837 + * You should have received a copy of the GNU General Public License
838 + * along with this program; if not, write to the Free Software
839 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
840 + */
841 +
842 +#if defined(HAVE_CONFIG_H)
843 +#include "config.h"
844 +#endif
845 +
846 +#define _GNU_SOURCE
847 +#include <assert.h>
848 +#include <errno.h>
849 +#include <fcntl.h>
850 +#include <string.h>
851 +#include <sys/stat.h>
852 +#include <sys/types.h>
853 +
854 +#include "log/log.h"
855 +#include "talloc/talloc.h"
856 +#include "joystick.h"
857 +
858 +/**
859 + * pjs_process_event - Read joystick event and map to UI key code.
860 + *
861 + * Returns a map routine UI key code or zero.
862 + */
863 +
864 +int pjs_process_event(const struct pjs *pjs)
865 +{
866 + int result;
867 + struct js_event e;
868 +
869 + assert(pjs->fd);
870 +
871 + result = read(pjs->fd, &e, sizeof(e));
872 +
873 + if (result != sizeof(e)) {
874 + pb_log("%s: read failed: %s\n", __func__, strerror(errno));
875 + return 0;
876 + }
877 +
878 + return pjs->map(&e);
879 +}
880 +
881 +/**
882 + * pjs_destructor - The talloc destructor for a joystick handler.
883 + */
884 +
885 +static int pjs_destructor(void *arg)
886 +{
887 + struct pjs *pjs = pjs_from_arg(arg);
888 +
889 + close(pjs->fd);
890 + pjs->fd = 0;
891 +
892 + return 0;
893 +}
894 +
895 +/**
896 + * pjs_init - Initialize the joystick event handler.
897 + */
898 +
899 +struct pjs *pjs_init(void *ctx, int (*map)(const struct js_event *))
900 +{
901 + static const char dev_name[] = "/dev/input/js0";
902 + struct pjs *pjs;
903 +
904 + pjs = talloc_zero(ctx, struct pjs);
905 +
906 + if (!pjs)
907 + return NULL;
908 +
909 + pjs->map = map;
910 + pjs->fd = open(dev_name, O_RDONLY | O_NONBLOCK);
911 +
912 + if (pjs->fd < 0) {
913 + pb_log("%s: open %s failed: %s\n", __func__, dev_name,
914 + strerror(errno));
915 + goto out_err;
916 + }
917 +
918 + talloc_set_destructor(pjs, pjs_destructor);
919 +
920 + pb_log("%s: using %s\n", __func__, dev_name);
921 +
922 + return pjs;
923 +
924 +out_err:
925 + close(pjs->fd);
926 + pjs->fd = 0;
927 + talloc_free(pjs);
928 + return NULL;
929 +}
930 diff --git a/ui/common/joystick.h b/ui/common/joystick.h
931 new file mode 100644
932 index 0000000..cf3fc45
933 --- /dev/null
934 +++ b/ui/common/joystick.h
935 @@ -0,0 +1,47 @@
936 +/*
937 + * Copyright (C) 2009 Sony Computer Entertainment Inc.
938 + * Copyright 2009 Sony Corp.
939 + *
940 + * This program is free software; you can redistribute it and/or modify
941 + * it under the terms of the GNU General Public License as published by
942 + * the Free Software Foundation; version 2 of the License.
943 + *
944 + * This program is distributed in the hope that it will be useful,
945 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
946 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
947 + * GNU General Public License for more details.
948 + *
949 + * You should have received a copy of the GNU General Public License
950 + * along with this program; if not, write to the Free Software
951 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
952 + */
953 +
954 +#if !defined(_PB_JOYSTICK_H)
955 +#define _PB_JOYSTICK_H
956 +
957 +#include <linux/joystick.h>
958 +
959 +/**
960 + * struct pjs - Petitboot joystick event handler.
961 + * @map: Routine to map from a Linux struct js_event to a ui key code.
962 + */
963 +
964 +struct pjs {
965 + int fd;
966 + int (*map)(const struct js_event *e);
967 +};
968 +
969 +struct pjs *pjs_init(void *ctx, int (*map)(const struct js_event *));
970 +int pjs_process_event(const struct pjs *pjs);
971 +
972 +static inline struct pjs *pjs_from_arg(void *arg)
973 +{
974 + return arg;
975 +}
976 +
977 +static inline int pjs_get_fd(const struct pjs *pjs)
978 +{
979 + return pjs->fd;
980 +}
981 +
982 +#endif
983 diff --git a/ui/common/loader.c b/ui/common/loader.c
984 index babca28..5c69533 100644
985 --- a/ui/common/loader.c
986 +++ b/ui/common/loader.c
987 @@ -227,7 +227,7 @@ enum wget_flags {
988 static char *pb_load_wget(void *ctx, struct pb_url *url, enum wget_flags flags)
989 {
990 int result;
991 - const char *argv[6];
992 + const char *argv[7];
993 const char **p;
994 char *local;
995
996 @@ -238,12 +238,15 @@ static char *pb_load_wget(void *ctx, struct pb_url *url, enum wget_flags flags)
997
998 p = argv;
999 *p++ = pb_system_apps.wget; /* 1 */
1000 - *p++ = "-O"; /* 2 */
1001 - *p++ = local; /* 3 */
1002 - *p++ = url->full; /* 4 */
1003 +#if !defined(DEBUG)
1004 + *p++ = "--quiet"; /* 2 */
1005 +#endif
1006 + *p++ = "-O"; /* 3 */
1007 + *p++ = local; /* 4 */
1008 + *p++ = url->full; /* 5 */
1009 if (flags & wget_no_check_certificate)
1010 - *p++ = "--no-check-certificate"; /* 5 */
1011 - *p++ = NULL; /* 6 */
1012 + *p++ = "--no-check-certificate"; /* 6 */
1013 + *p++ = NULL; /* 7 */
1014
1015 result = pb_run_cmd(argv);
1016
1017 @@ -260,16 +263,22 @@ fail:
1018 /**
1019 * pb_load_file - Loads a remote file and returns the local file path.
1020 * @ctx: The talloc context to associate with the returned string.
1021 + * @remote: The remote file URL.
1022 + * @tempfile: An optional variable pointer to be set when a temporary local
1023 + * file is created.
1024 *
1025 * Returns the local file path in a talloc'ed character string on success,
1026 * or NULL on error.
1027 */
1028
1029 -char *pb_load_file(void *ctx, const char *remote)
1030 +char *pb_load_file(void *ctx, const char *remote, unsigned int *tempfile)
1031 {
1032 char *local;
1033 struct pb_url *url = pb_url_parse(NULL, remote);
1034
1035 + if (tempfile)
1036 + *tempfile = 0;
1037 +
1038 if (!url)
1039 return NULL;
1040
1041 @@ -277,19 +286,28 @@ char *pb_load_file(void *ctx, const char *remote)
1042 case pb_url_ftp:
1043 case pb_url_http:
1044 local = pb_load_wget(ctx, url, 0);
1045 + if (tempfile && local)
1046 + *tempfile = 1;
1047 break;
1048 case pb_url_https:
1049 - local = pb_load_wget(ctx, url,
1050 - wget_no_check_certificate);
1051 + local = pb_load_wget(ctx, url, wget_no_check_certificate);
1052 + if (tempfile && local)
1053 + *tempfile = 1;
1054 break;
1055 case pb_url_nfs:
1056 local = pb_load_nfs(ctx, url);
1057 + if (tempfile && local)
1058 + *tempfile = 1;
1059 break;
1060 case pb_url_sftp:
1061 local = pb_load_sftp(ctx, url);
1062 + if (tempfile && local)
1063 + *tempfile = 1;
1064 break;
1065 case pb_url_tftp:
1066 local = pb_load_tftp(ctx, url);
1067 + if (tempfile && local)
1068 + *tempfile = 1;
1069 break;
1070 default:
1071 local = talloc_strdup(ctx, url->full);
1072 diff --git a/ui/common/loader.h b/ui/common/loader.h
1073 index b06bb43..42d4d4b 100644
1074 --- a/ui/common/loader.h
1075 +++ b/ui/common/loader.h
1076 @@ -19,6 +19,6 @@
1077 #if !defined(_PB_FILE_LOADER_H)
1078 #define _PB_FILE_LOADER_H
1079
1080 -char *pb_load_file(void *ctx, const char *remote);
1081 +char *pb_load_file(void *ctx, const char *remote, unsigned int *tempfile);
1082
1083 #endif
1084 diff --git a/ui/common/ps3.c b/ui/common/ps3.c
1085 index 5c83289..cb1c8d1 100644
1086 --- a/ui/common/ps3.c
1087 +++ b/ui/common/ps3.c
1088 @@ -49,6 +49,11 @@ static const struct os_area_db_id id_flags =
1089 .owner = OS_AREA_DB_OWNER_PETITBOOT, /* 3 */
1090 .key = 3,
1091 };
1092 +static const struct os_area_db_id id_timeout =
1093 +{
1094 + .owner = OS_AREA_DB_OWNER_PETITBOOT, /* 3 */
1095 + .key = 4,
1096 +};
1097
1098 struct ps3_flash_ctx {
1099 FILE *dev;
1100 @@ -59,6 +64,8 @@ struct ps3_flash_ctx {
1101
1102 static void ps3_flash_close(struct ps3_flash_ctx *fc)
1103 {
1104 + assert(fc->dev);
1105 +
1106 fclose(fc->dev);
1107 fc->dev = NULL;
1108 }
1109 @@ -104,19 +111,19 @@ int ps3_flash_get_values(struct ps3_flash_values *values)
1110 struct ps3_flash_ctx fc;
1111 uint64_t tmp;
1112
1113 - memset(values, 0, sizeof(*values));
1114 -
1115 result = ps3_flash_open(&fc, "r");
1116
1117 if (result)
1118 - return -1;
1119 + goto done;
1120
1121 result = os_area_db_read(&fc.db, &fc.header, fc.dev);
1122
1123 + ps3_flash_close(&fc);
1124 +
1125 if (result) {
1126 pb_log("%s: os_area_db_read failed: %s\n", __func__,
1127 strerror(errno));
1128 - goto fail;
1129 + goto done;
1130 }
1131
1132 sum = result = os_area_db_get(&fc.db, &id_default_item, &tmp);
1133 @@ -124,21 +131,25 @@ int ps3_flash_get_values(struct ps3_flash_values *values)
1134 if (!result)
1135 values->default_item = (uint32_t)tmp;
1136
1137 - sum += result = os_area_db_get(&fc.db, &id_video_mode, &tmp);
1138 + result = os_area_db_get(&fc.db, &id_timeout, &tmp);
1139
1140 if (!result)
1141 - values->video_mode = (uint16_t)tmp;
1142 + values->timeout = (uint8_t)tmp;
1143
1144 + sum += result = os_area_db_get(&fc.db, &id_video_mode, &tmp);
1145
1146 - pb_log("%s: default_item: %u\n", __func__, values->default_item);
1147 - pb_log("%s: video_mode: %u\n", __func__, values->video_mode);
1148 + if (!result)
1149 + values->video_mode = (uint16_t)tmp;
1150
1151 - ps3_flash_close(&fc);
1152 - return !!sum;
1153 +done:
1154 + pb_log("%s: default_item: %x\n", __func__,
1155 + (unsigned int)values->default_item);
1156 + pb_log("%s: timeout: %u\n", __func__,
1157 + (unsigned int)values->timeout);
1158 + pb_log("%s: video_mode: %u\n", __func__,
1159 + (unsigned int)values->video_mode);
1160
1161 -fail:
1162 - ps3_flash_close(&fc);
1163 - return -1;
1164 + return (result || sum) ? -1 : 0;
1165 }
1166
1167 /**
1168 @@ -177,6 +188,8 @@ int ps3_flash_set_values(const struct ps3_flash_values *values)
1169 }
1170 }
1171
1172 + /* timeout is currently read-only, set with ps3-bl-option */
1173 +
1174 result = os_area_db_set_32(&fc.db, &id_default_item,
1175 values->default_item);
1176 result += os_area_db_set_16(&fc.db, &id_video_mode,
1177 diff --git a/ui/common/ps3.h b/ui/common/ps3.h
1178 index 8a7fe1c..5ba8afe 100644
1179 --- a/ui/common/ps3.h
1180 +++ b/ui/common/ps3.h
1181 @@ -33,9 +33,14 @@ enum ps3_flash_flags {
1182 ps3_flag_telnet = 1,
1183 };
1184
1185 +enum ps3_timeouts {
1186 + ps3_timeout_forever = 255,
1187 +};
1188 +
1189 /**
1190 * struct ps3_flash_values - Values from PS3 flash memory.
1191 * @default_item: The default menu item.
1192 + * @timeout: The timeout in seconds.
1193 * @video_mode: The default video_mode.
1194 * @flags: Logical OR of enum ps3_flash_flags.
1195 */
1196 @@ -44,6 +49,13 @@ struct ps3_flash_values {
1197 uint32_t default_item;
1198 uint16_t video_mode;
1199 /* uint16_t flags; */
1200 + uint8_t timeout;
1201 +};
1202 +
1203 +static const struct ps3_flash_values ps3_flash_defaults = {
1204 + .default_item = 0,
1205 + .video_mode = 1,
1206 + .timeout = ps3_timeout_forever,
1207 };
1208
1209 int ps3_flash_get_values(struct ps3_flash_values *values);
1210 diff --git a/ui/common/timer.c b/ui/common/timer.c
1211 new file mode 100644
1212 index 0000000..954a18a
1213 --- /dev/null
1214 +++ b/ui/common/timer.c
1215 @@ -0,0 +1,139 @@
1216 +/*
1217 + * Copyright (C) 2009 Sony Computer Entertainment Inc.
1218 + * Copyright 2009 Sony Corp.
1219 + *
1220 + * This program is free software; you can redistribute it and/or modify
1221 + * it under the terms of the GNU General Public License as published by
1222 + * the Free Software Foundation; version 2 of the License.
1223 + *
1224 + * This program is distributed in the hope that it will be useful,
1225 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1226 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1227 + * GNU General Public License for more details.
1228 + *
1229 + * You should have received a copy of the GNU General Public License
1230 + * along with this program; if not, write to the Free Software
1231 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
1232 + */
1233 +
1234 +#if defined(HAVE_CONFIG_H)
1235 +#include "config.h"
1236 +#endif
1237 +
1238 +#define _GNU_SOURCE
1239 +#include <assert.h>
1240 +#include <limits.h>
1241 +#include <unistd.h>
1242 +
1243 +#include "log/log.h"
1244 +#include "timer.h"
1245 +
1246 +/**
1247 + * ui_timer_init - Initialize the timer for use.
1248 + * @seconds: The final timeout value in seconds.
1249 + */
1250 +
1251 +void ui_timer_init(struct ui_timer *timer, unsigned int seconds)
1252 +{
1253 + pb_log("%s: %u\n", __func__, seconds);
1254 + assert(!timer->disabled);
1255 + timer->timeout = seconds;
1256 +}
1257 +
1258 +/**
1259 + * ui_timer_next - Calculate the next timer interval.
1260 + */
1261 +
1262 +static unsigned int ui_timer_next(unsigned int seconds)
1263 +{
1264 + unsigned int next;
1265 +
1266 + if (seconds == 0) {
1267 + next = 0;
1268 + goto done;
1269 + }
1270 +
1271 + if (seconds <= 10) {
1272 + next = 1;
1273 + goto done;
1274 + }
1275 +
1276 + if (seconds <= 60) {
1277 + next = seconds % 5;
1278 + next = next ? next : 5;
1279 + goto done;
1280 + }
1281 +
1282 + next = seconds % 10;
1283 + next = next ? next : 10;
1284 +
1285 +done:
1286 + pb_log("%s: %u = %u\n", __func__, seconds, next);
1287 + return next;
1288 +}
1289 +
1290 +/**
1291 + * ui_timer_kick - Kickstart the next timer interval.
1292 + */
1293 +
1294 +void ui_timer_kick(struct ui_timer *timer)
1295 +{
1296 + unsigned int next;
1297 +
1298 + if(timer->disabled)
1299 + return;
1300 +
1301 + if (timer->update_display)
1302 + timer->update_display(timer, timer->timeout);
1303 +
1304 + next = ui_timer_next(timer->timeout);
1305 + timer->timeout -= next;
1306 +
1307 + if (next) {
1308 + alarm(next);
1309 + return;
1310 + }
1311 +
1312 + pb_log("%s: timed out\n", __func__);
1313 +
1314 + ui_timer_disable(timer);
1315 + timer->handle_timeout(timer);
1316 +}
1317 +
1318 +/**
1319 + * ui_timer_disable - Stop and disable the timer.
1320 + */
1321 +
1322 +void ui_timer_disable(struct ui_timer *timer)
1323 +{
1324 + if (timer->disabled)
1325 + return;
1326 +
1327 + pb_log("%s\n", __func__);
1328 + timer->disabled = 1;
1329 + timer->timeout = UINT_MAX;
1330 + alarm(0);
1331 +}
1332 +
1333 +/**
1334 + * ui_timer_sigalrm
1335 + *
1336 + * Called at SIGALRM.
1337 + */
1338 +
1339 +void ui_timer_sigalrm(struct ui_timer *timer)
1340 +{
1341 + timer->signaled = 1;
1342 +}
1343 +
1344 +/**
1345 + * ui_timer_process_sig - Process a timer signal
1346 + */
1347 +
1348 +void ui_timer_process_sig(struct ui_timer *timer)
1349 +{
1350 + while (timer->signaled) {
1351 + timer->signaled = 0;
1352 + ui_timer_kick(timer);
1353 + }
1354 +}
1355 diff --git a/ui/common/timer.h b/ui/common/timer.h
1356 new file mode 100644
1357 index 0000000..781b442
1358 --- /dev/null
1359 +++ b/ui/common/timer.h
1360 @@ -0,0 +1,42 @@
1361 +/*
1362 + * Copyright (C) 2009 Sony Computer Entertainment Inc.
1363 + * Copyright 2009 Sony Corp.
1364 + *
1365 + * This program is free software; you can redistribute it and/or modify
1366 + * it under the terms of the GNU General Public License as published by
1367 + * the Free Software Foundation; version 2 of the License.
1368 + *
1369 + * This program is distributed in the hope that it will be useful,
1370 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1371 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1372 + * GNU General Public License for more details.
1373 + *
1374 + * You should have received a copy of the GNU General Public License
1375 + * along with this program; if not, write to the Free Software
1376 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
1377 + */
1378 +
1379 +#if !defined(_PB_UI_TIMER_H)
1380 +#define _PB_UI_TIMER_H
1381 +
1382 +#include <signal.h>
1383 +
1384 +/**
1385 + * struct ui_timer - UI timeout.
1386 + */
1387 +
1388 +struct ui_timer {
1389 + unsigned int timeout;
1390 + unsigned int disabled;
1391 + sig_atomic_t signaled;
1392 + void (*update_display)(struct ui_timer *timer, unsigned int timeout);
1393 + void (*handle_timeout)(struct ui_timer *timer);
1394 +};
1395 +
1396 +void ui_timer_init(struct ui_timer *timer, unsigned int seconds);
1397 +void ui_timer_kick(struct ui_timer *timer);
1398 +void ui_timer_disable(struct ui_timer *timer);
1399 +void ui_timer_sigalrm(struct ui_timer *timer);
1400 +void ui_timer_process_sig(struct ui_timer *timer);
1401 +
1402 +#endif
1403 diff --git a/ui/common/ui-system.c b/ui/common/ui-system.c
1404 index 3f54191..0140f0e 100644
1405 --- a/ui/common/ui-system.c
1406 +++ b/ui/common/ui-system.c
1407 @@ -33,46 +33,80 @@
1408 #include "ui-system.h"
1409
1410 /**
1411 - * run_kexec_local - Final kexec helper.
1412 + * kexec_load - kexec load helper.
1413 * @l_image: The local image file for kexec to execute.
1414 * @l_initrd: Optional local initrd file for kexec --initrd, can be NULL.
1415 * @args: Optional command line args for kexec --append, can be NULL.
1416 */
1417
1418 -static int run_kexec_local(const char *l_image, const char *l_initrd,
1419 +static int kexec_load(const char *l_image, const char *l_initrd,
1420 const char *args)
1421 {
1422 int result;
1423 - const char *argv[8];
1424 + const char *argv[6];
1425 const char **p;
1426 + char *s_initrd = NULL;
1427 + char *s_args = NULL;
1428
1429 p = argv;
1430 - *p++ = pb_system_apps.kexec; /* 1 */
1431 + *p++ = pb_system_apps.kexec; /* 1 */
1432 + *p++ = "-l"; /* 2 */
1433
1434 if (l_initrd) {
1435 - *p++ = "--initrd"; /* 2 */
1436 - *p++ = l_initrd; /* 3 */
1437 + s_initrd = talloc_asprintf(NULL, "--initrd=%s", l_initrd);
1438 + assert(s_initrd);
1439 + *p++ = s_initrd; /* 3 */
1440 }
1441
1442 if (args) {
1443 - *p++ = "--append"; /* 4 */
1444 - *p++ = args; /* 5 */
1445 + s_args = talloc_asprintf(NULL, "--append=%s", args);
1446 + assert(s_args);
1447 + *p++ = s_args; /* 4 */
1448 }
1449
1450 - /* First try by telling kexec to run shutdown */
1451 + *p++ = l_image; /* 5 */
1452 + *p++ = NULL; /* 6 */
1453
1454 - *(p + 0) = l_image;
1455 - *(p + 1) = NULL;
1456 + result = pb_run_cmd(argv);
1457 +
1458 + if (result)
1459 + pb_log("%s: failed: (%d)\n", __func__, result);
1460 +
1461 + talloc_free(s_initrd);
1462 + talloc_free(s_args);
1463 +
1464 + return result;
1465 +}
1466 +
1467 +/**
1468 + * kexec_reboot - Helper to boot the new kernel.
1469 + *
1470 + * Must only be called after a successful call to kexec_load().
1471 + */
1472 +
1473 +static int kexec_reboot(void)
1474 +{
1475 + int result;
1476 + const char *argv[4];
1477 + const char **p;
1478 +
1479 + /* First try running shutdown. Init scripts should run 'exec -e' */
1480 +
1481 + p = argv;
1482 + *p++ = pb_system_apps.shutdown; /* 1 */
1483 + *p++ = "-r"; /* 2 */
1484 + *p++ = "now"; /* 3 */
1485 + *p++ = NULL; /* 4 */
1486
1487 result = pb_run_cmd(argv);
1488
1489 - /* kexec will return zero on success */
1490 - /* On error, force a kexec with the -f option */
1491 + /* On error, force a kexec with the -e option */
1492
1493 if (result) {
1494 - *(p + 0) = "-f"; /* 6 */
1495 - *(p + 1) = l_image; /* 7 */
1496 - *(p + 2) = NULL; /* 8 */
1497 + p = argv;
1498 + *p++ = pb_system_apps.kexec; /* 1 */
1499 + *p++ = "-e"; /* 2 */
1500 + *p++ = NULL; /* 3 */
1501
1502 result = pb_run_cmd(argv);
1503 }
1504 @@ -85,38 +119,51 @@ static int run_kexec_local(const char *l_image, const char *l_initrd,
1505
1506 /**
1507 * pb_run_kexec - Run kexec with the supplied boot options.
1508 - *
1509 - * For the convenience of the user, tries to load both files before
1510 - * returning error.
1511 */
1512
1513 int pb_run_kexec(const struct pb_kexec_data *kd)
1514 {
1515 int result;
1516 - char *l_image;
1517 - char *l_initrd;
1518 + char *l_image = NULL;
1519 + char *l_initrd = NULL;
1520 + unsigned int clean_image = 0;
1521 + unsigned int clean_initrd = 0;
1522
1523 pb_log("%s: image: '%s'\n", __func__, kd->image);
1524 pb_log("%s: initrd: '%s'\n", __func__, kd->initrd);
1525 pb_log("%s: args: '%s'\n", __func__, kd->args);
1526
1527 - if (kd->image)
1528 - l_image = pb_load_file(NULL, kd->image);
1529 - else {
1530 - l_image = NULL;
1531 - pb_log("%s: error null image\n", __func__);
1532 + result = -1;
1533 +
1534 + if (kd->image) {
1535 + l_image = pb_load_file(NULL, kd->image, &clean_image);
1536 + if (!l_image)
1537 + goto no_load;
1538 + }
1539 +
1540 + if (kd->initrd) {
1541 + l_initrd = pb_load_file(NULL, kd->initrd, &clean_initrd);
1542 + if (!l_initrd)
1543 + goto no_load;
1544 }
1545
1546 - l_initrd = kd->initrd ? pb_load_file(NULL, kd->initrd) : NULL;
1547 + if (!l_image && !l_initrd)
1548 + goto no_load;
1549 +
1550 + result = kexec_load(l_image, l_initrd, kd->args);
1551
1552 - if (!l_image || (kd->initrd && !l_initrd))
1553 - result = -1;
1554 - else
1555 - result = run_kexec_local(l_image, l_initrd, kd->args);
1556 +no_load:
1557 + if (clean_image)
1558 + unlink(l_image);
1559 + if (clean_initrd)
1560 + unlink(l_initrd);
1561
1562 talloc_free(l_image);
1563 talloc_free(l_initrd);
1564
1565 + if (!result)
1566 + result = kexec_reboot();
1567 +
1568 return result;
1569 }
1570
1571 diff --git a/ui/ncurses/nc-cui.c b/ui/ncurses/nc-cui.c
1572 index 2a4c971..aed5ff7 100644
1573 --- a/ui/ncurses/nc-cui.c
1574 +++ b/ui/ncurses/nc-cui.c
1575 @@ -30,7 +30,6 @@
1576 #include "ui/common/discover-client.h"
1577 #include "nc-cui.h"
1578
1579 -
1580 static struct cui_opt_data *cod_from_item(struct pmenu_item *item)
1581 {
1582 return item->data;
1583 @@ -61,6 +60,35 @@ void cui_resize(struct cui *cui)
1584 }
1585
1586 /**
1587 + * cui_make_item_name - Format the menu item name srting.
1588 + *
1589 + * Returns a talloc string.
1590 + */
1591 +
1592 +static char *cui_make_item_name(struct pmenu_item *i, struct cui_opt_data *cod)
1593 +{
1594 + char *name;
1595 +
1596 + assert(cod->name);
1597 + assert(cod->kd);
1598 +
1599 + name = talloc_asprintf(i, "%s:", cod->name);
1600 +
1601 + if (cod->kd->image)
1602 + name = talloc_asprintf_append(name, " %s", cod->kd->image);
1603 +
1604 + if (cod->kd->initrd)
1605 + name = talloc_asprintf_append(name, " initrd=%s",
1606 + cod->kd->initrd);
1607 +
1608 + if (cod->kd->args)
1609 + name = talloc_asprintf_append(name, " %s", cod->kd->args);
1610 +
1611 + DBGS("@%s@\n", name);
1612 + return name;
1613 +}
1614 +
1615 +/**
1616 * cui_on_exit - A generic main menu ESC callback.
1617 */
1618
1619 @@ -109,8 +137,8 @@ static int cui_run_kexec(struct pmenu_item *item)
1620 assert(cui->current == &cui->main->scr);
1621 assert(cui->on_kexec);
1622
1623 - pb_log("%s: %s\n", __func__, cod->dev->name, cod->opt->name);
1624 - nc_scr_status_printf(cui->current, "Booting %s...", cod->opt->name);
1625 + pb_log("%s: %s\n", __func__, cod->name);
1626 + nc_scr_status_printf(cui->current, "Booting %s...", cod->name);
1627
1628 def_prog_mode();
1629
1630 @@ -141,9 +169,10 @@ static void cui_ked_on_exit(struct ked *ked, enum ked_result ked_result,
1631 {
1632 struct cui *cui = cui_from_arg(ked->scr.ui_ctx);
1633
1634 - if (ked_result == ked_update || ked_result == ked_boot) {
1635 + if (ked_result == ked_update) {
1636 struct pmenu_item *i = pmenu_find_selected(cui->main);
1637 struct cui_opt_data *cod = cod_from_item(i);
1638 + char *name;
1639
1640 assert(kd);
1641
1642 @@ -151,7 +180,13 @@ static void cui_ked_on_exit(struct ked *ked, enum ked_result ked_result,
1643 talloc_free(cod->kd);
1644 cod->kd = kd;
1645
1646 - pb_log("%s: updating opt '%s'\n", __func__, cod->opt->name);
1647 + name = cui_make_item_name(i, cod);
1648 + pmenu_item_replace(i, name);
1649 +
1650 + /* FIXME: need to make item visible somehow */
1651 + set_current_item(cui->main->ncm, i->nci);
1652 +
1653 + pb_log("%s: updating opt '%s'\n", __func__, cod->name);
1654 pb_log(" image '%s'\n", cod->kd->image);
1655 pb_log(" initrd '%s'\n", cod->kd->initrd);
1656 pb_log(" args '%s'\n", cod->kd->args);
1657 @@ -160,20 +195,15 @@ static void cui_ked_on_exit(struct ked *ked, enum ked_result ked_result,
1658 cui_set_current(cui, &cui->main->scr);
1659
1660 talloc_free(ked);
1661 -
1662 - if (ked_result == ked_boot) {
1663 - struct pmenu_item *i = pmenu_find_selected(cui->main);
1664 - i->on_execute(i);
1665 - }
1666 }
1667
1668 int cui_ked_run(struct pmenu_item *item)
1669 {
1670 struct cui *cui = cui_from_item(item);
1671 + struct cui_opt_data *cod = cod_from_item(item);
1672 struct ked *ked;
1673
1674 - ked = ked_init(cui, cod_from_item(item)->kd, cui_ked_on_exit);
1675 -
1676 + ked = ked_init(cui, cod->kd, cui_ked_on_exit);
1677 cui_set_current(cui, &ked->scr);
1678
1679 return 0;
1680 @@ -200,14 +230,43 @@ struct nc_scr *cui_set_current(struct cui *cui, struct nc_scr *scr)
1681 return old;
1682 }
1683
1684 +/**
1685 + * cui_process_key - Process input on stdin.
1686 + */
1687 +
1688 static int cui_process_key(void *arg)
1689 {
1690 struct cui *cui = cui_from_arg(arg);
1691
1692 assert(cui->current);
1693 +
1694 + ui_timer_disable(&cui->timer);
1695 cui->current->process_key(cui->current);
1696 +
1697 + return 0;
1698 +}
1699 +
1700 +/**
1701 + * cui_process_js - Process joystick events.
1702 + */
1703 +
1704 +static int cui_process_js(void *arg)
1705 +{
1706 + struct cui *cui = cui_from_arg(arg);
1707 + int c;
1708 +
1709 + c = pjs_process_event(cui->pjs);
1710 +
1711 + if (c) {
1712 + ungetch(c);
1713 + cui_process_key(arg);
1714 + }
1715 +
1716 return 0;
1717 }
1718 +/**
1719 + * cui_client_process_socket - Process a socket event from the discover server.
1720 + */
1721
1722 static int cui_client_process_socket(void *arg)
1723 {
1724 @@ -218,6 +277,24 @@ static int cui_client_process_socket(void *arg)
1725 }
1726
1727 /**
1728 + * cui_handle_timeout - Handle the timeout.
1729 + */
1730 +
1731 +static void cui_handle_timeout(struct ui_timer *timer)
1732 +{
1733 + struct cui *cui = cui_from_timer(timer);
1734 + struct pmenu_item *i = pmenu_find_selected(cui->main);
1735 +
1736 +#if defined(DEBUG)
1737 + {
1738 + struct cui_opt_data *cod = cod_from_item(i);
1739 + assert(cod && (cod->opt_hash == cui->default_item));
1740 + }
1741 +#endif
1742 + i->on_execute(i);
1743 +}
1744 +
1745 +/**
1746 * cui_handle_resize - Handle the term resize.
1747 */
1748
1749 @@ -243,6 +320,46 @@ static void cui_handle_resize(struct cui *cui)
1750 }
1751
1752 /**
1753 + * cui_on_open - Open new item callback.
1754 + */
1755 +
1756 +void cui_on_open(struct pmenu *menu)
1757 +{
1758 + unsigned int insert_pt;
1759 + struct pmenu_item *i;
1760 + struct cui_opt_data *cod;
1761 +
1762 + menu->scr.unpost(&menu->scr);
1763 +
1764 + /* This disconnects items array from menu. */
1765 +
1766 + set_menu_items(menu->ncm, NULL);
1767 +
1768 + /* Insert new items at insert_pt. */
1769 +
1770 + insert_pt = pmenu_grow(menu, 1);
1771 + i = pmenu_item_alloc(menu);
1772 +
1773 + i->on_edit = cui_ked_run;
1774 + i->on_execute = cui_run_kexec;
1775 + i->data = cod = talloc_zero(i, struct cui_opt_data);
1776 +
1777 + cod->name = talloc_asprintf(i, "User item %u:", insert_pt);
1778 + cod->kd = talloc_zero(i, struct pb_kexec_data);
1779 +
1780 + pmenu_item_setup(menu, i, insert_pt, talloc_strdup(i, cod->name));
1781 +
1782 + /* Re-attach the items array. */
1783 +
1784 + set_menu_items(menu->ncm, menu->items);
1785 +
1786 + menu->scr.post(&menu->scr);
1787 + set_current_item(menu->ncm, i->nci);
1788 +
1789 + i->on_edit(i);
1790 +}
1791 +
1792 +/**
1793 * cui_device_add - Client device_add callback.
1794 *
1795 * Creates menu_items for all the device boot_options and inserts those
1796 @@ -284,23 +401,11 @@ static int cui_device_add(struct device *dev, void *arg)
1797 struct pmenu_item *i;
1798 struct cui_opt_data *cod;
1799 char *name;
1800 - char *description;
1801
1802 /* Save the item in opt->ui_info for cui_device_remove() */
1803
1804 opt->ui_info = i = pmenu_item_alloc(cui->main);
1805
1806 - name = talloc_asprintf(i, "%s: %s", opt->name,
1807 - opt->description);
1808 -
1809 - description = talloc_asprintf(i,
1810 - " kexec: image='%s' initrd='%s' args='%s'",
1811 - opt->boot_image_file,
1812 - opt->initrd_file,
1813 - opt->boot_args);
1814 -
1815 - pmenu_item_setup(cui->main, i, insert_pt, name, description);
1816 -
1817 i->on_edit = cui_ked_run;
1818 i->on_execute = cui_run_kexec;
1819 i->data = cod = talloc(i, struct cui_opt_data);
1820 @@ -308,23 +413,29 @@ static int cui_device_add(struct device *dev, void *arg)
1821 cod->dev = dev;
1822 cod->opt = opt;
1823 cod->opt_hash = pb_opt_hash(dev, opt);
1824 + cod->name = opt->name;
1825 cod->kd = talloc(i, struct pb_kexec_data);
1826
1827 cod->kd->image = talloc_strdup(cod->kd, opt->boot_image_file);
1828 cod->kd->initrd = talloc_strdup(cod->kd, opt->initrd_file);
1829 cod->kd->args = talloc_strdup(cod->kd, opt->boot_args);
1830
1831 - insert_pt++;
1832 -
1833 - /* If this is the default_item select it. */
1834 + name = cui_make_item_name(i, cod);
1835 + pmenu_item_setup(cui->main, i, insert_pt, name);
1836
1837 - if (cod->opt_hash == cui->default_item)
1838 - selected = i->nci;
1839 + insert_pt++;
1840
1841 - pb_log("%s: adding opt '%s'\n", __func__, cod->opt->name);
1842 + pb_log("%s: adding opt '%s'\n", __func__, cod->name);
1843 pb_log(" image '%s'\n", cod->kd->image);
1844 pb_log(" initrd '%s'\n", cod->kd->initrd);
1845 pb_log(" args '%s'\n", cod->kd->args);
1846 +
1847 + /* If this is the default_item select it and start timer. */
1848 +
1849 + if (cod->opt_hash == cui->default_item) {
1850 + selected = i->nci;
1851 + ui_timer_kick(&cui->timer);
1852 + }
1853 }
1854
1855 /* Re-attach the items array. */
1856 @@ -340,6 +451,9 @@ static int cui_device_add(struct device *dev, void *arg)
1857 item_count(cui->main->ncm) + 1);
1858 }
1859
1860 + /* FIXME: need to make item visible somehow */
1861 + menu_driver(cui->main->ncm, REQ_SCR_UPAGE);
1862 + menu_driver(cui->main->ncm, REQ_SCR_DPAGE);
1863 set_current_item(cui->main->ncm, selected);
1864
1865 if (cui->current == &cui->main->scr)
1866 @@ -375,9 +489,15 @@ static void cui_device_remove(struct device *dev, void *arg)
1867
1868 list_for_each_entry(&dev->boot_options, opt, list) {
1869 struct pmenu_item *i = pmenu_item_from_arg(opt->ui_info);
1870 + struct cui_opt_data *cod = cod_from_item(i);
1871
1872 - assert(pb_protocol_device_cmp(dev, cod_from_item(i)->dev));
1873 + assert(pb_protocol_device_cmp(dev, cod->dev));
1874 pmenu_remove(cui->main, i);
1875 +
1876 + /* If this is the default_item disable timer. */
1877 +
1878 + if (cod->opt_hash == cui->default_item)
1879 + ui_timer_disable(&cui->timer);
1880 }
1881
1882 /* Re-attach the items array. */
1883 @@ -397,10 +517,6 @@ static void cui_device_remove(struct device *dev, void *arg)
1884 cui->current->post(cui->current);
1885 }
1886
1887 -/**
1888 - * cui_client_process_socket - Process a socket event from the discover server.
1889 - */
1890 -
1891 static struct discover_client_ops cui_client_ops = {
1892 .device_add = cui_device_add,
1893 .device_remove = cui_device_remove,
1894 @@ -417,7 +533,8 @@ static struct discover_client_ops cui_client_ops = {
1895 */
1896
1897 struct cui *cui_init(void* platform_info,
1898 - int (*on_kexec)(struct cui *, struct cui_opt_data *))
1899 + int (*on_kexec)(struct cui *, struct cui_opt_data *),
1900 + int (*js_map)(const struct js_event *e))
1901 {
1902 struct cui *cui;
1903 struct discover_client *client;
1904 @@ -434,6 +551,7 @@ struct cui *cui_init(void* platform_info,
1905 cui->c_sig = pb_cui_sig;
1906 cui->platform_info = platform_info;
1907 cui->on_kexec = on_kexec;
1908 + cui->timer.handle_timeout = cui_handle_timeout;
1909
1910 /* Loop here for scripts that just started the server. */
1911
1912 @@ -462,6 +580,15 @@ struct cui *cui_init(void* platform_info,
1913
1914 waiter_register(STDIN_FILENO, WAIT_IN, cui_process_key, cui);
1915
1916 + if (js_map) {
1917 +
1918 + cui->pjs = pjs_init(cui, js_map);
1919 +
1920 + if (cui->pjs)
1921 + waiter_register(pjs_get_fd(cui->pjs), WAIT_IN,
1922 + cui_process_js, cui);
1923 + }
1924 +
1925 return cui;
1926
1927 fail_client_init:
1928 @@ -501,6 +628,8 @@ int cui_run(struct cui *cui, struct pmenu *main, unsigned int default_item)
1929 if (cui->abort)
1930 break;
1931
1932 + ui_timer_process_sig(&cui->timer);
1933 +
1934 while (cui->resize) {
1935 cui->resize = 0;
1936 cui_handle_resize(cui);
1937 diff --git a/ui/ncurses/nc-cui.h b/ui/ncurses/nc-cui.h
1938 index 668776e..94fef6b 100644
1939 --- a/ui/ncurses/nc-cui.h
1940 +++ b/ui/ncurses/nc-cui.h
1941 @@ -21,15 +21,19 @@
1942
1943 #include <signal.h>
1944
1945 +#include "ui/common/joystick.h"
1946 +#include "ui/common/timer.h"
1947 #include "nc-menu.h"
1948 #include "nc-ked.h"
1949
1950 -
1951 struct cui_opt_data {
1952 + const char *name;
1953 + struct pb_kexec_data *kd;
1954 +
1955 + /* optional data */
1956 const struct device *dev;
1957 const struct boot_option *opt;
1958 uint32_t opt_hash;
1959 - struct pb_kexec_data *kd;
1960 };
1961
1962 /**
1963 @@ -49,13 +53,16 @@ struct cui {
1964 sig_atomic_t resize;
1965 struct nc_scr *current;
1966 struct pmenu *main;
1967 + struct ui_timer timer;
1968 + struct pjs *pjs;
1969 void *platform_info;
1970 unsigned int default_item;
1971 int (*on_kexec)(struct cui *cui, struct cui_opt_data *cod);
1972 };
1973
1974 struct cui *cui_init(void* platform_info,
1975 - int (*on_kexec)(struct cui *, struct cui_opt_data *));
1976 + int (*on_kexec)(struct cui *, struct cui_opt_data *),
1977 + int (*js_map)(const struct js_event *e));
1978 struct nc_scr *cui_set_current(struct cui *cui, struct nc_scr *scr);
1979 int cui_run(struct cui *cui, struct pmenu *main, unsigned int default_item);
1980 int cui_ked_run(struct pmenu_item *item);
1981 @@ -65,6 +72,7 @@ int cui_ked_run(struct pmenu_item *item);
1982 void cui_abort(struct cui *cui);
1983 void cui_resize(struct cui *cui);
1984 void cui_on_exit(struct pmenu *menu);
1985 +void cui_on_open(struct pmenu *menu);
1986 int cui_run_cmd(struct pmenu_item *item);
1987
1988 static inline struct cui *cui_from_arg(void *arg)
1989 @@ -85,4 +93,15 @@ static inline struct cui *cui_from_item(struct pmenu_item *item)
1990 return cui_from_pmenu(item->pmenu);
1991 }
1992
1993 +static inline struct cui *cui_from_timer(struct ui_timer *timer)
1994 +{
1995 + struct cui *cui;
1996 +
1997 + cui = (struct cui *)((char *)timer
1998 + - (size_t)&((struct cui *)0)->timer);
1999 + assert(cui->c_sig == pb_cui_sig);
2000 +
2001 + return cui;
2002 +}
2003 +
2004 #endif
2005 diff --git a/ui/ncurses/nc-ked.c b/ui/ncurses/nc-ked.c
2006 index 3bdbd6c..806d389 100644
2007 --- a/ui/ncurses/nc-ked.c
2008 +++ b/ui/ncurses/nc-ked.c
2009 @@ -48,12 +48,15 @@ static struct ked *ked_from_arg(void *arg)
2010 * @req: An ncurses request or char to send to form_driver().
2011 */
2012
2013 -static void ked_move_cursor(struct ked *ked, int req)
2014 +static int ked_move_cursor(struct ked *ked, int req)
2015 {
2016 + int result;
2017 +
2018 wchgat(ked->scr.sub_ncw, 1, ked_attr_field_selected, 0, 0);
2019 - form_driver(ked->ncf, req);
2020 + result = form_driver(ked->ncf, req);
2021 wchgat(ked->scr.sub_ncw, 1, ked->attr_cursor, 0, 0);
2022 wrefresh(ked->scr.main_ncw);
2023 + return result;
2024 }
2025
2026 /**
2027 @@ -93,12 +96,15 @@ static void ked_insert_mode_tog(struct ked *ked)
2028 * @req: An ncurses request to send to form_driver().
2029 */
2030
2031 -static void ked_move_field(struct ked *ked, int req)
2032 +static int ked_move_field(struct ked *ked, int req)
2033 {
2034 + int result;
2035 +
2036 set_field_back(current_field(ked->ncf), ked_attr_field_normal);
2037 - form_driver(ked->ncf, req);
2038 + result = form_driver(ked->ncf, req);
2039 set_field_back(current_field(ked->ncf), ked_attr_field_selected);
2040 ked_move_cursor(ked, REQ_END_FIELD);
2041 + return result;
2042 }
2043
2044 static int ked_post(struct nc_scr *scr)
2045 @@ -143,9 +149,10 @@ static char *ked_chomp(char *s)
2046 for (; s < s_end; s++)
2047 if (*s != ' ' && *s != '\t')
2048 break;
2049 - start = s;
2050
2051 - for (++s; s < s_end; s++)
2052 + start = end = s;
2053 +
2054 + for (; s < s_end; s++)
2055 if (*s != ' ' && *s != '\t')
2056 end = s;
2057 *(end + 1) = 0;
2058 @@ -183,41 +190,33 @@ static struct pb_kexec_data *ked_prepare_data(struct ked *ked)
2059 static void ked_process_key(struct nc_scr *scr)
2060 {
2061 struct ked *ked = ked_from_scr(scr);
2062 + struct pb_kexec_data *kd;
2063
2064 while (1) {
2065 int c = getch();
2066
2067 + if (c == ERR)
2068 + return;
2069 +
2070 + /* DBGS("%d (%o)\n", c, c); */
2071 +
2072 switch (c) {
2073 default:
2074 ked_move_cursor(ked, c);
2075 - break;
2076 - case ERR:
2077 - return;
2078 + break;
2079
2080 /* hot keys */
2081 - case 2: { /* CTRL-B */
2082 - struct pb_kexec_data *kd;
2083 -
2084 - form_driver(ked->ncf, REQ_VALIDATION);
2085 - kd = ked_prepare_data(ked);
2086 - ked->on_exit(ked, ked_boot, kd);
2087 - nc_flush_keys();
2088 - return;
2089 - }
2090 case 27: /* ESC */
2091 ked->on_exit(ked, ked_cancel, NULL);
2092 nc_flush_keys();
2093 return;
2094 case '\n':
2095 - case '\r': {
2096 - struct pb_kexec_data *kd;
2097 -
2098 + case '\r':
2099 form_driver(ked->ncf, REQ_VALIDATION);
2100 kd = ked_prepare_data(ked);
2101 ked->on_exit(ked, ked_update, kd);
2102 nc_flush_keys();
2103 return;
2104 - }
2105
2106 /* insert mode */
2107 case KEY_IC:
2108 @@ -252,8 +251,8 @@ static void ked_process_key(struct nc_scr *scr)
2109 ked_move_cursor(ked, REQ_RIGHT_CHAR);
2110 break;
2111 case KEY_BACKSPACE:
2112 - ked_move_cursor(ked, REQ_LEFT_CHAR);
2113 - ked_move_cursor(ked, REQ_DEL_CHAR);
2114 + if (ked_move_cursor(ked, REQ_LEFT_CHAR) == E_OK)
2115 + ked_move_cursor(ked, REQ_DEL_CHAR);
2116 break;
2117 case KEY_DC:
2118 ked_move_cursor(ked, REQ_DEL_CHAR);
2119 @@ -325,7 +324,7 @@ struct ked *ked_init(void *ui_ctx, const struct pb_kexec_data *kd,
2120
2121 ked->scr.frame.title = talloc_strdup(ked, "Petitboot Option Editor");
2122 ked->scr.frame.help = talloc_strdup(ked,
2123 - "ESC=cancel, Enter=accept, Ctrl-b=boot");
2124 + "ESC=cancel, Enter=accept");
2125
2126 ked->on_exit = on_exit;
2127
2128 diff --git a/ui/ncurses/nc-ked.h b/ui/ncurses/nc-ked.h
2129 index 36ed4f1..62fddd6 100644
2130 --- a/ui/ncurses/nc-ked.h
2131 +++ b/ui/ncurses/nc-ked.h
2132 @@ -20,6 +20,7 @@
2133 #define _PB_NC_KED_H
2134
2135 #include <assert.h>
2136 +#include <linux/input.h> /* This must be included before ncurses.h */
2137 #include <form.h>
2138
2139 #include "pb-protocol/pb-protocol.h"
2140 @@ -40,13 +41,11 @@ enum ked_attr_cursor {
2141 * enum ked_result - Result code for ked:on_exit().
2142 * @ked_cancel: The user canceled the operation.
2143 * @ked_update: The args were updated.
2144 - * @ked_boot: The user requested a boot of this item.
2145 */
2146
2147 enum ked_result {
2148 ked_cancel,
2149 ked_update,
2150 - ked_boot,
2151 };
2152
2153 /**
2154 diff --git a/ui/ncurses/nc-menu.c b/ui/ncurses/nc-menu.c
2155 index 0a76b11..f96eb82 100644
2156 --- a/ui/ncurses/nc-menu.c
2157 +++ b/ui/ncurses/nc-menu.c
2158 @@ -91,17 +91,17 @@ struct pmenu_item *pmenu_item_alloc(struct pmenu *menu)
2159 }
2160
2161 struct pmenu_item *pmenu_item_setup(struct pmenu *menu, struct pmenu_item *i,
2162 - unsigned int index, const char *name,
2163 - const char *description)
2164 + unsigned int index, const char *name)
2165 {
2166 assert(i);
2167 + assert(name);
2168
2169 if (!i)
2170 return NULL;
2171
2172 i->i_sig = pb_item_sig;
2173 i->pmenu = menu;
2174 - i->nci = new_item(name, description);
2175 + i->nci = new_item(name, NULL);
2176
2177 if (!i->nci) {
2178 talloc_free(i);
2179 @@ -115,6 +115,67 @@ struct pmenu_item *pmenu_item_setup(struct pmenu *menu, struct pmenu_item *i,
2180 return i;
2181 }
2182
2183 +static int pmenu_item_get_index(const struct pmenu_item *item)
2184 +{
2185 + unsigned int i;
2186 +
2187 + for (i = 0; i < item->pmenu->item_count; i++)
2188 + if (item->pmenu->items[i] == item->nci)
2189 + return i;
2190 +
2191 + pb_log("%s: not found: %p %s\n", __func__, item,
2192 + (item ? item->nci->name.str : "(null)"));
2193 + return -1;
2194 +}
2195 +
2196 +/**
2197 + * pmenu_item_replace - Replace the menu item with a new one.
2198 + *
2199 + * Use this routine to change a menu item's text.
2200 + */
2201 +
2202 +int pmenu_item_replace(struct pmenu_item *i, const char *name)
2203 +{
2204 + struct pmenu *menu;
2205 + ITEM *nci;
2206 + int index;
2207 +
2208 + assert(name);
2209 + assert(i->nci);
2210 +
2211 + menu = i->pmenu;
2212 + index = pmenu_item_get_index(i);
2213 +
2214 + if (index < 0) {
2215 + assert(0 && "get_index failed");
2216 + return -1;
2217 + }
2218 +
2219 + nci = new_item(name, NULL);
2220 +
2221 + if (!nci) {
2222 + assert(0 && "new_item failed");
2223 + return -1;
2224 + }
2225 +
2226 + set_item_userptr(nci, i);
2227 +
2228 + menu->scr.unpost(&menu->scr);
2229 + set_menu_items(menu->ncm, NULL);
2230 +
2231 + // FIXME: need to assure item name is a talloc string.
2232 + /* talloc_free((char *)item_name(i->nci)); */
2233 +
2234 + free_item(i->nci);
2235 + menu->items[index] = nci;
2236 + i->nci = nci;
2237 +
2238 + set_menu_items(menu->ncm, menu->items);
2239 + menu->scr.post(&menu->scr);
2240 +
2241 + return 0;
2242 +}
2243 +
2244 /**
2245 * pmenu_move_cursor - Move the cursor.
2246 * @req: An ncurses request or char to send to menu_driver().
2247 @@ -143,7 +204,7 @@ static void pmenu_process_key(struct nc_scr *scr)
2248 if (c == ERR)
2249 return;
2250
2251 - /* DBGS("%d (%o)\n", c, c); */
2252 + if (1) DBGS("%d (%o)\n", c, c);
2253
2254 if (menu->hot_key)
2255 c = menu->hot_key(menu, item, c);
2256 @@ -174,13 +235,16 @@ static void pmenu_process_key(struct nc_scr *scr)
2257 case '\t':
2258 pmenu_move_cursor(menu, REQ_DOWN_ITEM);
2259 break;
2260 -
2261 case KEY_LEFT:
2262 - case 'E':
2263 case 'e':
2264 if (item->on_edit)
2265 item->on_edit(item);
2266 break;
2267 + case 'o':
2268 + DBGS("on_open: %p\n", menu->on_open);
2269 + if (menu->on_open)
2270 + menu->on_open(menu);
2271 + break;
2272 case '\n':
2273 case '\r':
2274 if (item->on_execute)
2275 @@ -228,19 +292,6 @@ unsigned int pmenu_grow(struct pmenu *menu, unsigned int count)
2276 return tmp;
2277 }
2278
2279 -static int pmenu_item_get_index(const struct pmenu_item *item)
2280 -{
2281 - unsigned int i;
2282 -
2283 - for (i = 0; i < item->pmenu->item_count; i++)
2284 - if (item->pmenu->items[i] == item->nci)
2285 - return i;
2286 -
2287 - pb_log("%s: not found: %p %s\n", __func__, item,
2288 - (item ? item->nci->name.str : "(null)"));
2289 - return -1;
2290 -}
2291 -
2292 /**
2293 * pmenu_remove - Remove an item from the item array.
2294 *
2295 @@ -262,6 +313,9 @@ int pmenu_remove(struct pmenu *menu, struct pmenu_item *item)
2296 if (index < 0)
2297 return -1;
2298
2299 + free_item(item->nci);
2300 + talloc_free(item);
2301 +
2302 /* Note that items array has a null terminator. */
2303
2304 menu->insert_pt--;
2305 @@ -349,7 +403,7 @@ void pmenu_delete(struct pmenu *menu)
2306 menu->scr.sig = pb_removed_sig;
2307
2308 for (i = item_count(menu->ncm); i; i--)
2309 - free_item(menu->items[i]);
2310 + free_item(menu->items[i - 1]);
2311
2312 free_menu(menu->ncm);
2313 delwin(menu->scr.sub_ncw);
2314 diff --git a/ui/ncurses/nc-menu.h b/ui/ncurses/nc-menu.h
2315 index b487df9..4abec6f 100644
2316 --- a/ui/ncurses/nc-menu.h
2317 +++ b/ui/ncurses/nc-menu.h
2318 @@ -20,6 +20,7 @@
2319 #define _PB_NC_MENU_H
2320
2321 #include <assert.h>
2322 +#include <linux/input.h> /* This must be included before ncurses.h */
2323 #include <menu.h>
2324
2325 #include "log/log.h"
2326 @@ -45,7 +46,8 @@ struct pmenu_item {
2327
2328 struct pmenu_item *pmenu_item_alloc(struct pmenu *menu);
2329 struct pmenu_item *pmenu_item_setup(struct pmenu *menu, struct pmenu_item *i,
2330 - unsigned int index, const char *name, const char *description);
2331 + unsigned int index, const char *name);
2332 +int pmenu_item_replace(struct pmenu_item *i, const char *name);
2333 void pmenu_item_delete(struct pmenu_item *item);
2334
2335 static inline struct pmenu_item *pmenu_item_from_arg(void *arg)
2336 @@ -57,10 +59,9 @@ static inline struct pmenu_item *pmenu_item_from_arg(void *arg)
2337 }
2338
2339 static inline struct pmenu_item *pmenu_item_init(struct pmenu *menu,
2340 - unsigned int index, const char *name, const char *description)
2341 + unsigned int index, const char *name)
2342 {
2343 - return pmenu_item_setup(menu, pmenu_item_alloc(menu), index, name,
2344 - description);
2345 + return pmenu_item_setup(menu, pmenu_item_alloc(menu), index, name);
2346 }
2347
2348 /**
2349 @@ -77,6 +78,7 @@ struct pmenu {
2350 unsigned int insert_pt;
2351 int (*hot_key)(struct pmenu *menu, struct pmenu_item *item, int c);
2352 void (*on_exit)(struct pmenu *menu);
2353 + void (*on_open)(struct pmenu *menu);
2354 };
2355
2356 struct pmenu *pmenu_init(void *ui_ctx, unsigned int item_count,
2357 diff --git a/ui/ncurses/nc-scr.h b/ui/ncurses/nc-scr.h
2358 index c08fcd4..2374c20 100644
2359 --- a/ui/ncurses/nc-scr.h
2360 +++ b/ui/ncurses/nc-scr.h
2361 @@ -19,6 +19,7 @@
2362 #if !defined(_PB_NC_SCR_H)
2363 #define _PB_NC_SCR_H
2364
2365 +#include <linux/input.h> /* This must be included before ncurses.h */
2366 #include <ncurses.h>
2367
2368 #define DBG(fmt, args...) pb_log("DBG: " fmt, ## args)
2369 diff --git a/ui/ncurses/pb-cui.c b/ui/ncurses/pb-cui.c
2370 new file mode 100644
2371 index 0000000..972490a
2372 --- /dev/null
2373 +++ b/ui/ncurses/pb-cui.c
2374 @@ -0,0 +1,289 @@
2375 +/*
2376 + * Petitboot generic ncurses bootloader UI
2377 + *
2378 + * Copyright (C) 2009 Sony Computer Entertainment Inc.
2379 + * Copyright 2009 Sony Corp.
2380 + *
2381 + * This program is free software; you can redistribute it and/or modify
2382 + * it under the terms of the GNU General Public License as published by
2383 + * the Free Software Foundation; version 2 of the License.
2384 + *
2385 + * This program is distributed in the hope that it will be useful,
2386 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
2387 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2388 + * GNU General Public License for more details.
2389 + *
2390 + * You should have received a copy of the GNU General Public License
2391 + * along with this program; if not, write to the Free Software
2392 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
2393 + */
2394 +
2395 +#if defined(HAVE_CONFIG_H)
2396 +#include "config.h"
2397 +#endif
2398 +
2399 +#define _GNU_SOURCE
2400 +#include <errno.h>
2401 +#include <getopt.h>
2402 +#include <signal.h>
2403 +#include <stdlib.h>
2404 +#include <string.h>
2405 +#include <sys/time.h>
2406 +
2407 +#include "log/log.h"
2408 +#include "talloc/talloc.h"
2409 +#include "waiter/waiter.h"
2410 +#include "ui/common/discover-client.h"
2411 +#include "nc-cui.h"
2412 +
2413 +static void print_version(void)
2414 +{
2415 + printf("pb-cui (" PACKAGE_NAME ") " PACKAGE_VERSION "\n");
2416 +}
2417 +
2418 +static void print_usage(void)
2419 +{
2420 + print_version();
2421 + printf(
2422 +"Usage: pb-cui [-h, --help] [-l, --log log-file] [-V, --version]\n");
2423 +}
2424 +
2425 +/**
2426 + * enum opt_value - Tri-state options variables.
2427 + */
2428 +
2429 +enum opt_value {opt_undef = 0, opt_yes, opt_no};
2430 +
2431 +/**
2432 + * struct opts - Values from command line options.
2433 + */
2434 +
2435 +struct opts {
2436 + enum opt_value show_help;
2437 + const char *log_file;
2438 + enum opt_value show_version;
2439 +};
2440 +
2441 +/**
2442 + * opts_parse - Parse the command line options.
2443 + */
2444 +
2445 +static int opts_parse(struct opts *opts, int argc, char *argv[])
2446 +{
2447 + static const struct option long_options[] = {
2448 + {"help", no_argument, NULL, 'h'},
2449 + {"log", required_argument, NULL, 'l'},
2450 + {"version", no_argument, NULL, 'V'},
2451 + { NULL, 0, NULL, 0},
2452 + };
2453 + static const char short_options[] = "hl:V";
2454 + static const struct opts default_values = {
2455 + .log_file = "pb-cui.log",
2456 + };
2457 +
2458 + *opts = default_values;
2459 +
2460 + while (1) {
2461 + int c = getopt_long(argc, argv, short_options, long_options,
2462 + NULL);
2463 +
2464 + if (c == EOF)
2465 + break;
2466 +
2467 + switch (c) {
2468 + case 'h':
2469 + opts->show_help = opt_yes;
2470 + break;
2471 + case 'l':
2472 + opts->log_file = optarg;
2473 + break;
2474 + case 'V':
2475 + opts->show_version = opt_yes;
2476 + break;
2477 + default:
2478 + opts->show_help = opt_yes;
2479 + return -1;
2480 + }
2481 + }
2482 +
2483 + return 0;
2484 +}
2485 +
2486 +/**
2487 + * struct pb_cui - Main cui program instance.
2488 + * @mm: Main menu.
2489 + * @svm: Set video mode menu.
2490 + */
2491 +
2492 +struct pb_cui {
2493 + struct pmenu *mm;
2494 + struct cui *cui;
2495 +};
2496 +
2497 +static struct pb_cui *pb_from_cui(struct cui *cui)
2498 +{
2499 + struct pb_cui *pb;
2500 +
2501 + assert(cui->c_sig == pb_cui_sig);
2502 + pb = cui->platform_info;
2503 + assert(pb->cui->c_sig == pb_cui_sig);
2504 + return pb;
2505 +}
2506 +
2507 +/**
2508 + * pb_kexec_cb - The kexec callback.
2509 + */
2510 +
2511 +static int pb_kexec_cb(struct cui *cui, struct cui_opt_data *cod)
2512 +{
2513 + struct pb_cui *pb = pb_from_cui(cui);
2514 +
2515 + pb_log("%s: %s\n", __func__, cod->name);
2516 +
2517 + assert(pb->cui->current == &pb->cui->main->scr);
2518 +
2519 + return pb_run_kexec(cod->kd);
2520 +}
2521 +
2522 +/**
2523 + * pb_mm_init - Setup the main menu instance.
2524 + */
2525 +
2526 +static struct pmenu *pb_mm_init(struct pb_cui *pb_cui)
2527 +{
2528 + int result;
2529 + struct pmenu *m;
2530 + struct pmenu_item *i;
2531 +
2532 + m = pmenu_init(pb_cui->cui, 1, cui_on_exit);
2533 +
2534 + if (!m) {
2535 + pb_log("%s: failed\n", __func__);
2536 + return NULL;
2537 + }
2538 +
2539 + m->on_open = cui_on_open;
2540 +
2541 + m->scr.frame.title = talloc_strdup(m, "Petitboot");
2542 + m->scr.frame.help = talloc_strdup(m,
2543 + "ESC=exit, Enter=accept, e=edit, o=open");
2544 + m->scr.frame.status = talloc_strdup(m, "Welcome to Petitboot");
2545 +
2546 + i = pmenu_item_init(m, 0, "Exit to Shell");
2547 + i->on_execute = pmenu_exit_cb;
2548 +
2549 + result = pmenu_setup(m);
2550 +
2551 + if (result) {
2552 + pb_log("%s:%d: pmenu_setup failed: %s\n", __func__, __LINE__,
2553 + strerror(errno));
2554 + goto fail_setup;
2555 + }
2556 +
2557 + menu_opts_off(m->ncm, O_SHOWDESC);
2558 + set_menu_mark(m->ncm, " *");
2559 + set_current_item(m->ncm, i->nci);
2560 +
2561 + return m;
2562 +
2563 +fail_setup:
2564 + talloc_free(m);
2565 + return NULL;
2566 +}
2567 +
2568 +static struct pb_cui pb;
2569 +
2570 +static void sig_handler(int signum)
2571 +{
2572 + DBGS("%d\n", signum);
2573 +
2574 + switch (signum) {
2575 + case SIGALRM:
2576 + if (pb.cui)
2577 + ui_timer_sigalrm(&pb.cui->timer);
2578 + break;
2579 + case SIGWINCH:
2580 + if (pb.cui)
2581 + cui_resize(pb.cui);
2582 + break;
2583 + default:
2584 + assert(0 && "unknown sig");
2585 + /* fall through */
2586 + case SIGINT:
2587 + case SIGHUP:
2588 + case SIGTERM:
2589 + if (pb.cui)
2590 + cui_abort(pb.cui);
2591 + break;
2592 + }
2593 +}
2594 +
2595 +/**
2596 + * main - cui bootloader main routine.
2597 + */
2598 +
2599 +int main(int argc, char *argv[])
2600 +{
2601 + static struct sigaction sa;
2602 + static struct opts opts;
2603 + int result;
2604 + int cui_result;
2605 + FILE *log;
2606 +
2607 + result = opts_parse(&opts, argc, argv);
2608 +
2609 + if (result) {
2610 + print_usage();
2611 + return EXIT_FAILURE;
2612 + }
2613 +
2614 + if (opts.show_help == opt_yes) {
2615 + print_usage();
2616 + return EXIT_SUCCESS;
2617 + }
2618 +
2619 + if (opts.show_version == opt_yes) {
2620 + print_version();
2621 + return EXIT_SUCCESS;
2622 + }
2623 +
2624 + log = fopen(opts.log_file, "a");
2625 + assert(log);
2626 + pb_log_set_stream(log);
2627 +
2628 +#if defined(DEBUG)
2629 + pb_log_always_flush(1);
2630 +#endif
2631 +
2632 + pb_log("--- pb-cui ---\n");
2633 +
2634 + sa.sa_handler = sig_handler;
2635 + result = sigaction(SIGALRM, &sa, NULL);
2636 + result += sigaction(SIGHUP, &sa, NULL);
2637 + result += sigaction(SIGINT, &sa, NULL);
2638 + result += sigaction(SIGTERM, &sa, NULL);
2639 + result += sigaction(SIGWINCH, &sa, NULL);
2640 +
2641 + if (result) {
2642 + pb_log("%s sigaction failed.\n", __func__);
2643 + return EXIT_FAILURE;
2644 + }
2645 +
2646 + pb.cui = cui_init(&pb, pb_kexec_cb, NULL);
2647 +
2648 + if (!pb.cui)
2649 + return EXIT_FAILURE;
2650 +
2651 + pb.mm = pb_mm_init(&pb);
2652 + ui_timer_disable(&pb.cui->timer);
2653 +
2654 + cui_result = cui_run(pb.cui, pb.mm, 0);
2655 +
2656 + pmenu_delete(pb.mm);
2657 +
2658 + talloc_free(pb.cui);
2659 +
2660 + pb_log("--- end ---\n");
2661 +
2662 + return cui_result ? EXIT_FAILURE : EXIT_SUCCESS;
2663 +}
2664 diff --git a/ui/ncurses/ps3-cui.c b/ui/ncurses/ps3-cui.c
2665 index f166c88..d9a66fa 100644
2666 --- a/ui/ncurses/ps3-cui.c
2667 +++ b/ui/ncurses/ps3-cui.c
2668 @@ -21,9 +21,7 @@
2669 /*
2670 * TODO
2671 * removable media event
2672 - * resize after video mode change
2673 * ncurses mouse support
2674 - * timeout
2675 */
2676
2677 #if defined(HAVE_CONFIG_H)
2678 @@ -36,6 +34,7 @@
2679 #include <signal.h>
2680 #include <stdlib.h>
2681 #include <string.h>
2682 +#include <sys/time.h>
2683
2684 #include "log/log.h"
2685 #include "talloc/talloc.h"
2686 @@ -53,7 +52,8 @@ static void print_usage(void)
2687 {
2688 print_version();
2689 printf(
2690 -"Usage: pb-cui [-h, --help] [-l, --log log-file] [-V, --version]\n");
2691 +"Usage: pb-cui [-h, --help] [-l, --log log-file] [-r, --reset-defaults]\n"
2692 +" [-t, --timeout] [-V, --version]\n");
2693 }
2694
2695 /**
2696 @@ -69,6 +69,8 @@ enum opt_value {opt_undef = 0, opt_yes, opt_no};
2697 struct opts {
2698 enum opt_value show_help;
2699 const char *log_file;
2700 + enum opt_value reset_defaults;
2701 + enum opt_value use_timeout;
2702 enum opt_value show_version;
2703 };
2704
2705 @@ -79,12 +81,14 @@ struct opts {
2706 static int opts_parse(struct opts *opts, int argc, char *argv[])
2707 {
2708 static const struct option long_options[] = {
2709 - {"help", no_argument, NULL, 'h'},
2710 - {"log", required_argument, NULL, 'l'},
2711 - {"version", no_argument, NULL, 'V'},
2712 - { NULL, 0, NULL, 0},
2713 + {"help", no_argument, NULL, 'h'},
2714 + {"log", required_argument, NULL, 'l'},
2715 + {"reset-defaults", no_argument, NULL, 'r'},
2716 + {"timeout", no_argument, NULL, 't'},
2717 + {"version", no_argument, NULL, 'V'},
2718 + { NULL, 0, NULL, 0},
2719 };
2720 - static const char short_options[] = "hl:V";
2721 + static const char short_options[] = "hl:trV";
2722 static const struct opts default_values = {
2723 .log_file = "pb-cui.log",
2724 };
2725 @@ -105,6 +109,12 @@ static int opts_parse(struct opts *opts, int argc, char *argv[])
2726 case 'l':
2727 opts->log_file = optarg;
2728 break;
2729 + case 't':
2730 + opts->use_timeout = opt_yes;
2731 + break;
2732 + case 'r':
2733 + opts->reset_defaults = opt_yes;
2734 + break;
2735 case 'V':
2736 opts->show_version = opt_yes;
2737 break;
2738 @@ -114,7 +124,7 @@ static int opts_parse(struct opts *opts, int argc, char *argv[])
2739 }
2740 }
2741
2742 - return 0;
2743 + return optind != argc;
2744 }
2745
2746 /**
2747 @@ -147,6 +157,83 @@ static struct ps3_cui *ps3_from_item(struct pmenu_item *item)
2748 }
2749
2750 /**
2751 + * ps3_sixaxis_map - Map a Linux joystick event to an ncurses key code.
2752 + *
2753 + */
2754 +
2755 +static int ps3_sixaxis_map(const struct js_event *e)
2756 +{
2757 +#if 0
2758 + static const int axis_map[] = {
2759 + 0, /* 0 Left thumb X */
2760 + 0, /* 1 Left thumb Y */
2761 + 0, /* 2 Right thumb X */
2762 + 0, /* 3 Right thumb Y */
2763 + 0, /* 4 nothing */
2764 + 0, /* 5 nothing */
2765 + 0, /* 6 nothing */
2766 + 0, /* 7 nothing */
2767 + 0, /* 8 Dpad Up */
2768 + 0, /* 9 Dpad Right */
2769 + 0, /* 10 Dpad Down */
2770 + 0, /* 11 Dpad Left */
2771 + 0, /* 12 L2 */
2772 + 0, /* 13 R2 */
2773 + 0, /* 14 L1 */
2774 + 0, /* 15 R1 */
2775 + 0, /* 16 Triangle */
2776 + 0, /* 17 Circle */
2777 + 0, /* 18 Cross */
2778 + 0, /* 19 Square */
2779 + 0, /* 20 nothing */
2780 + 0, /* 21 nothing */
2781 + 0, /* 22 nothing */
2782 + 0, /* 23 nothing */
2783 + 0, /* 24 nothing */
2784 + 0, /* 25 nothing */
2785 + 0, /* 26 nothing */
2786 + 0, /* 27 nothing */
2787 + };
2788 +#endif
2789 + static const int button_map[] = {
2790 + 0, /* 0 Select */
2791 + 0, /* 1 L3 */
2792 + 0, /* 2 R3 */
2793 + 0, /* 3 Start */
2794 + KEY_UP, /* 4 Dpad Up */
2795 + 0, /* 5 Dpad Right */
2796 + KEY_DOWN, /* 6 Dpad Down */
2797 + 0, /* 7 Dpad Left */
2798 + KEY_UP, /* 8 L2 */
2799 + KEY_DOWN, /* 9 R2 */
2800 + KEY_HOME, /* 10 L1 */
2801 + KEY_END, /* 11 R1 */
2802 + 0, /* 12 Triangle */
2803 + 0, /* 13 Circle */
2804 + 13, /* 14 Cross */
2805 + 0, /* 15 Square */
2806 + 0, /* 16 PS Button */
2807 + 0, /* 17 nothing */
2808 + 0, /* 18 nothing */
2809 + };
2810 +
2811 + if (!e->value)
2812 + return 0;
2813 +
2814 + if (e->type == JS_EVENT_BUTTON
2815 + && e->number < sizeof(button_map) / sizeof(button_map[0]))
2816 + return button_map[e->number];
2817 +
2818 +#if 0
2819 + if (e->type == JS_EVENT_AXIS
2820 + && e->number < sizeof(axis_map) / sizeof(axis_map[0]))
2821 + return axis_map[e->number];
2822 +#endif
2823 +
2824 + return 0;
2825 +}
2826 +
2827 +/**
2828 * ps3_set_mode - Set video mode helper.
2829 *
2830 * Runs ps3_set_video_mode().
2831 @@ -183,22 +270,51 @@ static int ps3_svm_cb(struct pmenu_item *item)
2832 * ps3_kexec_cb - The kexec callback.
2833 *
2834 * Writes config data to PS3 flash then calls pb_run_kexec().
2835 + * Adds a video mode arg to the kernel command line if needed.
2836 */
2837
2838 static int ps3_kexec_cb(struct cui *cui, struct cui_opt_data *cod)
2839 {
2840 struct ps3_cui *ps3 = ps3_from_cui(cui);
2841 + int result;
2842 + int altered_args;
2843 + char *orig_args;
2844
2845 - pb_log("%s: %s:%s\n", __func__, cod->dev->name, cod->opt->name);
2846 + pb_log("%s: %s\n", __func__, cod->name);
2847
2848 assert(ps3->cui->current == &ps3->cui->main->scr);
2849
2850 - if (cui->default_item != cod->opt_hash || ps3->dirty_values) {
2851 + /* Save values to flash if needed */
2852 +
2853 + if ((cod->opt_hash && cod->opt_hash != cui->default_item)
2854 + || ps3->dirty_values) {
2855 ps3->values.default_item = cod->opt_hash;
2856 ps3_flash_set_values(&ps3->values);
2857 }
2858
2859 - return pb_run_kexec(cod->kd);
2860 + /* Add a default kernel video mode. */
2861 +
2862 + if (!cod->kd->args) {
2863 + altered_args = 1;
2864 + orig_args = NULL;
2865 + cod->kd->args = talloc_asprintf(NULL, "video=ps3fb:mode:%u",
2866 + (unsigned int)ps3->values.video_mode);
2867 + } else if (!strstr(cod->kd->args, "video=")) {
2868 + altered_args = 1;
2869 + orig_args = cod->kd->args;
2870 + cod->kd->args = talloc_asprintf(NULL, "%s video=ps3fb:mode:%u",
2871 + orig_args, (unsigned int)ps3->values.video_mode);
2872 + } else
2873 + altered_args = 0;
2874 +
2875 + result = pb_run_kexec(cod->kd);
2876 +
2877 + if (altered_args) {
2878 + talloc_free(cod->kd->args);
2879 + cod->kd->args = orig_args;
2880 + }
2881 +
2882 + return result;
2883 }
2884
2885 /**
2886 @@ -283,6 +399,21 @@ static int ps3_hot_key(struct pmenu __attribute__((unused)) *menu,
2887 }
2888
2889 /**
2890 + * ps3_timer_update - Timer callback.
2891 + */
2892 +
2893 +static void ps3_timer_update(struct ui_timer *timer, unsigned int timeout)
2894 +{
2895 + struct ps3_cui *ps3 = ps3_from_cui(cui_from_timer(timer));
2896 +
2897 + //FIXME: make scr:timer.
2898 + // nc_scr_timer_update(&ps3.mm->scr, timeout);
2899 +
2900 + nc_scr_status_printf(&ps3->mm->scr,
2901 + "Welcome to Petitboot (timeout %u sec)", timeout);
2902 +}
2903 +
2904 +/**
2905 * ps3_mm_init - Setup the main menu instance.
2906 */
2907
2908 @@ -291,8 +422,7 @@ static struct pmenu *ps3_mm_init(struct ps3_cui *ps3_cui)
2909 int result;
2910 struct pmenu *m;
2911 struct pmenu_item *i;
2912 - static const char *const bgo[] =
2913 - {"/usr/sbin/ps3-boot-game-os-NOT", NULL};
2914 + static const char *const bgo[] = {"/usr/sbin/ps3-boot-game-os", NULL};
2915
2916 m = pmenu_init(ps3_cui->cui, 3, cui_on_exit);
2917
2918 @@ -302,22 +432,26 @@ static struct pmenu *ps3_mm_init(struct ps3_cui *ps3_cui)
2919 }
2920
2921 m->hot_key = ps3_hot_key;
2922 + m->on_open = cui_on_open;
2923 +
2924 +#if defined(DEBUG)
2925 + m->scr.frame.title = talloc_strdup(m,
2926 + "Petitboot PS3 (" PACKAGE_VERSION ")");
2927 +#else
2928 m->scr.frame.title = talloc_strdup(m, "Petitboot PS3");
2929 +#endif
2930 m->scr.frame.help = talloc_strdup(m,
2931 - "ESC=exit, Enter=accept, E,e=edit");
2932 + "ESC=exit, Enter=accept, e=edit, o=open");
2933 m->scr.frame.status = talloc_strdup(m, "Welcome to Petitboot");
2934
2935 - i = pmenu_item_init(m, 0, "Boot GameOS",
2936 - "Reboot the PS3 into the GameOS");
2937 + i = pmenu_item_init(m, 0, "Boot GameOS");
2938 i->on_execute = cui_run_cmd;
2939 i->data = (void *)bgo;
2940
2941 - i = pmenu_item_init(m, 1, "Set Video Mode",
2942 - "Display a video mode selection menu");
2943 + i = pmenu_item_init(m, 1, "Set Video Mode");
2944 i->on_execute = ps3_mm_to_svm_cb;
2945
2946 - i = pmenu_item_init(m, 2, "Exit to Shell",
2947 - "Exit petitboot and return to a shell prompt");
2948 + i = pmenu_item_init(m, 2, "Exit to Shell");
2949 i->on_execute = pmenu_exit_cb;
2950
2951 result = pmenu_setup(m);
2952 @@ -360,53 +494,51 @@ static struct pmenu *ps3_svm_init(struct ps3_cui *ps3_cui)
2953 m->scr.frame.title = talloc_strdup(m, "Select PS3 Video Mode");
2954 m->scr.frame.help = talloc_strdup(m, "ESC=exit, Enter=accept");
2955
2956 - i = pmenu_item_init(m, 0, "auto detect",
2957 - "Auto detect the best HDMI video mode");
2958 + i = pmenu_item_init(m, 0, "auto detect");
2959 i->on_execute = ps3_svm_cb;
2960 i->data = (void *)0;
2961
2962 - i = pmenu_item_init(m, 1, "480i (576 x 384)", NULL);
2963 + i = pmenu_item_init(m, 1, "480i (576 x 384)");
2964 i->on_execute = ps3_svm_cb;
2965 i->data = (void *)1;
2966
2967 - i = pmenu_item_init(m, 2, "480p (576 x 384)", NULL);
2968 + i = pmenu_item_init(m, 2, "480p (576 x 384)");
2969 i->on_execute = ps3_svm_cb;
2970 i->data = (void *)2;
2971
2972 - i = pmenu_item_init(m, 3, "576i (576 x 460)", NULL);
2973 + i = pmenu_item_init(m, 3, "576i (576 x 460)");
2974 i->on_execute = ps3_svm_cb;
2975 i->data = (void *)6;
2976
2977 - i = pmenu_item_init(m, 4, "576p (576 x 460)", NULL);
2978 + i = pmenu_item_init(m, 4, "576p (576 x 460)");
2979 i->on_execute = ps3_svm_cb;
2980 i->data = (void *)7;
2981
2982 - i = pmenu_item_init(m, 5, "720p (1124 x 644)", NULL);
2983 + i = pmenu_item_init(m, 5, "720p (1124 x 644)");
2984 i->on_execute = ps3_svm_cb;
2985 i->data = (void *)3;
2986
2987 - i = pmenu_item_init(m, 6, "1080i (1688 x 964)", NULL);
2988 + i = pmenu_item_init(m, 6, "1080i (1688 x 964)");
2989 i->on_execute = ps3_svm_cb;
2990 i->data = (void *)4;
2991
2992 - i = pmenu_item_init(m, 7, "1080p (1688 x 964)", NULL);
2993 + i = pmenu_item_init(m, 7, "1080p (1688 x 964)");
2994 i->on_execute = ps3_svm_cb;
2995 i->data = (void *)5;
2996
2997 - i = pmenu_item_init(m, 8, "wxga (1280 x 768)", NULL);
2998 + i = pmenu_item_init(m, 8, "wxga (1280 x 768)");
2999 i->on_execute = ps3_svm_cb;
3000 i->data = (void *)11;
3001
3002 - i = pmenu_item_init(m, 9, "sxga (1280 x 1024)", NULL);
3003 + i = pmenu_item_init(m, 9, "sxga (1280 x 1024)");
3004 i->on_execute = ps3_svm_cb;
3005 i->data = (void *)12;
3006
3007 - i = pmenu_item_init(m, 10, "wuxga (1920 x 1200)", NULL);
3008 + i = pmenu_item_init(m, 10, "wuxga (1920 x 1200)");
3009 i->on_execute = ps3_svm_cb;
3010 i->data = (void *)13;
3011
3012 - i = pmenu_item_init(m, 11, "Return",
3013 - "Return to the main menu");
3014 + i = pmenu_item_init(m, 11, "Return");
3015 i->on_execute = ps3_svm_to_mm_cb;
3016
3017 result = pmenu_setup(m);
3018 @@ -434,6 +566,10 @@ static void sig_handler(int signum)
3019 DBGS("%d\n", signum);
3020
3021 switch (signum) {
3022 + case SIGALRM:
3023 + if (ps3.cui)
3024 + ui_timer_sigalrm(&ps3.cui->timer);
3025 + break;
3026 case SIGWINCH:
3027 if (ps3.cui)
3028 cui_resize(ps3.cui);
3029 @@ -491,8 +627,9 @@ int main(int argc, char *argv[])
3030 pb_log("--- pb-cui ---\n");
3031
3032 sa.sa_handler = sig_handler;
3033 - result = sigaction(SIGINT, &sa, NULL);
3034 + result = sigaction(SIGALRM, &sa, NULL);
3035 result += sigaction(SIGHUP, &sa, NULL);
3036 + result += sigaction(SIGINT, &sa, NULL);
3037 result += sigaction(SIGTERM, &sa, NULL);
3038 result += sigaction(SIGWINCH, &sa, NULL);
3039
3040 @@ -501,7 +638,10 @@ int main(int argc, char *argv[])
3041 return EXIT_FAILURE;
3042 }
3043
3044 - ps3.dirty_values = ps3_flash_get_values(&ps3.values);
3045 + ps3.values = ps3_flash_defaults;
3046 +
3047 + if (opts.reset_defaults != opt_yes)
3048 + ps3.dirty_values = ps3_flash_get_values(&ps3.values);
3049
3050 result = ps3_get_video_mode(&mode);
3051
3052 @@ -515,7 +655,7 @@ int main(int argc, char *argv[])
3053 if (!result && (ps3.values.video_mode != (uint16_t)mode))
3054 ps3_set_video_mode(ps3.values.video_mode);
3055
3056 - ps3.cui = cui_init(&ps3, ps3_kexec_cb);
3057 + ps3.cui = cui_init(&ps3, ps3_kexec_cb, ps3_sixaxis_map);
3058
3059 if (!ps3.cui)
3060 return EXIT_FAILURE;
3061 @@ -523,6 +663,14 @@ int main(int argc, char *argv[])
3062 ps3.mm = ps3_mm_init(&ps3);
3063 ps3.svm = ps3_svm_init(&ps3);
3064
3065 + if (opts.use_timeout != opt_yes
3066 + || ps3.values.timeout == ps3_timeout_forever)
3067 + ui_timer_disable(&ps3.cui->timer);
3068 + else {
3069 + ps3.cui->timer.update_display = ps3_timer_update;
3070 + ui_timer_init(&ps3.cui->timer, ps3.values.timeout);
3071 + }
3072 +
3073 cui_result = cui_run(ps3.cui, ps3.mm, ps3.values.default_item);
3074
3075 pmenu_delete(ps3.mm);