]> git.ozlabs.org Git - petitboot/blob - ui/ncurses/nc-config.c
ui/ncurses: Exit safe mode on configuration change
[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 "nc-cui.h"
33 #include "nc-config.h"
34 #include "nc-widgets.h"
35
36 #define N_FIELDS        26
37
38 extern struct help_text config_help_text;
39
40 enum autoboot_type {
41         AUTOBOOT_ANY,
42         AUTOBOOT_ONE,
43         AUTOBOOT_DISABLED,
44 };
45
46 enum net_conf_type {
47         NET_CONF_TYPE_DHCP_ALL,
48         NET_CONF_TYPE_DHCP_ONE,
49         NET_CONF_TYPE_STATIC,
50 };
51
52 struct config_screen {
53         struct nc_scr           scr;
54         struct cui              *cui;
55         struct nc_widgetset     *widgetset;
56         WINDOW                  *pad;
57
58         bool                    exit;
59         bool                    show_help;
60         void                    (*on_exit)(struct cui *);
61
62         int                     scroll_y;
63
64         int                     label_x;
65         int                     field_x;
66         int                     network_config_y;
67
68         enum net_conf_type      net_conf_type;
69         enum autoboot_type      autoboot_type;
70
71         struct {
72                 struct nc_widget_select         *autoboot_f;
73                 struct nc_widget_label          *autoboot_l;
74                 struct nc_widget_select         *boot_device_f;
75                 struct nc_widget_textbox        *timeout_f;
76                 struct nc_widget_label          *timeout_l;
77                 struct nc_widget_label          *timeout_help_l;
78
79                 struct nc_widget_label          *network_l;
80                 struct nc_widget_select         *network_f;
81
82                 struct nc_widget_label          *iface_l;
83                 struct nc_widget_select         *iface_f;
84                 struct nc_widget_label          *ip_addr_l;
85                 struct nc_widget_textbox        *ip_addr_f;
86                 struct nc_widget_label          *ip_mask_l;
87                 struct nc_widget_textbox        *ip_mask_f;
88                 struct nc_widget_label          *ip_addr_mask_help_l;
89                 struct nc_widget_label          *gateway_l;
90                 struct nc_widget_textbox        *gateway_f;
91                 struct nc_widget_label          *gateway_help_l;
92                 struct nc_widget_label          *dns_l;
93                 struct nc_widget_textbox        *dns_f;
94                 struct nc_widget_label          *dns_dhcp_help_l;
95                 struct nc_widget_label          *dns_help_l;
96
97                 struct nc_widget_label          *safe_mode;
98                 struct nc_widget_button         *ok_b;
99                 struct nc_widget_button         *help_b;
100                 struct nc_widget_button         *cancel_b;
101         } widgets;
102 };
103
104 static struct config_screen *config_screen_from_scr(struct nc_scr *scr)
105 {
106         struct config_screen *config_screen;
107
108         assert(scr->sig == pb_config_screen_sig);
109         config_screen = (struct config_screen *)
110                 ((char *)scr - (size_t)&((struct config_screen *)0)->scr);
111         assert(config_screen->scr.sig == pb_config_screen_sig);
112         return config_screen;
113 }
114
115 static void pad_refresh(struct config_screen *screen)
116 {
117         int y, x, rows, cols;
118
119         getmaxyx(screen->scr.sub_ncw, rows, cols);
120         getbegyx(screen->scr.sub_ncw, y, x);
121
122         prefresh(screen->pad, screen->scroll_y, 0, y, x, rows, cols);
123 }
124
125 static void config_screen_process_key(struct nc_scr *scr, int key)
126 {
127         struct config_screen *screen = config_screen_from_scr(scr);
128         bool handled;
129
130         handled = widgetset_process_key(screen->widgetset, key);
131
132         if (!handled) {
133                 switch (key) {
134                 case 'x':
135                 case 27: /* esc */
136                         screen->exit = true;
137                         break;
138                 case 'h':
139                         screen->show_help = true;
140                         break;
141                 }
142         }
143
144         if (screen->exit) {
145                 screen->on_exit(screen->cui);
146
147         } else if (screen->show_help) {
148                 screen->show_help = false;
149                 cui_show_help(screen->cui, _("System Configuration"),
150                                 &config_help_text);
151
152         } else if (handled) {
153                 pad_refresh(screen);
154         }
155 }
156
157 static void config_screen_resize(struct nc_scr *scr)
158 {
159         struct config_screen *screen = config_screen_from_scr(scr);
160         (void)screen;
161 }
162
163 static int config_screen_post(struct nc_scr *scr)
164 {
165         struct config_screen *screen = config_screen_from_scr(scr);
166         widgetset_post(screen->widgetset);
167         nc_scr_frame_draw(scr);
168         redrawwin(scr->main_ncw);
169         wrefresh(screen->scr.main_ncw);
170         pad_refresh(screen);
171         return 0;
172 }
173
174 static int config_screen_unpost(struct nc_scr *scr)
175 {
176         struct config_screen *screen = config_screen_from_scr(scr);
177         widgetset_unpost(screen->widgetset);
178         return 0;
179 }
180
181 struct nc_scr *config_screen_scr(struct config_screen *screen)
182 {
183         return &screen->scr;
184 }
185
186 static int screen_process_form(struct config_screen *screen)
187 {
188         const struct system_info *sysinfo = screen->cui->sysinfo;
189         enum net_conf_type net_conf_type;
190         struct interface_config *iface;
191         struct config *config;
192         char *str, *end;
193         int rc, idx;
194
195         config = config_copy(screen, screen->cui->config);
196
197         screen->autoboot_type =
198                 widget_select_get_value(screen->widgets.autoboot_f);
199
200         config->autoboot_enabled = screen->autoboot_type != AUTOBOOT_DISABLED;
201
202         if (screen->autoboot_type == AUTOBOOT_ONE) {
203                 char mac[20], *uuid = NULL;
204
205                 /* if idx is -1 here, we have an unknown UUID selected.
206                  * Otherwise, it's a blockdev index (idx <= n_blockdevs) or an
207                  * interface index.
208                  */
209                 idx = widget_select_get_value(screen->widgets.boot_device_f);
210                 if (idx >= (int)sysinfo->n_blockdevs) {
211                         struct interface_info *info = sysinfo->
212                                 interfaces[idx - sysinfo->n_blockdevs];
213                         mac_str(info->hwaddr, info->hwaddr_size,
214                                         mac, sizeof(mac));
215                         uuid = mac;
216                 } else if (idx != -1) {
217                         uuid = sysinfo->blockdevs[idx]->uuid;
218                 }
219
220                 if (uuid) {
221                         talloc_free(config->boot_device);
222                         config->boot_device = talloc_strdup(config, uuid);
223                 }
224         }
225
226         str = widget_textbox_get_value(screen->widgets.timeout_f);
227         if (str) {
228                 unsigned long x;
229                 errno = 0;
230                 x = strtoul(str, &end, 10);
231                 if (!errno && end != str)
232                         config->autoboot_timeout_sec = x;
233         }
234
235         net_conf_type = widget_select_get_value(screen->widgets.network_f);
236
237         /* if we don't have any network interfaces, prevent per-interface
238          * configuration */
239         if (sysinfo->n_interfaces == 0)
240                 net_conf_type = NET_CONF_TYPE_DHCP_ALL;
241
242         if (net_conf_type == NET_CONF_TYPE_DHCP_ALL) {
243                 config->network.n_interfaces = 0;
244
245         } else {
246                 iface = talloc_zero(config, struct interface_config);
247                 config->network.n_interfaces = 1;
248                 config->network.interfaces = talloc_array(config,
249                                 struct interface_config *, 1);
250                 config->network.interfaces[0] = iface;
251
252                 /* copy hwaddr (from the sysinfo interface data) to
253                  * the configuration */
254                 idx = widget_select_get_value(screen->widgets.iface_f);
255                 memcpy(iface->hwaddr, sysinfo->interfaces[idx]->hwaddr,
256                                 sizeof(iface->hwaddr));
257         }
258
259         if (net_conf_type == NET_CONF_TYPE_DHCP_ONE) {
260                 iface->method = CONFIG_METHOD_DHCP;
261         }
262
263         if (net_conf_type == NET_CONF_TYPE_STATIC) {
264                 char *ip, *mask, *gateway;
265
266                 ip = widget_textbox_get_value(screen->widgets.ip_addr_f);
267                 mask = widget_textbox_get_value(screen->widgets.ip_mask_f);
268                 gateway = widget_textbox_get_value(screen->widgets.gateway_f);
269
270                 if (!ip || !*ip || !mask || !*mask) {
271                         screen->scr.frame.status =
272                                 _("No IP / mask values are set");
273                         nc_scr_frame_draw(&screen->scr);
274                         talloc_free(config);
275                         return -1;
276                 }
277
278                 iface->method = CONFIG_METHOD_STATIC;
279                 iface->static_config.address = talloc_asprintf(iface, "%s/%s",
280                                 ip, mask);
281                 iface->static_config.gateway = talloc_strdup(iface, gateway);
282         }
283
284         str = widget_textbox_get_value(screen->widgets.dns_f);
285         talloc_free(config->network.dns_servers);
286         config->network.dns_servers = NULL;
287         config->network.n_dns_servers = 0;
288
289         if (str && strlen(str)) {
290                 char *dns, *tmp;
291                 int i;
292
293                 for (;;) {
294                         dns = strtok_r(str, " \t", &tmp);
295
296                         if (!dns)
297                                 break;
298
299                         i = config->network.n_dns_servers++;
300                         config->network.dns_servers = talloc_realloc(config,
301                                         config->network.dns_servers,
302                                         const char *,
303                                         config->network.n_dns_servers);
304                         config->network.dns_servers[i] =
305                                 talloc_strdup(config, dns);
306
307                         str = NULL;
308                 }
309         }
310
311         config->safe_mode = false;
312         rc = cui_send_config(screen->cui, config);
313         talloc_free(config);
314
315         if (rc)
316                 pb_log("cui_send_config failed!\n");
317         else
318                 pb_debug("config sent!\n");
319
320         return 0;
321 }
322
323 static void ok_click(void *arg)
324 {
325         struct config_screen *screen = arg;
326         if (screen_process_form(screen))
327                 /* errors are written to the status line, so we'll need
328                  * to refresh */
329                 wrefresh(screen->scr.main_ncw);
330         else
331                 screen->exit = true;
332 }
333
334 static void help_click(void *arg)
335 {
336         struct config_screen *screen = arg;
337         screen->show_help = true;
338 }
339
340 static void cancel_click(void *arg)
341 {
342         struct config_screen *screen = arg;
343         screen->exit = true;
344 }
345
346 static int layout_pair(struct config_screen *screen, int y,
347                 struct nc_widget_label *label,
348                 struct nc_widget *field)
349 {
350         struct nc_widget *label_w = widget_label_base(label);
351         widget_move(label_w, y, screen->label_x);
352         widget_move(field, y, screen->field_x);
353         return max(widget_height(label_w), widget_height(field));
354 }
355
356 static void config_screen_layout_widgets(struct config_screen *screen)
357 {
358         struct nc_widget *wl, *wf, *wh;
359         int y, x, help_x;
360         bool show;
361
362         y = 1;
363         help_x = screen->field_x + 2 +
364                 widget_width(widget_textbox_base(screen->widgets.dns_f));
365
366         y += layout_pair(screen, y, screen->widgets.autoboot_l,
367                         widget_select_base(screen->widgets.autoboot_f));
368
369         wf = widget_select_base(screen->widgets.boot_device_f);
370         if (screen->autoboot_type == AUTOBOOT_ONE) {
371                 widget_set_visible(wf, true);
372                 widget_move(wf, y, screen->field_x + 3);
373                 y += widget_height(wf);
374         } else {
375                 widget_set_visible(wf, false);
376         }
377
378         y += 1;
379
380         wf = widget_textbox_base(screen->widgets.timeout_f);
381         wl = widget_label_base(screen->widgets.timeout_l);
382         wh = widget_label_base(screen->widgets.timeout_help_l);
383         if (screen->autoboot_type != AUTOBOOT_DISABLED) {
384                 widget_set_visible(wl, true);
385                 widget_set_visible(wf, true);
386                 widget_set_visible(wh, true);
387                 widget_move(wl, y, screen->label_x);
388                 widget_move(wf, y, screen->field_x);
389                 widget_move(wh, y, screen->field_x + widget_width(wf) + 1);
390                 y += 2;
391         } else {
392                 widget_set_visible(wl, false);
393                 widget_set_visible(wf, false);
394                 widget_set_visible(wh, false);
395         }
396
397         y += layout_pair(screen, y, screen->widgets.network_l,
398                         widget_select_base(screen->widgets.network_f));
399
400         y += 1;
401
402         /* conditionally show iface select */
403         wl = widget_label_base(screen->widgets.iface_l);
404         wf = widget_select_base(screen->widgets.iface_f);
405
406         show = screen->net_conf_type == NET_CONF_TYPE_DHCP_ONE ||
407                 screen->net_conf_type == NET_CONF_TYPE_STATIC;
408
409         widget_set_visible(wl, show);
410         widget_set_visible(wf, show);
411
412         if (show)
413                 y += layout_pair(screen, y, screen->widgets.iface_l, wf) + 1;
414
415         /* conditionally show static IP params */
416         show = screen->net_conf_type == NET_CONF_TYPE_STATIC;
417
418         wl = widget_label_base(screen->widgets.ip_addr_l);
419         wf = widget_textbox_base(screen->widgets.ip_addr_f);
420         widget_set_visible(wl, show);
421         widget_set_visible(wf, show);
422         x = screen->field_x + widget_width(wf) + 1;
423
424         if (show)
425                 layout_pair(screen, y, screen->widgets.ip_addr_l, wf);
426
427         wl = widget_label_base(screen->widgets.ip_mask_l);
428         wf = widget_textbox_base(screen->widgets.ip_mask_f);
429         widget_set_visible(wl, show);
430         widget_set_visible(wf, show);
431
432         if (show) {
433                 widget_move(wl, y, x);
434                 widget_move(wf, y, x + 2);
435         }
436
437         /* help for IP/mask */
438         wh = widget_label_base(screen->widgets.ip_addr_mask_help_l);
439         widget_set_visible(wh, show);
440         if (show) {
441                 widget_move(wh, y, help_x);
442                 y++;
443         }
444
445         wl = widget_label_base(screen->widgets.gateway_l);
446         wf = widget_textbox_base(screen->widgets.gateway_f);
447         wh = widget_label_base(screen->widgets.gateway_help_l);
448         widget_set_visible(wl, show);
449         widget_set_visible(wf, show);
450         widget_set_visible(wh, show);
451
452         if (show) {
453                 layout_pair(screen, y, screen->widgets.gateway_l, wf);
454                 widget_move(wh, y, help_x);
455                 y++;
456         }
457
458         wh = widget_label_base(screen->widgets.dns_help_l);
459         layout_pair(screen, y, screen->widgets.dns_l,
460                         widget_textbox_base(screen->widgets.dns_f));
461         widget_move(wh, y, help_x);
462         y++;
463
464         /* we show the DNS/DHCP help if we're configuring DHCP */
465         show = screen->net_conf_type != NET_CONF_TYPE_STATIC;
466         wl = widget_label_base(screen->widgets.dns_dhcp_help_l);
467         widget_set_visible(wl, show);
468         if (show) {
469                 widget_move(wl, y, screen->field_x);
470                 y += 1;
471         }
472
473         y += 1;
474
475         show = screen->cui->config->safe_mode;
476         if (show) {
477                 widget_move(widget_label_base(screen->widgets.safe_mode),
478                         y, screen->field_x);
479                 y += 1;
480         }
481
482         widget_move(widget_button_base(screen->widgets.ok_b),
483                         y, screen->field_x);
484         widget_move(widget_button_base(screen->widgets.help_b),
485                         y, screen->field_x + 10);
486         widget_move(widget_button_base(screen->widgets.cancel_b),
487                         y, screen->field_x + 20);
488 }
489
490 static void config_screen_network_change(void *arg, int value)
491 {
492         struct config_screen *screen = arg;
493         screen->net_conf_type = value;
494         widgetset_unpost(screen->widgetset);
495         config_screen_layout_widgets(screen);
496         widgetset_post(screen->widgetset);
497 }
498
499 static void config_screen_autoboot_change(void *arg, int value)
500 {
501         struct config_screen *screen = arg;
502         screen->autoboot_type = value;
503         widgetset_unpost(screen->widgetset);
504         config_screen_layout_widgets(screen);
505         widgetset_post(screen->widgetset);
506 }
507
508 static struct interface_config *first_active_interface(
509                 const struct config *config)
510 {
511         unsigned int i;
512
513         for (i = 0; i < config->network.n_interfaces; i++) {
514                 if (config->network.interfaces[i]->ignore)
515                         continue;
516                 return config->network.interfaces[i];
517         }
518         return NULL;
519 }
520
521 static enum net_conf_type find_net_conf_type(const struct config *config)
522 {
523         struct interface_config *ifcfg;
524
525         ifcfg = first_active_interface(config);
526
527         if (!ifcfg)
528                 return NET_CONF_TYPE_DHCP_ALL;
529
530         else if (ifcfg->method == CONFIG_METHOD_DHCP)
531                 return NET_CONF_TYPE_DHCP_ONE;
532
533         else if (ifcfg->method == CONFIG_METHOD_STATIC)
534                 return NET_CONF_TYPE_STATIC;
535
536         assert(0);
537         return NET_CONF_TYPE_DHCP_ALL;
538 }
539
540 static void config_screen_setup_empty(struct config_screen *screen)
541 {
542         widget_new_label(screen->widgetset, 2, screen->field_x,
543                         _("Waiting for configuration data..."));
544         screen->widgets.cancel_b = widget_new_button(screen->widgetset,
545                         4, screen->field_x, 6, _("Cancel"),
546                         cancel_click, screen);
547 }
548
549
550 static void config_screen_setup_widgets(struct config_screen *screen,
551                 const struct config *config,
552                 const struct system_info *sysinfo)
553 {
554         struct nc_widgetset *set = screen->widgetset;
555         struct interface_config *ifcfg;
556         char *str, *ip, *mask, *gw;
557         enum net_conf_type type;
558         unsigned int i;
559         bool found;
560
561         build_assert(sizeof(screen->widgets) / sizeof(struct widget *)
562                         == N_FIELDS);
563
564         type = screen->net_conf_type;
565         ifcfg = first_active_interface(config);
566
567         screen->widgets.autoboot_l = widget_new_label(set, 0, 0,
568                                         _("Autoboot:"));
569         screen->widgets.autoboot_f = widget_new_select(set, 0, 0, 55);
570
571         widget_select_on_change(screen->widgets.autoboot_f,
572                         config_screen_autoboot_change, screen);
573
574         screen->widgets.boot_device_f = widget_new_select(set, 0, 0, 55);
575
576         widget_select_add_option(screen->widgets.autoboot_f,
577                                         AUTOBOOT_DISABLED,
578                                         _("Don't autoboot"),
579                                         screen->autoboot_type ==
580                                                 AUTOBOOT_DISABLED);
581         widget_select_add_option(screen->widgets.autoboot_f,
582                                         AUTOBOOT_ANY,
583                                         _("Autoboot from any "
584                                                 "disk/network device"),
585                                         screen->autoboot_type ==
586                                                 AUTOBOOT_ANY);
587         widget_select_add_option(screen->widgets.autoboot_f,
588                                         AUTOBOOT_ONE,
589                                         _("Only autoboot from a specific "
590                                                 "disk/network device"),
591                                         screen->autoboot_type ==
592                                                 AUTOBOOT_ONE);
593
594         found = false;
595
596         for (i = 0; i < sysinfo->n_blockdevs; i++) {
597                 struct blockdev_info *bd = sysinfo->blockdevs[i];
598                 bool selected;
599                 char *label;
600
601                 selected = config->boot_device &&
602                                 !strcmp(config->boot_device, bd->uuid);
603                 if (selected)
604                         found = true;
605
606                 label = talloc_asprintf(screen, _("disk: %s [uuid: %s]"),
607                                 bd->name, bd->uuid);
608
609                 widget_select_add_option(screen->widgets.boot_device_f, i,
610                                         label, selected);
611         }
612
613         for (i = 0; i < sysinfo->n_interfaces; i++) {
614                 struct interface_info *info = sysinfo->interfaces[i];
615                 char *label, mac[20];
616                 bool selected;
617
618                 mac_str(info->hwaddr, info->hwaddr_size, mac, sizeof(mac));
619                 selected = config->boot_device &&
620                                 !strcmp(config->boot_device, mac);
621                 if (selected)
622                         found = true;
623
624                 label = talloc_asprintf(screen, _("net:  %s [mac: %s]"),
625                                 info->name, mac);
626
627                 widget_select_add_option(screen->widgets.boot_device_f,
628                                                 i + sysinfo->n_blockdevs,
629                                                 label, selected);
630         }
631
632         if (screen->autoboot_type == AUTOBOOT_ONE && !found) {
633                 char *label;
634
635                 label = talloc_asprintf(screen, _("Unknown UUID: %s"),
636                                 config->boot_device);
637
638                 widget_select_add_option(screen->widgets.boot_device_f, -1,
639                                                 label, true);
640         }
641
642         str = talloc_asprintf(screen, "%d", config->autoboot_timeout_sec);
643         screen->widgets.timeout_l = widget_new_label(set, 0, 0, _("Timeout:"));
644         screen->widgets.timeout_f = widget_new_textbox(set, 0, 0, 5, str);
645         screen->widgets.timeout_help_l = widget_new_label(set, 0, 0,
646                                         _("seconds"));
647
648         widget_textbox_set_fixed_size(screen->widgets.timeout_f);
649         widget_textbox_set_validator_integer(screen->widgets.timeout_f, 0, 999);
650
651         screen->widgets.network_l = widget_new_label(set, 0, 0, _("Network:"));
652         screen->widgets.network_f = widget_new_select(set, 0, 0, 50);
653
654         widget_select_add_option(screen->widgets.network_f,
655                                         NET_CONF_TYPE_DHCP_ALL,
656                                         _("DHCP on all active interfaces"),
657                                         type == NET_CONF_TYPE_DHCP_ALL);
658         widget_select_add_option(screen->widgets.network_f,
659                                         NET_CONF_TYPE_DHCP_ONE,
660                                         _("DHCP on a specific interface"),
661                                         type == NET_CONF_TYPE_DHCP_ONE);
662         widget_select_add_option(screen->widgets.network_f,
663                                         NET_CONF_TYPE_STATIC,
664                                         _("Static IP configuration"),
665                                         type == NET_CONF_TYPE_STATIC);
666
667         widget_select_on_change(screen->widgets.network_f,
668                         config_screen_network_change, screen);
669
670         screen->widgets.iface_l = widget_new_label(set, 0, 0, _("Device:"));
671         screen->widgets.iface_f = widget_new_select(set, 0, 0, 50);
672
673         for (i = 0; i < sysinfo->n_interfaces; i++) {
674                 struct interface_info *info = sysinfo->interfaces[i];
675                 char str[50], mac[20];
676                 bool is_default;
677
678                 is_default = ifcfg && !memcmp(ifcfg->hwaddr, info->hwaddr,
679                                         sizeof(ifcfg->hwaddr));
680
681                 mac_str(info->hwaddr, info->hwaddr_size, mac, sizeof(mac));
682                 snprintf(str, sizeof(str), "%s [%s, %s]", info->name, mac,
683                                 info->link ? _("link up") : _("link down"));
684
685                 widget_select_add_option(screen->widgets.iface_f,
686                                                 i, str, is_default);
687         }
688
689         gw = ip = mask = NULL;
690         if (ifcfg && ifcfg->method == CONFIG_METHOD_STATIC) {
691                 char *sep;
692
693                 str = talloc_strdup(screen, ifcfg->static_config.address);
694                 sep = strchr(str, '/');
695                 ip = str;
696
697                 if (sep) {
698                         *sep = '\0';
699                         mask = sep + 1;
700                 }
701                 gw = ifcfg->static_config.gateway;
702         }
703
704         screen->widgets.ip_addr_l = widget_new_label(set, 0, 0, _("IP/mask:"));
705         screen->widgets.ip_addr_f = widget_new_textbox(set, 0, 0, 16, ip);
706         screen->widgets.ip_mask_l = widget_new_label(set, 0, 0, "/");
707         screen->widgets.ip_mask_f = widget_new_textbox(set, 0, 0, 3, mask);
708         screen->widgets.ip_addr_mask_help_l =
709                 widget_new_label(set, 0, 0, _("(eg. 192.168.0.10 / 24)"));
710
711         widget_textbox_set_fixed_size(screen->widgets.ip_addr_f);
712         widget_textbox_set_fixed_size(screen->widgets.ip_mask_f);
713         widget_textbox_set_validator_ipv4(screen->widgets.ip_addr_f);
714         widget_textbox_set_validator_integer(screen->widgets.ip_mask_f, 1, 31);
715
716         screen->widgets.gateway_l = widget_new_label(set, 0, 0, _("Gateway:"));
717         screen->widgets.gateway_f = widget_new_textbox(set, 0, 0, 16, gw);
718         screen->widgets.gateway_help_l =
719                 widget_new_label(set, 0, 0, _("(eg. 192.168.0.1)"));
720
721         widget_textbox_set_fixed_size(screen->widgets.gateway_f);
722         widget_textbox_set_validator_ipv4(screen->widgets.gateway_f);
723
724         str = talloc_strdup(screen, "");
725         for (i = 0; i < config->network.n_dns_servers; i++) {
726                 str = talloc_asprintf_append(str, "%s%s",
727                                 (i == 0) ? "" : " ",
728                                 config->network.dns_servers[i]);
729         }
730
731         screen->widgets.dns_l = widget_new_label(set, 0, 0,
732                                         _("DNS Server(s):"));
733         screen->widgets.dns_f = widget_new_textbox(set, 0, 0, 32, str);
734         screen->widgets.dns_help_l =
735                 widget_new_label(set, 0, 0, _("(eg. 192.168.0.2)"));
736
737         widget_textbox_set_validator_ipv4_multi(screen->widgets.dns_f);
738
739         screen->widgets.dns_dhcp_help_l = widget_new_label(set, 0, 0,
740                         _("(if not provided by DHCP server)"));
741
742         if (config->safe_mode)
743                 screen->widgets.safe_mode = widget_new_label(set, 0, 0,
744                          _("Selecting 'OK' will exit safe mode"));
745
746         screen->widgets.ok_b = widget_new_button(set, 0, 0, 6, _("OK"),
747                         ok_click, screen);
748         screen->widgets.help_b = widget_new_button(set, 0, 0, 6, _("Help"),
749                         help_click, screen);
750         screen->widgets.cancel_b = widget_new_button(set, 0, 0, 6, _("Cancel"),
751                         cancel_click, screen);
752 }
753
754 static void config_screen_widget_focus(struct nc_widget *widget, void *arg)
755 {
756         struct config_screen *screen = arg;
757         int w_y, s_max;
758
759         w_y = widget_y(widget) + widget_focus_y(widget);
760         s_max = getmaxy(screen->scr.sub_ncw) - 1;
761
762         if (w_y < screen->scroll_y)
763                 screen->scroll_y = w_y;
764
765         else if (w_y + screen->scroll_y + 1 > s_max)
766                 screen->scroll_y = 1 + w_y - s_max;
767
768         else
769                 return;
770
771         pad_refresh(screen);
772 }
773
774 static void config_screen_draw(struct config_screen *screen,
775                 const struct config *config,
776                 const struct system_info *sysinfo)
777 {
778         bool repost = false;
779         int height;
780
781         /* The size of the pad we'll need depends on the number of interfaces.
782          *
783          * We use N_FIELDS (which is quite conservative, as some fields share
784          * a line) as a base, then add 3 (as the network select field is
785          * takes 3 lines), and n_interfaces (as the network interface field
786          * has n_interfaces lines).
787          */
788         height = N_FIELDS + 3;
789         if (sysinfo)
790                 height += sysinfo->n_interfaces;
791         if (!screen->pad || getmaxy(screen->pad) < height) {
792                 if (screen->pad)
793                         delwin(screen->pad);
794                 screen->pad = newpad(height, COLS);
795         }
796
797         if (screen->widgetset) {
798                 widgetset_unpost(screen->widgetset);
799                 talloc_free(screen->widgetset);
800                 repost = true;
801         }
802
803         screen->widgetset = widgetset_create(screen, screen->scr.main_ncw,
804                         screen->pad);
805         widgetset_set_widget_focus(screen->widgetset,
806                         config_screen_widget_focus, screen);
807
808         if (!config || !sysinfo) {
809                 config_screen_setup_empty(screen);
810         } else {
811                 screen->net_conf_type = find_net_conf_type(config);
812                 if (!config->autoboot_enabled)
813                         screen->autoboot_type = AUTOBOOT_DISABLED;
814                 else
815                         screen->autoboot_type = config->boot_device ?
816                                         AUTOBOOT_ONE : AUTOBOOT_ANY;
817
818                 config_screen_setup_widgets(screen, config, sysinfo);
819                 config_screen_layout_widgets(screen);
820         }
821
822         if (repost)
823                 widgetset_post(screen->widgetset);
824 }
825
826 void config_screen_update(struct config_screen *screen,
827                 const struct config *config,
828                 const struct system_info *sysinfo)
829 {
830         config_screen_draw(screen, config, sysinfo);
831         pad_refresh(screen);
832 }
833
834 static int config_screen_destroy(void *arg)
835 {
836         struct config_screen *screen = arg;
837         if (screen->pad)
838                 delwin(screen->pad);
839         return 0;
840 }
841
842 struct config_screen *config_screen_init(struct cui *cui,
843                 const struct config *config,
844                 const struct system_info *sysinfo,
845                 void (*on_exit)(struct cui *))
846 {
847         struct config_screen *screen;
848
849         screen = talloc_zero(cui, struct config_screen);
850         talloc_set_destructor(screen, config_screen_destroy);
851         nc_scr_init(&screen->scr, pb_config_screen_sig, 0,
852                         cui, config_screen_process_key,
853                         config_screen_post, config_screen_unpost,
854                         config_screen_resize);
855
856         screen->cui = cui;
857         screen->on_exit = on_exit;
858         screen->label_x = 2;
859         screen->field_x = 17;
860
861         screen->scr.frame.ltitle = talloc_strdup(screen,
862                         _("Petitboot System Configuration"));
863         screen->scr.frame.rtitle = NULL;
864         screen->scr.frame.help = talloc_strdup(screen,
865                         _("tab=next, shift+tab=previous, x=exit, h=help"));
866         nc_scr_frame_draw(&screen->scr);
867
868         scrollok(screen->scr.sub_ncw, true);
869
870         config_screen_draw(screen, config, sysinfo);
871
872         return screen;
873 }