2 * Copyright (C) 2009 Sony Computer Entertainment Inc.
3 * Copyright 2009 Sony Corp.
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; version 2 of the License.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 #if defined(HAVE_CONFIG_H)
27 #include <sys/ioctl.h>
30 #include "pb-protocol/pb-protocol.h"
31 #include "talloc/talloc.h"
32 #include "waiter/waiter.h"
33 #include "process/process.h"
34 #include "i18n/i18n.h"
35 #include "ui/common/discover-client.h"
36 #include "ui/common/ui-system.h"
38 #include "nc-boot-editor.h"
39 #include "nc-config.h"
40 #include "nc-add-url.h"
41 #include "nc-sysinfo.h"
43 #include "nc-helpscreen.h"
44 #include "nc-subset.h"
46 extern const struct help_text main_menu_help_text;
48 static bool cui_detached = false;
50 static struct pmenu *main_menu_init(struct cui *cui);
52 static void cui_start(void)
54 initscr(); /* Initialize ncurses. */
55 cbreak(); /* Disable line buffering. */
56 noecho(); /* Disable getch() echo. */
57 keypad(stdscr, TRUE); /* Enable num keypad keys. */
58 nonl(); /* Disable new-line translation. */
59 intrflush(stdscr, FALSE); /* Disable interrupt flush. */
60 curs_set(0); /* Make cursor invisible */
61 nodelay(stdscr, TRUE); /* Enable non-blocking getch() */
63 /* We may be operating with an incorrect $TERM type; in this case
64 * the keymappings will be slightly broken. We want at least
65 * backspace to work though, so we'll define both DEL and ^H to
67 define_key("\x7f", KEY_BACKSPACE);
68 define_key("\x08", KEY_BACKSPACE);
70 /* we need backtab too, for form navigation. vt220 doesn't include
71 * this (kcbt), but we don't want to require a full linux/xterm termcap
73 define_key("\x1b[Z", KEY_BTAB);
75 /* We'll define a few other keys too since they're commonly
76 * used for navigation but the escape character will cause
77 * Petitboot to exit if they're left undefined */
78 define_key("\x1b\x5b\x35\x7e", KEY_PPAGE);
79 define_key("\x1b\x5b\x36\x7e", KEY_NPAGE);
80 define_key("\x1b\x5b\x31\x7e", KEY_HOME);
81 define_key("\x1b\x5b\x34\x7e", KEY_END);
82 define_key("\x1b\x4f\x48", KEY_HOME);
83 define_key("\x1b\x4f\x46", KEY_END);
84 define_key("OH", KEY_HOME);
85 define_key("OF", KEY_END);
86 define_key("\x1b\x5b\x41", KEY_UP);
87 define_key("\x1b\x5b\x42", KEY_DOWN);
88 define_key("\x1b\x5b\x33\x7e", KEY_DC);
90 while (getch() != ERR) /* flush stdin */
94 static void cui_atexit(void)
105 * cui_abort - Signal the main cui program loop to exit.
107 * Sets cui.abort, which causes the cui_run() routine to return.
110 void cui_abort(struct cui *cui)
112 pb_log("%s: exiting\n", __func__);
117 * cui_resize - Signal the main cui program loop to resize
119 * Called at SIGWINCH.
122 void cui_resize(struct cui *cui)
124 pb_debug("%s: resizing\n", __func__);
129 * cui_on_exit - A generic main menu exit callback.
132 void cui_on_exit(struct pmenu *menu)
134 cui_abort(cui_from_pmenu(menu));
138 * cui_run_cmd - A generic cb to run the supplied command.
141 int cui_run_cmd(struct pmenu_item *item)
144 struct cui *cui = cui_from_item(item);
145 const char **cmd_argv = item->data;
147 nc_scr_status_printf(cui->current, _("Running %s..."), cmd_argv[0]);
151 result = process_run_simple_argv(item, cmd_argv);
154 redrawwin(cui->current->main_ncw);
157 pb_log("%s: failed: '%s'\n", __func__, cmd_argv[0]);
158 nc_scr_status_printf(cui->current, _("Failed: %s"),
166 * cui_boot - A generic cb to run kexec.
169 static int cui_boot(struct pmenu_item *item)
172 struct cui *cui = cui_from_item(item);
173 struct cui_opt_data *cod = cod_from_item(item);
175 assert(cui->current == &cui->main->scr);
177 pb_debug("%s: %s\n", __func__, cod->name);
179 nc_scr_status_printf(cui->current, _("Booting %s..."), cod->name);
181 result = discover_client_boot(cui->client, NULL, cod->opt, cod->bd);
184 nc_scr_status_printf(cui->current,
185 _("Failed: boot %s"), cod->bd->image);
191 static void cui_boot_editor_on_exit(struct cui *cui,
192 struct pmenu_item *item,
193 struct pb_boot_data *bd)
195 struct pmenu *menu = cui->main;
196 struct cui_opt_data *cod;
197 int idx, top, rows, cols;
198 static int user_idx = 0;
200 /* Was the edit cancelled? */
202 cui_set_current(cui, &cui->main->scr);
203 talloc_free(cui->boot_editor);
204 cui->boot_editor = NULL;
208 /* Is this was a new item, we'll need to update the menu */
212 cod = talloc_zero(NULL, struct cui_opt_data);
213 cod->name = talloc_asprintf(cod, _("User item %u"), ++user_idx);
215 item = pmenu_item_create(menu, cod->name);
221 item->on_edit = cui_item_edit;
222 item->on_execute = cui_boot;
225 talloc_steal(item, cod);
227 /* Detach the items array. */
228 set_menu_items(menu->ncm, NULL);
230 /* Insert new item at insert_pt. */
231 insert_pt = pmenu_grow(menu, 1);
232 pmenu_item_insert(menu, item, insert_pt);
234 /* Re-attach the items array. */
235 set_menu_items(menu->ncm, menu->items);
237 /* If our index is above the current top row, align
238 * us to the new top. Otherwise, align us to the new
240 menu_format(cui->main->ncm, &rows, &cols);
241 top = top_row(cui->main->ncm);
242 idx = item_index(item->nci);
247 top = idx < rows ? 0 : idx - rows + 1;
249 set_top_row(cui->main->ncm, top);
250 set_current_item(item->pmenu->ncm, item->nci);
252 nc_scr_post(&menu->scr);
257 cod->bd = talloc_steal(cod, bd);
260 cui_set_current(cui, &cui->main->scr);
261 talloc_free(cui->boot_editor);
262 cui->boot_editor = NULL;
265 void cui_item_edit(struct pmenu_item *item)
267 struct cui *cui = cui_from_item(item);
268 cui->boot_editor = boot_editor_init(cui, item, cui->sysinfo,
269 cui_boot_editor_on_exit);
270 cui_set_current(cui, boot_editor_scr(cui->boot_editor));
273 void cui_item_new(struct pmenu *menu)
275 struct cui *cui = cui_from_pmenu(menu);
276 cui->boot_editor = boot_editor_init(cui, NULL, cui->sysinfo,
277 cui_boot_editor_on_exit);
278 cui_set_current(cui, boot_editor_scr(cui->boot_editor));
281 static void cui_sysinfo_exit(struct cui *cui)
283 cui_set_current(cui, &cui->main->scr);
284 talloc_free(cui->sysinfo_screen);
285 cui->sysinfo_screen = NULL;
288 void cui_show_sysinfo(struct cui *cui)
290 cui->sysinfo_screen = sysinfo_screen_init(cui, cui->sysinfo,
292 cui_set_current(cui, sysinfo_screen_scr(cui->sysinfo_screen));
295 static void cui_config_exit(struct cui *cui)
297 cui_set_current(cui, &cui->main->scr);
298 talloc_free(cui->config_screen);
299 cui->config_screen = NULL;
302 void cui_show_config(struct cui *cui)
304 cui->config_screen = config_screen_init(cui, cui->config,
305 cui->sysinfo, cui_config_exit);
306 cui_set_current(cui, config_screen_scr(cui->config_screen));
309 static void cui_lang_exit(struct cui *cui)
311 cui_set_current(cui, &cui->main->scr);
312 talloc_free(cui->lang_screen);
313 cui->lang_screen = NULL;
316 void cui_show_lang(struct cui *cui)
318 cui->lang_screen = lang_screen_init(cui, cui->config, cui_lang_exit);
319 cui_set_current(cui, lang_screen_scr(cui->lang_screen));
322 static void cui_add_url_exit(struct cui *cui)
324 cui_set_current(cui, &cui->main->scr);
325 talloc_free(cui->add_url_screen);
326 cui->add_url_screen = NULL;
329 void cui_show_add_url(struct cui *cui)
331 cui->add_url_screen = add_url_screen_init(cui, cui_add_url_exit);
332 cui_set_current(cui, add_url_screen_scr(cui->add_url_screen));
335 static void cui_help_exit(struct cui *cui)
337 cui_set_current(cui, help_screen_return_scr(cui->help_screen));
338 talloc_free(cui->help_screen);
339 cui->help_screen = NULL;
342 void cui_show_help(struct cui *cui, const char *title,
343 const struct help_text *text)
348 if (cui->help_screen)
351 cui->help_screen = help_screen_init(cui, cui->current,
352 title, text, cui_help_exit);
354 if (cui->help_screen)
355 cui_set_current(cui, help_screen_scr(cui->help_screen));
358 static void cui_subset_exit(struct cui *cui)
360 cui_set_current(cui, subset_screen_return_scr(cui->subset_screen));
361 talloc_free(cui->subset_screen);
362 cui->subset_screen = NULL;
365 void cui_show_subset(struct cui *cui, const char *title,
371 if (cui->subset_screen)
374 cui->subset_screen = subset_screen_init(cui, cui->current,
375 title, arg, cui_subset_exit);
377 if (cui->subset_screen)
378 cui_set_current(cui, subset_screen_scr(cui->subset_screen));
382 * cui_set_current - Set the currently active screen and redraw it.
385 struct nc_scr *cui_set_current(struct cui *cui, struct nc_scr *scr)
389 DBGS("%p -> %p\n", cui->current, scr);
391 assert(cui->current != scr);
398 nc_scr_post(cui->current);
403 static bool process_global_keys(struct cui *cui, int key)
407 if (cui->current && cui->current->main_ncw)
415 * cui_process_key - Process input on stdin.
418 static int cui_process_key(void *arg)
420 struct cui *cui = cui_from_arg(arg);
422 assert(cui->current);
427 pb_debug("%s: got key %d\n", __func__, c);
432 if (!cui->has_input) {
433 cui->has_input = true;
435 pb_log("UI input received (key = %d), aborting "
436 "default boot\n", c);
437 discover_client_cancel_default(cui->client);
439 pb_log("UI input received (key = %d), aborting "
440 "once server connects\n", c);
444 if (process_global_keys(cui, c))
447 cui->current->process_key(cui->current, c);
454 * cui_process_js - Process joystick events.
457 static int cui_process_js(void *arg)
459 struct cui *cui = cui_from_arg(arg);
462 c = pjs_process_event(cui->pjs);
466 cui_process_key(arg);
473 * cui_handle_resize - Handle the term resize.
476 static void cui_handle_resize(struct cui *cui)
480 if (ioctl(1, TIOCGWINSZ, &ws) == -1) {
481 pb_log("%s: ioctl failed: %s\n", __func__, strerror(errno));
485 pb_debug("%s: {%u,%u}\n", __func__, ws.ws_row, ws.ws_col);
487 wclear(cui->current->main_ncw);
488 resize_term(ws.ws_row, ws.ws_col);
489 cui->current->resize(cui->current);
491 /* For some reason this makes ncurses redraw the screen */
493 redrawwin(cui->current->main_ncw);
494 wrefresh(cui->current->main_ncw);
498 * cui_device_add - Client device_add callback.
500 * Creates menu_items for all the device boot_options and inserts those
501 * menu_items into the main menu. Redraws the main menu if it is active.
504 static int cui_boot_option_add(struct device *dev, struct boot_option *opt,
507 struct pmenu_item *i, *dev_hdr = NULL;
508 struct cui *cui = cui_from_arg(arg);
509 struct cui_opt_data *cod;
510 const char *tab = " ";
511 unsigned int insert_pt;
512 int result, rows, cols;
516 pb_debug("%s: %p %s\n", __func__, opt, opt->id);
518 selected = current_item(cui->main->ncm);
519 menu_format(cui->main->ncm, &rows, &cols);
521 if (cui->current == &cui->main->scr)
522 nc_scr_unpost(cui->current);
524 /* Check if the boot device is new */
525 dev_hdr = pmenu_find_device(cui->main, dev, opt);
527 /* All actual boot entries are 'tabbed' across */
528 name = talloc_asprintf(cui->main, "%s%s",
529 tab, opt->name ? : "Unknown Name");
531 /* Save the item in opt->ui_info for cui_device_remove() */
532 opt->ui_info = i = pmenu_item_create(cui->main, name);
537 i->on_edit = cui_item_edit;
538 i->on_execute = cui_boot;
539 i->data = cod = talloc(i, struct cui_opt_data);
543 cod->opt_hash = pb_opt_hash(dev, opt);
544 cod->name = opt->name;
545 cod->bd = talloc(i, struct pb_boot_data);
547 cod->bd->image = talloc_strdup(cod->bd, opt->boot_image_file);
548 cod->bd->initrd = talloc_strdup(cod->bd, opt->initrd_file);
549 cod->bd->dtb = talloc_strdup(cod->bd, opt->dtb_file);
550 cod->bd->args = talloc_strdup(cod->bd, opt->boot_args);
552 /* This disconnects items array from menu. */
553 result = set_menu_items(cui->main->ncm, NULL);
556 pb_log("%s: set_menu_items failed: %d\n", __func__, result);
558 /* Insert new items at insert_pt. */
560 insert_pt = pmenu_grow(cui->main, 2);
561 pmenu_item_insert(cui->main, dev_hdr, insert_pt);
562 pb_log("%s: adding new device hierarchy %s\n",
563 __func__,opt->device_id);
564 pmenu_item_insert(cui->main, i, insert_pt+1);
566 insert_pt = pmenu_grow(cui->main, 1);
567 pmenu_item_add(cui->main, i, insert_pt);
570 pb_log("%s: adding opt '%s'\n", __func__, cod->name);
571 pb_log(" image '%s'\n", cod->bd->image);
572 pb_log(" initrd '%s'\n", cod->bd->initrd);
573 pb_log(" args '%s'\n", cod->bd->args);
575 /* Re-attach the items array. */
576 result = set_menu_items(cui->main->ncm, cui->main->items);
579 pb_log("%s: set_menu_items failed: %d\n", __func__, result);
582 pb_log("%s\n", __func__);
583 pmenu_dump_items(cui->main->items,
584 item_count(cui->main->ncm) + 1);
587 if (!item_visible(selected)) {
590 top = top_row(cui->main->ncm);
591 idx = item_index(selected);
593 /* If our index is above the current top row, align
594 * us to the new top. Otherwise, align us to the new
596 top = top < idx ? idx - rows + 1 : idx;
598 set_top_row(cui->main->ncm, top);
599 set_current_item(cui->main->ncm, selected);
602 if (cui->current == &cui->main->scr)
603 nc_scr_post(cui->current);
609 * cui_device_remove - Client device remove callback.
611 * Removes all the menu_items for the device from the main menu and redraws the
612 * main menu if it is active.
615 static void cui_device_remove(struct device *dev, void *arg)
617 struct cui *cui = cui_from_arg(arg);
618 struct boot_option *opt;
620 int rows, cols, top, last;
623 pb_log("%s: %p %s\n", __func__, dev, dev->id);
625 if (cui->current == &cui->main->scr)
626 nc_scr_unpost(cui->current);
628 /* This disconnects items array from menu. */
630 result = set_menu_items(cui->main->ncm, NULL);
633 pb_log("%s: set_menu_items failed: %d\n", __func__, result);
635 list_for_each_entry(&dev->boot_options, opt, list) {
636 struct pmenu_item *item = pmenu_item_from_arg(opt->ui_info);
638 assert(pb_protocol_device_cmp(dev, cod_from_item(item)->dev));
639 pmenu_remove(cui->main, item);
642 /* Manually remove remaining device hierarchy item */
643 for (i=0; i < cui->main->item_count; i++) {
644 struct pmenu_item *item = item_userptr(cui->main->items[i]);
645 if (!item || !item->data )
648 struct cui_opt_data *data = item->data;
649 if (data && data->dev && data->dev == dev)
650 pmenu_remove(cui->main,item);
653 /* Re-attach the items array. */
655 result = set_menu_items(cui->main->ncm, cui->main->items);
657 /* Move cursor to 'Exit' menu entry */
658 menu_format(cui->main->ncm, &rows, &cols);
659 last = cui->main->item_count - 1;
660 set_current_item(cui->main->ncm, cui->main->items[last]);
661 if (!item_visible(cui->main->items[last])) {
662 top = last < rows ? 0 : last - rows + 1;
663 set_top_row(cui->main->ncm, top);
667 pb_log("%s: set_menu_items failed: %d\n", __func__, result);
670 pb_log("%s\n", __func__);
671 pmenu_dump_items(cui->main->items,
672 item_count(cui->main->ncm) + 1);
675 if (cui->current == &cui->main->scr)
676 nc_scr_post(cui->current);
679 static void cui_update_status(struct boot_status *status, void *arg)
681 struct cui *cui = cui_from_arg(arg);
683 nc_scr_status_printf(cui->current,
685 status->type == BOOT_STATUS_ERROR ?
686 _("Error") : _("Info"),
691 static void cui_update_mm_title(struct cui *cui)
693 struct nc_frame *frame = &cui->main->scr.frame;
695 talloc_free(frame->rtitle);
697 frame->rtitle = talloc_strdup(cui->main, cui->sysinfo->type);
698 if (cui->sysinfo->identifier)
699 frame->rtitle = talloc_asprintf_append(frame->rtitle,
700 " %s", cui->sysinfo->identifier);
702 if (cui->current == &cui->main->scr)
703 nc_scr_post(cui->current);
706 static void cui_update_sysinfo(struct system_info *sysinfo, void *arg)
708 struct cui *cui = cui_from_arg(arg);
709 cui->sysinfo = talloc_steal(cui, sysinfo);
711 /* if we're currently displaying the system info screen, inform it
712 * of the updated information. */
713 if (cui->sysinfo_screen)
714 sysinfo_screen_update(cui->sysinfo_screen, sysinfo);
716 if (cui->subset_screen)
717 subset_screen_update(cui->subset_screen);
719 /* ... and do the same with the config screen... */
720 if (cui->config_screen)
721 config_screen_update(cui->config_screen, cui->config, sysinfo);
723 /* ... and the boot editor. */
724 if (cui->boot_editor)
725 boot_editor_update(cui->boot_editor, sysinfo);
727 cui_update_mm_title(cui);
730 static void cui_update_language(struct cui *cui, char *lang)
735 cur_lang = setlocale(LC_ALL, NULL);
736 if (cur_lang && !strcmp(cur_lang, lang))
739 setlocale(LC_ALL, lang);
741 /* we'll need to update the menu: drop all items and repopulate */
742 repost_menu = cui->current == &cui->main->scr;
744 nc_scr_unpost(cui->current);
746 talloc_free(cui->main);
747 cui->main = main_menu_init(cui);
750 cui->current = &cui->main->scr;
751 nc_scr_post(cui->current);
754 discover_client_enumerate(cui->client);
757 static void cui_update_config(struct config *config, void *arg)
759 struct cui *cui = cui_from_arg(arg);
760 cui->config = talloc_steal(cui, config);
763 cui_update_language(cui, config->lang);
765 if (cui->subset_screen)
766 subset_screen_update(cui->subset_screen);
768 if (cui->config_screen)
769 config_screen_update(cui->config_screen, config, cui->sysinfo);
771 if (config->safe_mode)
772 nc_scr_status_printf(cui->current,
773 _("SAFE MODE: select '%s' to continue"),
774 _("Rescan devices"));
777 int cui_send_config(struct cui *cui, struct config *config)
779 return discover_client_send_config(cui->client, config);
782 int cui_send_url(struct cui *cui, char * url)
784 return discover_client_send_url(cui->client, url);
787 void cui_send_reinit(struct cui *cui)
789 discover_client_send_reinit(cui->client);
792 static int menu_sysinfo_execute(struct pmenu_item *item)
794 cui_show_sysinfo(cui_from_item(item));
798 static int menu_config_execute(struct pmenu_item *item)
800 cui_show_config(cui_from_item(item));
804 static int menu_lang_execute(struct pmenu_item *item)
806 cui_show_lang(cui_from_item(item));
810 static int menu_reinit_execute(struct pmenu_item *item)
812 if (cui_from_item(item)->client)
813 cui_send_reinit(cui_from_item(item));
817 static int menu_add_url_execute(struct pmenu_item *item)
819 if (cui_from_item(item)->client)
820 cui_show_add_url(cui_from_item(item));
825 * pb_mm_init - Setup the main menu instance.
827 static struct pmenu *main_menu_init(struct cui *cui)
829 struct pmenu_item *i;
833 m = pmenu_init(cui, 7, cui_on_exit);
835 pb_log("%s: failed\n", __func__);
839 m->on_new = cui_item_new;
841 m->scr.frame.ltitle = talloc_asprintf(m,
842 "Petitboot (" PACKAGE_VERSION ")");
843 m->scr.frame.rtitle = NULL;
844 m->scr.frame.help = talloc_strdup(m,
845 _("Enter=accept, e=edit, n=new, x=exit, l=language, h=help"));
846 m->scr.frame.status = talloc_strdup(m, _("Welcome to Petitboot"));
848 /* add a separator */
849 i = pmenu_item_create(m, " ");
850 item_opts_off(i->nci, O_SELECTABLE);
851 pmenu_item_insert(m, i, 0);
853 /* add system items */
854 i = pmenu_item_create(m, _("System information"));
855 i->on_execute = menu_sysinfo_execute;
856 pmenu_item_insert(m, i, 1);
858 i = pmenu_item_create(m, _("System configuration"));
859 i->on_execute = menu_config_execute;
860 pmenu_item_insert(m, i, 2);
862 /* this label isn't translated, so we don't want a gettext() here */
863 i = pmenu_item_create(m, "Language");
864 i->on_execute = menu_lang_execute;
865 pmenu_item_insert(m, i, 3);
867 i = pmenu_item_create(m, _("Rescan devices"));
868 i->on_execute = menu_reinit_execute;
869 pmenu_item_insert(m, i, 4);
871 i = pmenu_item_create(m, _("Retrieve config from URL"));
872 i->on_execute = menu_add_url_execute;
873 pmenu_item_insert(m, i, 5);
875 i = pmenu_item_create(m, _("Exit to shell"));
876 i->on_execute = pmenu_exit_cb;
877 pmenu_item_insert(m, i, 6);
879 result = pmenu_setup(m);
882 pb_log("%s:%d: pmenu_setup failed: %s\n", __func__, __LINE__,
887 m->help_title = _("main menu");
888 m->help_text = &main_menu_help_text;
890 menu_opts_off(m->ncm, O_SHOWDESC);
891 set_menu_mark(m->ncm, " *");
892 set_current_item(m->ncm, i->nci);
901 static struct discover_client_ops cui_client_ops = {
903 .boot_option_add = cui_boot_option_add,
904 .device_remove = cui_device_remove,
905 .update_status = cui_update_status,
906 .update_sysinfo = cui_update_sysinfo,
907 .update_config = cui_update_config,
910 /* cui_server_wait_on_exit - On exit spin until the server is available.
912 * If the program exits before connecting to the server autoboot won't be
913 * cancelled even though there has been keyboard activity. This function is
914 * called by a child process which will spin until the server is connected and
915 * told to cancel autoboot.
917 * Processes exiting from this function will not carry out the cui_atexit()
920 static void cui_server_wait_on_exit(struct cui *cui)
924 while (!cui->client) {
925 cui->client = discover_client_init(cui->waitset,
926 &cui_client_ops, cui);
931 talloc_steal(cui, cui->client);
932 discover_client_cancel_default(cui->client);
935 /* cui_server_wait - Connect to the discover server.
936 * @arg: Pointer to the cui instance.
938 * A timeout callback that attempts to connect to the discover server; on
939 * failure it registers itself with a one second timeout to try again.
940 * On success the cui->client struct will be set.
942 * Since this updates the status line when called it must not be called
943 * before the UI is ready.
945 static int cui_server_wait(void *arg)
947 struct cui *cui = cui_from_arg(arg);
950 pb_debug("We already have a server!\n");
954 /* We haven't yet connected to the server */
955 pb_log("Trying to connect...\n");
956 cui->client = discover_client_init(cui->waitset,
957 &cui_client_ops, cui);
960 waiter_register_timeout(cui->waitset, 1000, cui_server_wait,
962 nc_scr_status_printf(cui->current,
963 "Info: Waiting for device discovery");
965 nc_scr_status_printf(cui->current,
966 "Info: Connected to pb-discover!");
967 talloc_steal(cui, cui->client);
969 if (cui->has_input) {
970 pb_log("Aborting default boot on pb-discover connect\n");
971 discover_client_cancel_default(cui->client);
979 * cui_init - Setup the cui instance.
980 * @platform_info: A value for the struct cui platform_info member.
982 * Returns a pointer to a struct cui on success, or NULL on error.
984 * Allocates the cui instance, sets up the client and stdin waiters, and
985 * sets up the ncurses menu screen.
988 struct cui *cui_init(void* platform_info,
989 int (*js_map)(const struct js_event *e), int start_daemon, int timeout)
994 cui = talloc_zero(NULL, struct cui);
996 pb_log("%s: alloc cui failed.\n", __func__);
997 fprintf(stderr, _("%s: alloc cui failed.\n"), __func__);
1001 cui->c_sig = pb_cui_sig;
1002 cui->platform_info = platform_info;
1003 cui->waitset = waitset_create(cui);
1005 process_init(cui, cui->waitset, false);
1007 /* Loop here for scripts that just started the server. */
1010 for (i = start_daemon ? 2 : 15; i && timeout; i--) {
1011 cui->client = discover_client_init(cui->waitset,
1012 &cui_client_ops, cui);
1013 if (cui->client || !i)
1015 pb_log("%s: waiting for server %d\n", __func__, i);
1019 if (!cui->client && start_daemon) {
1024 result = pb_start_daemon(cui);
1029 pb_log("%s: discover_client_init failed.\n", __func__);
1030 fprintf(stderr, _("%s: error: discover_client_init failed.\n"),
1032 fprintf(stderr, _("could not start pb-discover, the petitboot "
1034 goto fail_client_init;
1037 if (!cui->client && !timeout) {
1038 /* Have the first timeout fire immediately so we can check
1039 * for the server as soon as the UI is ready */
1040 waiter_register_timeout(cui->waitset, 0,
1041 cui_server_wait, cui);
1042 } else if (!cui->client) {
1043 pb_log("%s: discover_client_init failed.\n", __func__);
1044 fprintf(stderr, _("%s: error: discover_client_init failed.\n"),
1046 fprintf(stderr, _("check that pb-discover, "
1047 "the petitboot daemon is running.\n"));
1048 goto fail_client_init;
1052 talloc_steal(cui, cui->client);
1055 cui->main = main_menu_init(cui);
1057 goto fail_client_init;
1059 waiter_register_io(cui->waitset, STDIN_FILENO, WAIT_IN,
1060 cui_process_key, cui);
1064 cui->pjs = pjs_init(cui, js_map);
1067 waiter_register_io(cui->waitset, pjs_get_fd(cui->pjs),
1068 WAIT_IN, cui_process_js, cui);
1080 * cui_run - The main cui program loop.
1081 * @cui: The cui instance.
1082 * @main: The menu to use as the main menu.
1084 * Runs the cui engine. Does not return until indicated to do so by some
1085 * user action, or an error occurs. Frees the cui object on return.
1086 * Returns 0 on success (return to shell), -1 on error (should restart).
1089 int cui_run(struct cui *cui)
1095 cui->current = &cui->main->scr;
1096 cui->default_item = 0;
1098 nc_scr_post(cui->current);
1101 int result = waiter_poll(cui->waitset);
1104 pb_log("%s: poll: %s\n", __func__, strerror(errno));
1111 while (cui->resize) {
1113 cui_handle_resize(cui);
1120 /* Fork a child to tell the server to cancel autoboot */
1123 cui_server_wait_on_exit(cui);
1127 pb_log("Failed to fork child on exit: %m\n");
1130 return cui->abort ? 0 : -1;