]> git.ozlabs.org Git - petitboot/blob - ui/ncurses/nc-config.c
ui/ncurses: Add option to clear IPMI boot mailbox
[petitboot] / ui / ncurses / nc-config.c
1 /*
2  *  Copyright (C) 2013 IBM Corporation
3  *
4  *  This program is free software; you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License as published by
6  *  the Free Software Foundation; version 2 of the License.
7  *
8  *  This program is distributed in the hope that it will be useful,
9  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
10  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  *  GNU General Public License for more details.
12  *
13  *  You should have received a copy of the GNU General Public License
14  *  along with this program; if not, write to the Free Software
15  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16  */
17
18 #if defined(HAVE_CONFIG_H)
19 #include "config.h"
20 #endif
21
22 #include <errno.h>
23 #include <stdlib.h>
24 #include <string.h>
25
26 #include <pb-config/pb-config.h>
27 #include <talloc/talloc.h>
28 #include <types/types.h>
29 #include <log/log.h>
30 #include <i18n/i18n.h>
31
32 #include "ui/common/discover-client.h"
33 #include "nc-cui.h"
34 #include "nc-config.h"
35 #include "nc-widgets.h"
36
37 #define N_FIELDS        51
38
39 extern struct help_text config_help_text;
40
41 enum net_conf_type {
42         NET_CONF_TYPE_DHCP_ALL,
43         NET_CONF_TYPE_DHCP_ONE,
44         NET_CONF_TYPE_STATIC,
45 };
46
47 struct config_screen {
48         struct nc_scr           scr;
49         struct cui              *cui;
50         struct nc_widgetset     *widgetset;
51         WINDOW                  *pad;
52
53         bool                    exit;
54         bool                    show_help;
55         bool                    need_redraw;
56         bool                    need_update;
57
58         void                    (*on_exit)(struct cui *);
59
60         int                     scroll_y;
61
62         int                     label_x;
63         int                     field_x;
64         int                     network_config_y;
65
66         enum net_conf_type      net_conf_type;
67
68         bool                    autoboot_enabled;
69         bool                    ipmi_override;
70         bool                    ipmi_mailbox;
71         bool                    net_override;
72
73         struct {
74                 struct nc_widget_label          *autoboot_l;
75                 struct nc_widget_select         *autoboot_f;
76                 struct nc_widget_label          *boot_order_l;
77                 struct nc_widget_subset         *boot_order_f;
78                 struct nc_widget_label          *boot_empty_l;
79                 struct nc_widget_button         *boot_add_b;
80                 struct nc_widget_button         *boot_none_b;
81                 struct nc_widget_button         *boot_any_b;
82                 struct nc_widget_textbox        *timeout_f;
83                 struct nc_widget_label          *timeout_l;
84                 struct nc_widget_label          *timeout_help_l;
85
86                 struct nc_widget_label          *ipmi_type_l;
87                 struct nc_widget_label          *ipmi_clear_l;
88                 struct nc_widget_button         *ipmi_clear_b;
89
90                 struct nc_widget_label          *ipmi_mailbox_l;
91                 struct nc_widget_button         *ipmi_mailbox_b;
92
93                 struct nc_widget_label          *network_l;
94                 struct nc_widget_select         *network_f;
95
96                 struct nc_widget_label          *iface_l;
97                 struct nc_widget_select         *iface_f;
98                 struct nc_widget_label          *ip_addr_l;
99                 struct nc_widget_textbox        *ip_addr_f;
100                 struct nc_widget_label          *ip_mask_l;
101                 struct nc_widget_textbox        *ip_mask_f;
102                 struct nc_widget_label          *ip_addr_mask_help_l;
103                 struct nc_widget_label          *gateway_l;
104                 struct nc_widget_textbox        *gateway_f;
105                 struct nc_widget_label          *gateway_help_l;
106                 struct nc_widget_label          *url_l;
107                 struct nc_widget_textbox        *url_f;
108                 struct nc_widget_label          *url_help_l;
109                 struct nc_widget_label          *dns_l;
110                 struct nc_widget_textbox        *dns_f;
111                 struct nc_widget_label          *dns_dhcp_help_l;
112                 struct nc_widget_label          *dns_help_l;
113                 struct nc_widget_label          *http_proxy_l;
114                 struct nc_widget_textbox        *http_proxy_f;
115                 struct nc_widget_label          *https_proxy_l;
116                 struct nc_widget_textbox        *https_proxy_f;
117
118                 struct nc_widget_label          *allow_write_l;
119                 struct nc_widget_select         *allow_write_f;
120                 struct nc_widget_label          *boot_console_l;
121                 struct nc_widget_select         *boot_console_f;
122                 struct nc_widget_label          *manual_console_l;
123                 struct nc_widget_label          *current_console_l;
124
125                 struct nc_widget_button         *update_password_l;
126
127                 struct nc_widget_label          *net_override_l;
128                 struct nc_widget_label          *safe_mode;
129                 struct nc_widget_button         *ok_b;
130                 struct nc_widget_button         *help_b;
131                 struct nc_widget_button         *cancel_b;
132         } widgets;
133 };
134
135 static struct config_screen *config_screen_from_scr(struct nc_scr *scr)
136 {
137         struct config_screen *config_screen;
138
139         assert(scr->sig == pb_config_screen_sig);
140         config_screen = (struct config_screen *)
141                 ((char *)scr - (size_t)&((struct config_screen *)0)->scr);
142         assert(config_screen->scr.sig == pb_config_screen_sig);
143         return config_screen;
144 }
145
146 static void pad_refresh(struct config_screen *screen)
147 {
148         int y, x, rows, cols;
149
150         getmaxyx(screen->scr.sub_ncw, rows, cols);
151         getbegyx(screen->scr.sub_ncw, y, x);
152
153         prefresh(screen->pad, screen->scroll_y, 0, y, x, rows, cols);
154 }
155
156 static void config_screen_process_key(struct nc_scr *scr, int key)
157 {
158         struct config_screen *screen = config_screen_from_scr(scr);
159         bool handled;
160
161         handled = widgetset_process_key(screen->widgetset, key);
162
163         if (!handled) {
164                 switch (key) {
165                 case 'x':
166                 case 27: /* esc */
167                         screen->exit = true;
168                         break;
169                 case 'h':
170                         screen->show_help = true;
171                         break;
172                 }
173         }
174
175         if (screen->exit) {
176                 screen->on_exit(screen->cui);
177
178         } else if (screen->show_help) {
179                 screen->show_help = false;
180                 screen->need_redraw = true;
181                 cui_show_help(screen->cui, _("System Configuration"),
182                                 &config_help_text);
183
184         } else if (handled && (screen->cui->current == scr)) {
185                 pad_refresh(screen);
186         }
187 }
188
189 static void config_screen_resize(struct nc_scr *scr)
190 {
191         struct config_screen *screen = config_screen_from_scr(scr);
192         (void)screen;
193 }
194
195 static int config_screen_unpost(struct nc_scr *scr)
196 {
197         struct config_screen *screen = config_screen_from_scr(scr);
198         widgetset_unpost(screen->widgetset);
199         return 0;
200 }
201
202 struct nc_scr *config_screen_scr(struct config_screen *screen)
203 {
204         return &screen->scr;
205 }
206
207 static int screen_process_form(struct config_screen *screen)
208 {
209         const struct system_info *sysinfo = screen->cui->sysinfo;
210         enum net_conf_type net_conf_type;
211         struct interface_config *iface;
212         bool allow_write;
213         char *str, *end;
214         struct config *config;
215         int i, n_boot_opts, rc;
216         unsigned int *order, idx;
217         char mac[20];
218
219         config = config_copy(screen, screen->cui->config);
220
221         talloc_free(config->autoboot_opts);
222         config->n_autoboot_opts = 0;
223
224         n_boot_opts = widget_subset_get_order(config, &order,
225                                               screen->widgets.boot_order_f);
226
227         config->autoboot_enabled = widget_select_get_value(
228                                                 screen->widgets.autoboot_f);
229
230         config->n_autoboot_opts = n_boot_opts;
231         config->autoboot_opts = talloc_array(config, struct autoboot_option,
232                                              n_boot_opts);
233
234         for (i = 0; i < n_boot_opts; i++) {
235                 if (order[i] < sysinfo->n_blockdevs) {
236                         /* disk uuid */
237                         config->autoboot_opts[i].boot_type = BOOT_DEVICE_UUID;
238                         config->autoboot_opts[i].uuid = talloc_strdup(config,
239                                                         sysinfo->blockdevs[order[i]]->uuid);
240                 } else if(order[i] < (sysinfo->n_blockdevs + sysinfo->n_interfaces)) {
241                         /* net uuid */
242                         order[i] -= sysinfo->n_blockdevs;
243                         config->autoboot_opts[i].boot_type = BOOT_DEVICE_UUID;
244                         mac_str(sysinfo->interfaces[order[i]]->hwaddr,
245                                 sysinfo->interfaces[order[i]]->hwaddr_size,
246                                 mac, sizeof(mac));
247                         config->autoboot_opts[i].uuid = talloc_strdup(config, mac);
248                 } else {
249                         /* device type */
250                         order[i] -= (sysinfo->n_blockdevs + sysinfo->n_interfaces);
251                         config->autoboot_opts[i].boot_type = BOOT_DEVICE_TYPE;
252                         config->autoboot_opts[i].type = order[i];
253                 }
254         }
255
256         str = widget_textbox_get_value(screen->widgets.timeout_f);
257         if (str) {
258                 unsigned long x;
259                 errno = 0;
260                 x = strtoul(str, &end, 10);
261                 if (!errno && end != str)
262                         config->autoboot_timeout_sec = x;
263         }
264
265         net_conf_type = widget_select_get_value(screen->widgets.network_f);
266
267         /* if we don't have any network interfaces, prevent per-interface
268          * configuration */
269         if (sysinfo->n_interfaces == 0)
270                 net_conf_type = NET_CONF_TYPE_DHCP_ALL;
271
272         if (net_conf_type == NET_CONF_TYPE_DHCP_ALL) {
273                 config->network.n_interfaces = 0;
274
275         } else {
276                 iface = talloc_zero(config, struct interface_config);
277                 config->network.n_interfaces = 1;
278                 config->network.interfaces = talloc_array(config,
279                                 struct interface_config *, 1);
280                 config->network.interfaces[0] = iface;
281
282                 /* copy hwaddr (from the sysinfo interface data) to
283                  * the configuration */
284                 idx = widget_select_get_value(screen->widgets.iface_f);
285                 memcpy(iface->hwaddr, sysinfo->interfaces[idx]->hwaddr,
286                                 sizeof(iface->hwaddr));
287         }
288
289         if (net_conf_type == NET_CONF_TYPE_DHCP_ONE) {
290                 iface->method = CONFIG_METHOD_DHCP;
291         }
292
293         if (net_conf_type == NET_CONF_TYPE_STATIC) {
294                 char *ip, *mask, *gateway, *url;
295
296                 ip = widget_textbox_get_value(screen->widgets.ip_addr_f);
297                 mask = widget_textbox_get_value(screen->widgets.ip_mask_f);
298                 gateway = widget_textbox_get_value(screen->widgets.gateway_f);
299                 url = widget_textbox_get_value(screen->widgets.url_f);
300
301                 if (!ip || !*ip || !mask || !*mask) {
302                         screen->scr.frame.status =
303                                 _("No IP / mask values are set");
304                         nc_scr_frame_draw(&screen->scr);
305                         talloc_free(config);
306                         return -1;
307                 }
308
309                 iface->method = CONFIG_METHOD_STATIC;
310                 iface->static_config.address = talloc_asprintf(iface, "%s/%s",
311                                 ip, mask);
312                 iface->static_config.gateway = talloc_strdup(iface, gateway);
313                 iface->static_config.url = talloc_strdup(iface, url);
314         }
315
316         str = widget_textbox_get_value(screen->widgets.dns_f);
317         talloc_free(config->network.dns_servers);
318         config->network.dns_servers = NULL;
319         config->network.n_dns_servers = 0;
320
321         if (str && strlen(str)) {
322                 char *dns, *tmp;
323                 int i;
324
325                 for (;;) {
326                         dns = strtok_r(str, " \t", &tmp);
327
328                         if (!dns)
329                                 break;
330
331                         i = config->network.n_dns_servers++;
332                         config->network.dns_servers = talloc_realloc(config,
333                                         config->network.dns_servers,
334                                         const char *,
335                                         config->network.n_dns_servers);
336                         config->network.dns_servers[i] =
337                                 talloc_strdup(config, dns);
338
339                         str = NULL;
340                 }
341         }
342
343         talloc_free(config->http_proxy);
344         talloc_free(config->https_proxy);
345         str = widget_textbox_get_value(screen->widgets.http_proxy_f);
346         config->http_proxy = talloc_strdup(config, str);
347         str = widget_textbox_get_value(screen->widgets.https_proxy_f);
348         config->https_proxy = talloc_strdup(config, str);
349
350         allow_write = widget_select_get_value(screen->widgets.allow_write_f);
351         if (allow_write != config->allow_writes)
352                 config->allow_writes = allow_write;
353
354         if (config->n_consoles && !config->manual_console) {
355                 idx = widget_select_get_value(screen->widgets.boot_console_f);
356                 if (!config->boot_console) {
357                         config->boot_console = talloc_strdup(config,
358                                                         config->consoles[idx]);
359                 } else if (strncmp(config->boot_console, config->consoles[idx],
360                                 strlen(config->boot_console)) != 0) {
361                         talloc_free(config->boot_console);
362                         config->boot_console = talloc_strdup(config,
363                                                         config->consoles[idx]);
364                 }
365         }
366
367         config->safe_mode = false;
368         rc = cui_send_config(screen->cui, config);
369         talloc_free(config);
370
371         if (rc)
372                 pb_log("cui_send_config failed!\n");
373         else
374                 pb_debug("config sent!\n");
375
376         return 0;
377 }
378
379 static void config_screen_config_cb(struct nc_scr *scr)
380 {
381         struct config_screen *screen = config_screen_from_scr(scr);
382
383         if (!screen_process_form(screen))
384                 screen->exit = true;
385 }
386
387 #ifdef CRYPT_SUPPORT
388 static void password_click(void *arg)
389 {
390         struct config_screen *screen = arg;
391
392         screen->need_update = true;
393         cui_show_auth(screen->cui, screen->scr.main_ncw, true, NULL);
394 }
395 #endif
396
397 static void ok_click(void *arg)
398 {
399         struct config_screen *screen = arg;
400
401         if (discover_client_authenticated(screen->cui->client)) {
402                 if (screen_process_form(screen))
403                         /* errors are written to the status line, so we'll need
404                          * to refresh */
405                         wrefresh(screen->scr.main_ncw);
406                 else
407                         screen->exit = true;
408         } else {
409                 cui_show_auth(screen->cui, screen->scr.main_ncw, false,
410                                 config_screen_config_cb);
411         }
412 }
413
414 static void help_click(void *arg)
415 {
416         struct config_screen *screen = arg;
417         screen->show_help = true;
418 }
419
420 static void cancel_click(void *arg)
421 {
422         struct config_screen *screen = arg;
423         screen->exit = true;
424 }
425
426 static void ipmi_clear_click(void *arg)
427 {
428         struct config_screen *screen = arg;
429         struct config *config;
430         int rc;
431
432         config = config_copy(screen, screen->cui->config);
433         config->ipmi_bootdev = IPMI_BOOTDEV_INVALID;
434         config->safe_mode = false;
435
436         rc = cui_send_config(screen->cui, config);
437         talloc_free(config);
438
439         if (rc)
440                 pb_log("cui_send_config failed!\n");
441         else
442                 pb_debug("config sent!\n");
443         screen->exit = true;
444 }
445
446 static void ipmi_clear_mailbox_click(void *arg)
447 {
448         struct config_screen *screen = arg;
449         struct config *config;
450         int rc;
451
452         config = config_copy(screen, screen->cui->config);
453         config->ipmi_bootdev_mailbox = false;
454         config->safe_mode = false;
455
456         rc = cui_send_config(screen->cui, config);
457         talloc_free(config);
458
459         if (rc)
460                 pb_log("cui_send_config failed!\n");
461         else
462                 pb_debug("config sent!\n");
463         screen->exit = true;
464 }
465
466
467 static int layout_pair(struct config_screen *screen, int y,
468                 struct nc_widget_label *label,
469                 struct nc_widget *field)
470 {
471         struct nc_widget *label_w = widget_label_base(label);
472         widget_move(label_w, y, screen->label_x);
473         widget_move(field, y, screen->field_x);
474         return max(widget_height(label_w), widget_height(field));
475 }
476
477 static void config_screen_layout_widgets(struct config_screen *screen)
478 {
479         struct nc_widget *wl, *wf, *wh;
480         int y, x, help_x;
481         bool show;
482
483         y = 1;
484         /* currently, the longest label we have is the DNS-servers
485          * widget, so layout our screen based on that */
486         help_x = screen->field_x + 2 +
487                 widget_width(widget_textbox_base(screen->widgets.dns_f));
488
489         wl = widget_label_base(screen->widgets.autoboot_l);
490         widget_set_visible(wl, true);
491         widget_move(wl, y, screen->label_x);
492
493         wf = widget_select_base(screen->widgets.autoboot_f);
494         widget_set_visible(wf, true);
495         widget_move(wf, y, screen->field_x);
496         y += widget_height(wf);
497
498         show = screen->autoboot_enabled;
499
500         if (show)
501                 y += 1;
502
503         wl = widget_label_base(screen->widgets.boot_order_l);
504         widget_set_visible(wl, show);
505         widget_move(wl, y, screen->label_x);
506
507         wf = widget_subset_base(screen->widgets.boot_order_f);
508         widget_move(wf, y, screen->field_x);
509         wl = widget_label_base(screen->widgets.boot_empty_l);
510         widget_move(wl, y, screen->field_x);
511
512         if (widget_subset_height(screen->widgets.boot_order_f)) {
513                 widget_set_visible(wl, false);
514                 widget_set_visible(wf, show);
515                 y += show ? widget_height(wf) : 0;
516         } else {
517                 widget_set_visible(wl, show);
518                 widget_set_visible(wf, false);
519                 y += show ? 1 : 0;
520         }
521
522         if (show) {
523                 y += 1;
524                 widget_move(widget_button_base(screen->widgets.boot_add_b),
525                                 y++, screen->field_x);
526                 widget_move(widget_button_base(screen->widgets.boot_any_b),
527                                 y++, screen->field_x);
528                 widget_move(widget_button_base(screen->widgets.boot_none_b),
529                                 y, screen->field_x);
530         }
531
532         wf = widget_button_base(screen->widgets.boot_add_b);
533         if (widget_subset_n_inactive(screen->widgets.boot_order_f) && show)
534                 widget_set_visible(wf, true);
535         else
536                 widget_set_visible(wf, false);
537
538         if (show)
539                 y += 2;
540
541         widget_set_visible(widget_button_base(screen->widgets.boot_any_b), show);
542         widget_set_visible(widget_button_base(screen->widgets.boot_none_b), show);
543
544         wf = widget_textbox_base(screen->widgets.timeout_f);
545         wl = widget_label_base(screen->widgets.timeout_l);
546         wh = widget_label_base(screen->widgets.timeout_help_l);
547         widget_set_visible(wl, screen->autoboot_enabled);
548         widget_set_visible(wf, screen->autoboot_enabled);
549         widget_set_visible(wh, screen->autoboot_enabled);
550         if (screen->autoboot_enabled) {
551                 widget_set_visible(wh, screen->autoboot_enabled);
552                 widget_move(wl, y, screen->label_x);
553                 widget_move(wf, y, screen->field_x);
554                 widget_move(wh, y, screen->field_x + widget_width(wf) + 1);
555                 y += 2;
556         } else
557                 y += 1;
558
559         if (screen->ipmi_override) {
560                 wl = widget_label_base(screen->widgets.ipmi_type_l);
561                 widget_set_visible(wl, true);
562                 widget_move(wl, y, screen->label_x);
563                 y += 1;
564
565                 wl = widget_label_base(screen->widgets.ipmi_clear_l);
566                 wf = widget_button_base(screen->widgets.ipmi_clear_b);
567                 widget_set_visible(wl, true);
568                 widget_set_visible(wf, true);
569                 widget_move(wl, y, screen->label_x);
570                 widget_move(wf, y, screen->field_x);
571                 y += 1;
572         }
573
574         if (screen->ipmi_mailbox) {
575                 wl = widget_label_base(screen->widgets.ipmi_mailbox_l);
576                 widget_set_visible(wl, true);
577                 widget_move(wl, y, screen->label_x);
578                 y += 1;
579
580                 wf = widget_button_base(screen->widgets.ipmi_mailbox_b);
581                 widget_set_visible(wf, true);
582                 widget_move(wf, y, screen->field_x);
583                 y += 1;
584         }
585
586         y += 1;
587
588         y += layout_pair(screen, y, screen->widgets.network_l,
589                         widget_select_base(screen->widgets.network_f));
590
591         y += 1;
592
593         /* conditionally show iface select */
594         wl = widget_label_base(screen->widgets.iface_l);
595         wf = widget_select_base(screen->widgets.iface_f);
596
597         show = screen->net_conf_type == NET_CONF_TYPE_DHCP_ONE ||
598                 screen->net_conf_type == NET_CONF_TYPE_STATIC;
599
600         widget_set_visible(wl, show);
601         widget_set_visible(wf, show);
602
603         if (show)
604                 y += layout_pair(screen, y, screen->widgets.iface_l, wf) + 1;
605
606         /* conditionally show static IP params */
607         show = screen->net_conf_type == NET_CONF_TYPE_STATIC;
608
609         wl = widget_label_base(screen->widgets.ip_addr_l);
610         wf = widget_textbox_base(screen->widgets.ip_addr_f);
611         widget_set_visible(wl, show);
612         widget_set_visible(wf, show);
613         x = screen->field_x + widget_width(wf) + 1;
614
615         if (show)
616                 layout_pair(screen, y, screen->widgets.ip_addr_l, wf);
617
618         wl = widget_label_base(screen->widgets.ip_mask_l);
619         wf = widget_textbox_base(screen->widgets.ip_mask_f);
620         widget_set_visible(wl, show);
621         widget_set_visible(wf, show);
622
623         if (show) {
624                 widget_move(wl, y, x);
625                 widget_move(wf, y, x + 2);
626         }
627
628         /* help for IP/mask */
629         wh = widget_label_base(screen->widgets.ip_addr_mask_help_l);
630         widget_set_visible(wh, show);
631         if (show) {
632                 widget_move(wh, y, help_x);
633                 y++;
634         }
635
636         wl = widget_label_base(screen->widgets.gateway_l);
637         wf = widget_textbox_base(screen->widgets.gateway_f);
638         wh = widget_label_base(screen->widgets.gateway_help_l);
639         widget_set_visible(wl, show);
640         widget_set_visible(wf, show);
641         widget_set_visible(wh, show);
642
643         if (show) {
644                 layout_pair(screen, y, screen->widgets.gateway_l, wf);
645                 widget_move(wh, y, help_x);
646                 y++;
647         }
648
649         wl = widget_label_base(screen->widgets.url_l);
650         wf = widget_textbox_base(screen->widgets.url_f);
651         wh = widget_label_base(screen->widgets.url_help_l);
652         widget_set_visible(wl, show);
653         widget_set_visible(wf, show);
654         widget_set_visible(wh, show);
655
656         if (show) {
657                 layout_pair(screen, y, screen->widgets.url_l, wf);
658                 widget_move(wh, y, help_x);
659                 y++;
660         }
661
662         wh = widget_label_base(screen->widgets.dns_help_l);
663         layout_pair(screen, y, screen->widgets.dns_l,
664                         widget_textbox_base(screen->widgets.dns_f));
665         widget_move(wh, y, help_x);
666         y++;
667
668         /* we show the DNS/DHCP help if we're configuring DHCP */
669         show = screen->net_conf_type != NET_CONF_TYPE_STATIC;
670         wl = widget_label_base(screen->widgets.dns_dhcp_help_l);
671         widget_set_visible(wl, show);
672         if (show) {
673                 widget_move(wl, y, screen->field_x);
674                 y += 1;
675         }
676
677         wf = widget_textbox_base(screen->widgets.http_proxy_f);
678         layout_pair(screen, y, screen->widgets.http_proxy_l, wf);
679         y++;
680         wf = widget_textbox_base(screen->widgets.https_proxy_f);
681         layout_pair(screen, y, screen->widgets.https_proxy_l, wf);
682         y++;
683
684         y += 1;
685
686         layout_pair(screen, y, screen->widgets.allow_write_l,
687                     widget_select_base(screen->widgets.allow_write_f));
688         y += widget_height(widget_select_base(screen->widgets.allow_write_f));
689
690         y += 1;
691
692         if (screen->widgets.manual_console_l) {
693                 layout_pair(screen, y++, screen->widgets.boot_console_l,
694                         widget_label_base(screen->widgets.manual_console_l));
695                 widget_move(widget_label_base(screen->widgets.current_console_l),
696                         y, screen->field_x);
697                 widget_set_visible(widget_select_base(
698                         screen->widgets.boot_console_f), false);
699                 y += 2;
700         } else if (widget_height(widget_select_base(screen->widgets.boot_console_f))) {
701                 layout_pair(screen, y, screen->widgets.boot_console_l,
702                             widget_select_base(screen->widgets.boot_console_f));
703                 y += widget_height(widget_select_base(screen->widgets.boot_console_f));
704                 widget_move(widget_label_base(screen->widgets.current_console_l),
705                         y, screen->field_x);
706                 y += 2;
707         } else {
708                 widget_set_visible(widget_label_base(
709                                         screen->widgets.boot_console_l), false);
710                 widget_set_visible(widget_select_base(
711                                         screen->widgets.boot_console_f), false);
712                 widget_set_visible(widget_label_base(
713                                         screen->widgets.current_console_l), false);
714         }
715
716 #ifdef CRYPT_SUPPORT
717         widget_move(widget_button_base(screen->widgets.update_password_l),
718                         y, screen->field_x);
719         y += 2;
720 #endif
721
722         if (screen->net_override) {
723                 widget_move(widget_label_base(screen->widgets.net_override_l),
724                                 y, screen->label_x);
725                 widget_set_visible(widget_label_base(screen->widgets.net_override_l),
726                                         true);
727                 y += 1;
728         }
729
730         if (screen->cui->config->safe_mode) {
731                 widget_move(widget_label_base(screen->widgets.safe_mode),
732                         y, screen->label_x);
733                 widget_set_visible(widget_label_base(screen->widgets.safe_mode),
734                                         true);
735                 y += 1;
736         }
737
738         widget_move(widget_button_base(screen->widgets.ok_b),
739                         y, screen->field_x);
740         widget_move(widget_button_base(screen->widgets.help_b),
741                         y, screen->field_x + 14);
742         widget_move(widget_button_base(screen->widgets.cancel_b),
743                         y, screen->field_x + 28);
744 }
745
746 static void config_screen_network_change(void *arg, int value)
747 {
748         struct config_screen *screen = arg;
749         screen->net_conf_type = value;
750         widgetset_unpost(screen->widgetset);
751         config_screen_layout_widgets(screen);
752         widgetset_post(screen->widgetset);
753 }
754
755 static void config_screen_boot_order_change(void *arg, int value)
756 {
757         (void)value;
758         struct config_screen *screen = arg;
759         widgetset_unpost(screen->widgetset);
760         config_screen_layout_widgets(screen);
761         widgetset_post(screen->widgetset);
762 }
763
764 static void config_screen_autoboot_change(void *arg, int value)
765 {
766         struct config_screen *screen = arg;
767         screen->autoboot_enabled = !!value;
768         widgetset_unpost(screen->widgetset);
769         config_screen_layout_widgets(screen);
770         widgetset_post(screen->widgetset);
771 }
772
773 static void config_screen_add_device(void *arg)
774 {
775         struct config_screen *screen = arg;
776
777         cui_show_subset(screen->cui, _("Select a boot device to add"),
778                         screen->widgets.boot_order_f);
779 }
780
781 static void config_screen_autoboot_none(void *arg)
782 {
783         struct config_screen *screen = arg;
784         struct nc_widget_subset *subset = screen->widgets.boot_order_f;
785
786         widget_subset_clear_active(subset);
787
788         widgetset_unpost(screen->widgetset);
789         config_screen_layout_widgets(screen);
790         widgetset_post(screen->widgetset);
791 }
792
793 static void config_screen_autoboot_any(void *arg)
794 {
795         struct config_screen *screen = arg;
796         const struct system_info *sysinfo = screen->cui->sysinfo;
797         struct nc_widget_subset *subset = screen->widgets.boot_order_f;
798         int idx;
799
800         widget_subset_clear_active(subset);
801
802         idx = sysinfo->n_blockdevs + sysinfo->n_interfaces + DEVICE_TYPE_ANY;
803
804         widget_subset_make_active(screen->widgets.boot_order_f, idx);
805
806         screen->autoboot_enabled = true;
807
808         widgetset_unpost(screen->widgetset);
809         config_screen_layout_widgets(screen);
810         widgetset_post(screen->widgetset);
811 }
812
813 static void config_screen_update_subset(void *arg,
814                         struct nc_widget_subset *subset, int idx)
815 {
816         struct config_screen *screen = arg;
817
818         if (idx >= 0)
819                 widget_subset_make_active(subset, idx);
820         if (!screen->autoboot_enabled)
821                 screen->autoboot_enabled = true;
822         config_screen_layout_widgets(screen);
823 }
824
825 static struct interface_config *first_active_interface(
826                 const struct config *config)
827 {
828         unsigned int i;
829
830         for (i = 0; i < config->network.n_interfaces; i++) {
831                 if (config->network.interfaces[i]->ignore)
832                         continue;
833                 return config->network.interfaces[i];
834         }
835         return NULL;
836 }
837
838 static enum net_conf_type find_net_conf_type(const struct config *config)
839 {
840         struct interface_config *ifcfg;
841
842         ifcfg = first_active_interface(config);
843
844         if (!ifcfg)
845                 return NET_CONF_TYPE_DHCP_ALL;
846
847         else if (ifcfg->method == CONFIG_METHOD_DHCP)
848                 return NET_CONF_TYPE_DHCP_ONE;
849
850         else if (ifcfg->method == CONFIG_METHOD_STATIC)
851                 return NET_CONF_TYPE_STATIC;
852
853         assert(0);
854         return NET_CONF_TYPE_DHCP_ALL;
855 }
856
857 static void config_screen_setup_empty(struct config_screen *screen)
858 {
859         widget_new_label(screen->widgetset, 2, screen->field_x,
860                         _("Waiting for configuration data..."));
861         screen->widgets.cancel_b = widget_new_button(screen->widgetset,
862                         4, screen->field_x, 9, _("Cancel"),
863                         cancel_click, screen);
864 }
865
866 static int find_autoboot_idx(const struct system_info *sysinfo,
867                 struct autoboot_option *opt)
868 {
869         unsigned int i;
870
871         if (opt->boot_type == BOOT_DEVICE_TYPE)
872                 return sysinfo->n_blockdevs + sysinfo->n_interfaces + opt->type;
873
874         for (i = 0; i < sysinfo->n_blockdevs; i++) {
875                 if (!strcmp(sysinfo->blockdevs[i]->uuid, opt->uuid))
876                         return i;
877         }
878
879         for (i = 0; i < sysinfo->n_interfaces; i++) {
880                 struct interface_info *info = sysinfo->interfaces[i];
881                 char mac[20];
882
883                 mac_str(info->hwaddr, info->hwaddr_size, mac, sizeof(mac));
884
885                 if (!strcmp(mac, opt->uuid))
886                         return sysinfo->n_blockdevs + i;
887         }
888
889         return -1;
890 }
891
892 static void config_screen_setup_widgets(struct config_screen *screen,
893                 const struct config *config,
894                 const struct system_info *sysinfo)
895 {
896         struct nc_widgetset *set = screen->widgetset;
897         struct interface_config *ifcfg;
898         char *str, *ip, *mask, *gw, *url, *tty, *label;
899         enum net_conf_type type;
900         unsigned int i;
901         int add_len, clear_len, any_len, min_len = 20;
902         bool found;
903
904         build_assert(sizeof(screen->widgets) / sizeof(struct widget *)
905                         == N_FIELDS);
906
907         type = screen->net_conf_type;
908         ifcfg = first_active_interface(config);
909
910         screen->autoboot_enabled = config->autoboot_enabled;
911
912         screen->widgets.autoboot_l = widget_new_label(set, 0, 0,
913                                         _("Autoboot:"));
914         screen->widgets.autoboot_f = widget_new_select(set, 0, 0,
915                                         COLS - screen->field_x - 1);
916
917         widget_select_add_option(screen->widgets.autoboot_f, 0, _("Disabled"),
918                                  !screen->autoboot_enabled);
919         widget_select_add_option(screen->widgets.autoboot_f, 1, _("Enabled"),
920                                  screen->autoboot_enabled);
921
922         widget_select_on_change(screen->widgets.autoboot_f,
923                         config_screen_autoboot_change, screen);
924
925         add_len = max(min_len, strncols(_("Add Device")));
926         clear_len = max(min_len, strncols(_("Clear")));
927         any_len = max(min_len, strncols(_("Clear & Boot Any")));
928
929         screen->widgets.boot_add_b = widget_new_button(set, 0, 0, add_len,
930                                         _("Add Device"),
931                                         config_screen_add_device, screen);
932
933         screen->widgets.boot_none_b = widget_new_button(set, 0, 0, clear_len,
934                                         _("Clear"),
935                                         config_screen_autoboot_none, screen);
936
937         screen->widgets.boot_any_b = widget_new_button(set, 0, 0, any_len,
938                                         _("Clear & Boot Any"),
939                                         config_screen_autoboot_any, screen);
940
941         screen->widgets.boot_order_l = widget_new_label(set, 0, 0,
942                                         _("Boot Order:"));
943         screen->widgets.boot_order_f = widget_new_subset(set, 0, 0,
944                                         COLS - screen->field_x,
945                                         config_screen_update_subset);
946         screen->widgets.boot_empty_l = widget_new_label(set, 0, 0,
947                                         _("(None)"));
948
949         widget_subset_on_change(screen->widgets.boot_order_f,
950                         config_screen_boot_order_change, screen);
951
952         for (i = 0; i < sysinfo->n_blockdevs; i++) {
953                 struct blockdev_info *bd = sysinfo->blockdevs[i];
954
955                 label = talloc_asprintf(screen, _("disk: %s [uuid: %s]"),
956                                 bd->name, bd->uuid);
957
958                 widget_subset_add_option(screen->widgets.boot_order_f, label);
959         }
960
961         for (i = 0; i < sysinfo->n_interfaces; i++) {
962                 struct interface_info *info = sysinfo->interfaces[i];
963                 char mac[20];
964
965                 mac_str(info->hwaddr, info->hwaddr_size, mac, sizeof(mac));
966
967                 label = talloc_asprintf(screen, _("net:  %s [mac: %s]"),
968                                 info->name, mac);
969
970                 widget_subset_add_option(screen->widgets.boot_order_f, label);
971         }
972
973         for (i = DEVICE_TYPE_NETWORK; i < DEVICE_TYPE_UNKNOWN; i++) {
974
975                 if (i == DEVICE_TYPE_ANY)
976                         label = talloc_asprintf(screen, _("Any Device"));
977                 else
978                         label = talloc_asprintf(screen, _("Any %s device"),
979                                                 device_type_display_name(i));
980
981                 widget_subset_add_option(screen->widgets.boot_order_f, label);
982         }
983
984         for (i = 0; i < config->n_autoboot_opts; i++) {
985                 struct autoboot_option *opt = &config->autoboot_opts[i];
986                 int idx;
987
988                 idx = find_autoboot_idx(sysinfo, opt);
989
990                 if (idx >= 0) {
991                         widget_subset_make_active(screen->widgets.boot_order_f,
992                                                   idx);
993                 } else {
994                         if (opt->boot_type == BOOT_DEVICE_TYPE)
995                                 pb_log("%s: Unknown autoboot option: %d\n",
996                                        __func__, opt->type);
997                         else
998                                 pb_log("%s: Unknown autoboot UUID: %s\n",
999                                        __func__, opt->uuid);
1000                 }
1001         }
1002
1003
1004         str = talloc_asprintf(screen, "%d", config->autoboot_timeout_sec);
1005         screen->widgets.timeout_l = widget_new_label(set, 0, 0, _("Timeout:"));
1006         screen->widgets.timeout_f = widget_new_textbox(set, 0, 0, 5, str);
1007         screen->widgets.timeout_help_l = widget_new_label(set, 0, 0,
1008                                         _("seconds"));
1009
1010         widget_textbox_set_fixed_size(screen->widgets.timeout_f);
1011         widget_textbox_set_validator_integer(screen->widgets.timeout_f, 0, 999);
1012
1013         if (config->ipmi_bootdev) {
1014                 label = talloc_asprintf(screen,
1015                                 _("%s IPMI boot option: %s"),
1016                                 config->ipmi_bootdev_persistent ?
1017                                 _("Persistent") : _("Temporary"),
1018                                 ipmi_bootdev_display_name(config->ipmi_bootdev));
1019                 screen->widgets.ipmi_type_l = widget_new_label(set, 0, 0,
1020                                                         label);
1021                 screen->widgets.ipmi_clear_l = widget_new_label(set, 0, 0,
1022                                                         _("Clear option:"));
1023                 screen->widgets.ipmi_clear_b = widget_new_button(set, 0, 0,
1024                                 strncols(_("Clear IPMI override now")) + 10,
1025                                 _("Clear IPMI override now"),
1026                                 ipmi_clear_click, screen);
1027                 screen->ipmi_override = true;
1028         }
1029
1030         if (config->ipmi_bootdev_mailbox) {
1031                 screen->widgets.ipmi_mailbox_l = widget_new_label(set, 0, 0,
1032                                 _("IPMI boot order mailbox config present"));
1033                 screen->widgets.ipmi_mailbox_b = widget_new_button(set, 0, 0,
1034                                 strncols(_("Clear IPMI boot order mailbox now")) + 10,
1035                                 _("Clear IPMI boot order mailbox now"),
1036                                 ipmi_clear_mailbox_click, screen);
1037                 screen->ipmi_mailbox = true;
1038         }
1039
1040         screen->widgets.network_l = widget_new_label(set, 0, 0, _("Network:"));
1041         screen->widgets.network_f = widget_new_select(set, 0, 0,
1042                                                 COLS - screen->field_x - 1);
1043
1044         widget_select_add_option(screen->widgets.network_f,
1045                                         NET_CONF_TYPE_DHCP_ALL,
1046                                         _("DHCP on all active interfaces"),
1047                                         type == NET_CONF_TYPE_DHCP_ALL);
1048         widget_select_add_option(screen->widgets.network_f,
1049                                         NET_CONF_TYPE_DHCP_ONE,
1050                                         _("DHCP on a specific interface"),
1051                                         type == NET_CONF_TYPE_DHCP_ONE);
1052         widget_select_add_option(screen->widgets.network_f,
1053                                         NET_CONF_TYPE_STATIC,
1054                                         _("Static IP configuration"),
1055                                         type == NET_CONF_TYPE_STATIC);
1056
1057         widget_select_on_change(screen->widgets.network_f,
1058                         config_screen_network_change, screen);
1059
1060         screen->widgets.iface_l = widget_new_label(set, 0, 0, _("Device:"));
1061         screen->widgets.iface_f = widget_new_select(set, 0, 0, 50);
1062
1063         for (i = 0; i < sysinfo->n_interfaces; i++) {
1064                 struct interface_info *info = sysinfo->interfaces[i];
1065                 char str[50], mac[20];
1066                 bool is_default;
1067
1068                 is_default = ifcfg && !memcmp(ifcfg->hwaddr, info->hwaddr,
1069                                         sizeof(ifcfg->hwaddr));
1070
1071                 mac_str(info->hwaddr, info->hwaddr_size, mac, sizeof(mac));
1072                 snprintf(str, sizeof(str), "%s [%s, %s]", info->name, mac,
1073                                 info->link ? _("link up") : _("link down"));
1074
1075                 widget_select_add_option(screen->widgets.iface_f,
1076                                                 i, str, is_default);
1077         }
1078
1079         url = gw = ip = mask = NULL;
1080         if (ifcfg && ifcfg->method == CONFIG_METHOD_STATIC) {
1081                 char *sep;
1082
1083                 str = talloc_strdup(screen, ifcfg->static_config.address);
1084                 sep = strchr(str, '/');
1085                 ip = str;
1086
1087                 if (sep) {
1088                         *sep = '\0';
1089                         mask = sep + 1;
1090                 }
1091                 gw = ifcfg->static_config.gateway;
1092                 url = ifcfg->static_config.url;
1093         }
1094
1095         screen->net_override = ifcfg && ifcfg->override;
1096         if (screen->net_override) {
1097                 screen->widgets.net_override_l = widget_new_label(set, 0, 0,
1098                         _("Network Override Active! 'OK' will overwrite interface config"));
1099         }
1100
1101         screen->widgets.ip_addr_l = widget_new_label(set, 0, 0, _("IP/mask:"));
1102         screen->widgets.ip_addr_f = widget_new_textbox(set, 0, 0, 16, ip);
1103         screen->widgets.ip_mask_l = widget_new_label(set, 0, 0, "/");
1104         screen->widgets.ip_mask_f = widget_new_textbox(set, 0, 0, 3, mask);
1105         screen->widgets.ip_addr_mask_help_l =
1106                 widget_new_label(set, 0, 0, _("(eg. 192.168.0.10 / 24)"));
1107
1108         widget_textbox_set_fixed_size(screen->widgets.ip_addr_f);
1109         widget_textbox_set_fixed_size(screen->widgets.ip_mask_f);
1110         widget_textbox_set_validator_ip(screen->widgets.ip_addr_f);
1111         widget_textbox_set_validator_integer(screen->widgets.ip_mask_f, 1, 127);
1112
1113         screen->widgets.gateway_l = widget_new_label(set, 0, 0, _("Gateway:"));
1114         screen->widgets.gateway_f = widget_new_textbox(set, 0, 0, 16, gw);
1115         screen->widgets.gateway_help_l =
1116                 widget_new_label(set, 0, 0, _("(eg. 192.168.0.1)"));
1117
1118         widget_textbox_set_fixed_size(screen->widgets.gateway_f);
1119         widget_textbox_set_validator_ip(screen->widgets.gateway_f);
1120
1121         screen->widgets.url_l = widget_new_label(set, 0, 0, _("URL:"));
1122         screen->widgets.url_f = widget_new_textbox(set, 0, 0, 32, url);
1123         widget_textbox_set_validator_url(screen->widgets.url_f);
1124         screen->widgets.url_help_l =
1125                 widget_new_label(set, 0, 0, _("(eg. tftp://)"));
1126
1127         str = talloc_strdup(screen, "");
1128         for (i = 0; i < config->network.n_dns_servers; i++) {
1129                 str = talloc_asprintf_append(str, "%s%s",
1130                                 (i == 0) ? "" : " ",
1131                                 config->network.dns_servers[i]);
1132         }
1133
1134         screen->widgets.dns_l = widget_new_label(set, 0, 0,
1135                                         _("DNS Server(s):"));
1136         screen->widgets.dns_f = widget_new_textbox(set, 0, 0, 32, str);
1137         screen->widgets.dns_help_l =
1138                 widget_new_label(set, 0, 0, _("(eg. 192.168.0.2)"));
1139
1140         widget_textbox_set_validator_ip_multi(screen->widgets.dns_f);
1141
1142         screen->widgets.dns_dhcp_help_l = widget_new_label(set, 0, 0,
1143                         _("(if not provided by DHCP server)"));
1144
1145         screen->widgets.http_proxy_l = widget_new_label(set, 0, 0,
1146                                         _("HTTP Proxy:"));
1147         screen->widgets.http_proxy_f = widget_new_textbox(set, 0, 0, 32,
1148                                                 config->http_proxy);
1149         screen->widgets.https_proxy_l = widget_new_label(set, 0, 0,
1150                                         _("HTTPS Proxy:"));
1151         screen->widgets.https_proxy_f = widget_new_textbox(set, 0, 0, 32,
1152                                                 config->https_proxy);
1153
1154         if (config->safe_mode)
1155                 screen->widgets.safe_mode = widget_new_label(set, 0, 0,
1156                          _("Selecting 'OK' will exit safe mode"));
1157
1158         screen->widgets.allow_write_l = widget_new_label(set, 0, 0,
1159                         _("Disk R/W:"));
1160         screen->widgets.allow_write_f = widget_new_select(set, 0, 0,
1161                                                 COLS - screen->field_x - 1);
1162
1163         widget_select_add_option(screen->widgets.allow_write_f, 0,
1164                                 _("Prevent all writes to disk"),
1165                                 !config->allow_writes);
1166
1167         widget_select_add_option(screen->widgets.allow_write_f, 1,
1168                                 _("Allow bootloader scripts to modify disks"),
1169                                 config->allow_writes);
1170
1171         screen->widgets.boot_console_l = widget_new_label(set, 0, 0,
1172                         _("Boot console:"));
1173         screen->widgets.boot_console_f = widget_new_select(set, 0, 0,
1174                                                 COLS - screen->field_x - 1);
1175
1176         for (i = 0; i < config->n_consoles; i++){
1177                 found = config->boot_console &&
1178                         strncmp(config->boot_console, config->consoles[i],
1179                                 strlen(config->boot_console)) == 0;
1180                 widget_select_add_option(screen->widgets.boot_console_f, i,
1181                                         config->consoles[i], found);
1182         }
1183
1184         if (config->manual_console) {
1185                 label = talloc_asprintf(screen, _("Manually set: '%s'"),
1186                                         config->boot_console);
1187                 screen->widgets.manual_console_l = widget_new_label(set, 0, 0, label);
1188         }
1189
1190         tty = talloc_asprintf(screen, _("Current interface: %s"),
1191                                 ttyname(STDIN_FILENO));
1192         screen->widgets.current_console_l = widget_new_label(set, 0 , 0, tty);
1193
1194 #ifdef CRYPT_SUPPORT
1195         screen->widgets.update_password_l = widget_new_button(set, 0, 0, 30,
1196                         _("Update system password"), password_click, screen);
1197 #endif
1198
1199         screen->widgets.ok_b = widget_new_button(set, 0, 0, 10, _("OK"),
1200                         ok_click, screen);
1201         screen->widgets.help_b = widget_new_button(set, 0, 0, 10, _("Help"),
1202                         help_click, screen);
1203         screen->widgets.cancel_b = widget_new_button(set, 0, 0, 10, _("Cancel"),
1204                         cancel_click, screen);
1205 }
1206
1207 static void config_screen_widget_focus(struct nc_widget *widget, void *arg)
1208 {
1209         struct config_screen *screen = arg;
1210         int w_y, w_height, w_focus, s_max, adjust;
1211
1212         w_height = widget_height(widget);
1213         w_focus = widget_focus_y(widget);
1214         w_y = widget_y(widget) + w_focus;
1215         s_max = getmaxy(screen->scr.sub_ncw) - 1;
1216
1217         if (w_y < screen->scroll_y)
1218                 screen->scroll_y = w_y;
1219
1220         else if (w_y + screen->scroll_y + 1 > s_max) {
1221                 /* Fit as much of the widget into the screen as possible */
1222                 adjust = min(s_max - 1, w_height - w_focus);
1223                 if (w_y + adjust >= screen->scroll_y + s_max)
1224                         screen->scroll_y = max(0, 1 + w_y + adjust - s_max);
1225         } else
1226                 return;
1227
1228         pad_refresh(screen);
1229 }
1230
1231 static void config_screen_draw(struct config_screen *screen,
1232                 const struct config *config,
1233                 const struct system_info *sysinfo)
1234 {
1235         bool repost = false;
1236         int height;
1237
1238         /* The size of the pad we'll need depends on the number of interfaces.
1239          *
1240          * We use N_FIELDS (which is quite conservative, as some fields share
1241          * a line) as a base, then:
1242          * - add 6 (as the network select & boot device select fields take 3
1243          *   lines each),
1244          * - add n_interfaces for every field in the network select field, and
1245          * - add (n_blockdevs + n_interfaces) for every field in the boot device
1246          *   select field
1247          */
1248         height = N_FIELDS + 6;
1249         if (sysinfo) {
1250                 height += sysinfo->n_interfaces;
1251                 height += (sysinfo->n_blockdevs + sysinfo->n_interfaces);
1252         }
1253         if (!screen->pad || getmaxy(screen->pad) < height) {
1254                 if (screen->pad)
1255                         delwin(screen->pad);
1256                 screen->pad = newpad(height, COLS + 10);
1257         }
1258
1259         if (screen->widgetset) {
1260                 widgetset_unpost(screen->widgetset);
1261                 talloc_free(screen->widgetset);
1262                 repost = true;
1263         }
1264
1265         screen->widgetset = widgetset_create(screen, screen->scr.main_ncw,
1266                         screen->pad);
1267         widgetset_set_widget_focus(screen->widgetset,
1268                         config_screen_widget_focus, screen);
1269
1270         if (!config || !sysinfo) {
1271                 config_screen_setup_empty(screen);
1272         } else {
1273                 screen->net_conf_type = find_net_conf_type(config);
1274                 config_screen_setup_widgets(screen, config, sysinfo);
1275                 config_screen_layout_widgets(screen);
1276         }
1277
1278         if (repost)
1279                 widgetset_post(screen->widgetset);
1280 }
1281
1282 void config_screen_update(struct config_screen *screen,
1283                 const struct config *config,
1284                 const struct system_info *sysinfo)
1285 {
1286         if (screen->cui->current != config_screen_scr(screen)) {
1287                 screen->need_update = true;
1288                 return;
1289         }
1290
1291         config_screen_draw(screen, config, sysinfo);
1292         pad_refresh(screen);
1293 }
1294
1295 static int config_screen_post(struct nc_scr *scr)
1296 {
1297         struct config_screen *screen = config_screen_from_scr(scr);
1298
1299         /* We may have been posted after an auth action completed */
1300         if (screen->exit) {
1301                 screen->on_exit(screen->cui);
1302                 return 0;
1303         }
1304
1305         if (screen->need_update) {
1306                 config_screen_draw(screen, screen->cui->config,
1307                                    screen->cui->sysinfo);
1308                 screen->need_update = false;
1309         } else {
1310                 widgetset_post(screen->widgetset);
1311         }
1312
1313         nc_scr_frame_draw(scr);
1314         if (screen->need_redraw) {
1315                 redrawwin(scr->main_ncw);
1316                 screen->need_redraw = false;
1317         }
1318         wrefresh(screen->scr.main_ncw);
1319         pad_refresh(screen);
1320         return 0;
1321 }
1322
1323 static int config_screen_destroy(void *arg)
1324 {
1325         struct config_screen *screen = arg;
1326         if (screen->pad)
1327                 delwin(screen->pad);
1328         return 0;
1329 }
1330
1331 struct config_screen *config_screen_init(struct cui *cui,
1332                 const struct config *config,
1333                 const struct system_info *sysinfo,
1334                 void (*on_exit)(struct cui *))
1335 {
1336         struct config_screen *screen;
1337
1338         screen = talloc_zero(cui, struct config_screen);
1339         talloc_set_destructor(screen, config_screen_destroy);
1340         nc_scr_init(&screen->scr, pb_config_screen_sig, 0,
1341                         cui, config_screen_process_key,
1342                         config_screen_post, config_screen_unpost,
1343                         config_screen_resize);
1344
1345         screen->cui = cui;
1346         screen->on_exit = on_exit;
1347         screen->need_redraw = false;
1348         screen->need_update = false;
1349         screen->label_x = 2;
1350         screen->field_x = 17;
1351
1352         screen->ipmi_override = false;
1353
1354         screen->scr.frame.ltitle = talloc_strdup(screen,
1355                         _("Petitboot System Configuration"));
1356         screen->scr.frame.rtitle = NULL;
1357         screen->scr.frame.help = talloc_strdup(screen,
1358                         _("tab=next, shift+tab=previous, x=exit, h=help"));
1359         nc_scr_frame_draw(&screen->scr);
1360
1361         scrollok(screen->scr.sub_ncw, true);
1362
1363         config_screen_draw(screen, config, sysinfo);
1364
1365         return screen;
1366 }