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