ui/ncurses: Add sysinfo screen
authorJeremy Kerr <jk@ozlabs.org>
Thu, 17 Oct 2013 05:52:42 +0000 (13:52 +0800)
committerJeremy Kerr <jk@ozlabs.org>
Wed, 13 Nov 2013 09:47:20 +0000 (17:47 +0800)
Add a simple screen for displaying the struct system_info. We add this
to the main menu as a selectable option, and separate it from the boot
option list with an unselectable blank entry.

Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
ui/ncurses/Makefile.am
ui/ncurses/generic-main.c
ui/ncurses/nc-cui.c
ui/ncurses/nc-cui.h
ui/ncurses/nc-menu.c
ui/ncurses/nc-scr.h
ui/ncurses/nc-sysinfo.c [new file with mode: 0644]
ui/ncurses/nc-sysinfo.h [new file with mode: 0644]

index 64b6eb1fd9215d2efeac97ffe458080cd9791f7b..ac4ca4643ce638f2ddee568784385f60258ebe38 100644 (file)
@@ -36,7 +36,9 @@ libpbnc_la_SOURCES = \
        nc-menu.c \
        nc-menu.h \
        nc-scr.c \
-       nc-scr.h
+       nc-scr.h \
+       nc-sysinfo.c \
+       nc-sysinfo.h
 
 sbin_PROGRAMS = petitboot-nc
 
index 49a96cb0037f108a7e5b76228877638b04520ab4..9d8ebb9b766e6804ef026211bd200d84d280c85c 100644 (file)
@@ -126,6 +126,12 @@ struct pb_cui {
        struct cui *cui;
 };
 
+static int pmenu_sysinfo(struct pmenu_item *item)
+{
+       cui_show_sysinfo(cui_from_item(item));
+       return 0;
+}
+
 /**
  * pb_mm_init - Setup the main menu instance.
  */
@@ -136,7 +142,7 @@ static struct pmenu *pb_mm_init(struct pb_cui *pb_cui)
        struct pmenu *m;
        struct pmenu_item *i;
 
-       m = pmenu_init(pb_cui->cui, 1, cui_on_exit);
+       m = pmenu_init(pb_cui->cui, 3, cui_on_exit);
 
        if (!m) {
                pb_log("%s: failed\n", __func__);
@@ -152,7 +158,11 @@ static struct pmenu *pb_mm_init(struct pb_cui *pb_cui)
                "Enter=accept, e=edit, n=new, x=exit");
        m->scr.frame.status = talloc_strdup(m, "Welcome to Petitboot");
 
-       i = pmenu_item_init(m, 0, "Exit to Shell");
+       i = pmenu_item_init(m, 0, " ");
+       item_opts_off(i->nci, O_SELECTABLE);
+       i = pmenu_item_init(m, 1, "System information");
+       i->on_execute = pmenu_sysinfo;
+       i = pmenu_item_init(m, 2, "Exit to shell");
        i->on_execute = pmenu_exit_cb;
 
        result = pmenu_setup(m);
index b734cdcd46c2bd2a6868cd8c25ba831568aa47a5..5f411963d0b10ed28c92aab472935b2c8aaa91f7 100644 (file)
@@ -34,6 +34,7 @@
 #include "process/process.h"
 #include "ui/common/discover-client.h"
 #include "nc-cui.h"
+#include "nc-sysinfo.h"
 
 static struct cui_opt_data *cod_from_item(struct pmenu_item *item)
 {
@@ -236,6 +237,20 @@ void cui_item_new(struct pmenu *menu)
        cui_set_current(cui, &boot_editor->scr);
 }
 
+static void cui_sysinfo_exit(struct cui *cui)
+{
+       cui_set_current(cui, &cui->main->scr);
+       talloc_free(cui->sysinfo_screen);
+       cui->sysinfo_screen = NULL;
+}
+
+void cui_show_sysinfo(struct cui *cui)
+{
+       cui->sysinfo_screen = sysinfo_screen_init(cui, cui->sysinfo,
+                       cui_sysinfo_exit);
+       cui_set_current(cui, sysinfo_screen_scr(cui->sysinfo_screen));
+}
+
 /**
  * cui_set_current - Set the currently active screen and redraw it.
  */
@@ -506,6 +521,12 @@ static void cui_update_sysinfo(struct system_info *sysinfo, void *arg)
 {
        struct cui *cui = cui_from_arg(arg);
        cui->sysinfo = talloc_steal(cui, sysinfo);
+
+       /* if we're currently displaying the system info screen, inform it
+        * of the updated information. */
+       if (cui->sysinfo_screen)
+               sysinfo_screen_update(cui->sysinfo_screen, sysinfo);
+
        cui_update_mm_title(cui);
 }
 
index 730e7216559ba2239cdb4da119bd92aa9d2de564..d1edd795fbd7e8d057ca59ac8ff6394aa268a0f2 100644 (file)
@@ -56,6 +56,7 @@ struct cui {
        struct waitset *waitset;
        struct discover_client *client;
        struct system_info *sysinfo;
+       struct sysinfo_screen *sysinfo_screen;
        struct pjs *pjs;
        void *platform_info;
        unsigned int default_item;
@@ -69,6 +70,7 @@ struct nc_scr *cui_set_current(struct cui *cui, struct nc_scr *scr);
 int cui_run(struct cui *cui, struct pmenu *main, unsigned int default_item);
 void cui_item_edit(struct pmenu_item *item);
 void cui_item_new(struct pmenu *menu);
+void cui_show_sysinfo(struct cui *cui);
 
 /* convenience routines */
 
index 4dba0ad1d8d6680e7c21cd189e2642e0e5c167f8..dc4680789d3490ba03a669b59e6e923278077b6d 100644 (file)
@@ -27,6 +27,7 @@
 #include "log/log.h"
 #include "talloc/talloc.h"
 #include "ui/common/ui-system.h"
+#include "nc-cui.h"
 #include "nc-menu.h"
 
 /**
@@ -242,6 +243,8 @@ static void pmenu_process_key(struct nc_scr *scr, int key)
                if (item->on_execute)
                        item->on_execute(item);
                break;
+       case 'i':
+               cui_show_sysinfo(cui_from_arg(scr->ui_ctx));
        default:
                menu_driver(menu->ncm, key);
                break;
@@ -378,6 +381,8 @@ int pmenu_setup(struct pmenu *menu)
        /* Makes menu scrollable. */
        set_menu_format(menu->ncm, LINES - nc_scr_frame_lines, 1);
 
+       set_menu_grey(menu->ncm, A_NORMAL);
+
        return 0;
 }
 
index 4f9de59f6ce0eff73c743591e2359ec355f9c6f9..e3ed20a8502d8de3cad30f0fe6d1a3e475a62fb8 100644 (file)
 
 
 enum pb_nc_sig {
-       pb_cui_sig         = 111,
-       pb_pmenu_sig       = 222,
-       pb_item_sig        = 333,
-       pb_boot_editor_sig = 444,
-       pb_removed_sig     = -555,
+       pb_cui_sig              = 111,
+       pb_pmenu_sig            = 222,
+       pb_item_sig             = 333,
+       pb_boot_editor_sig      = 444,
+       pb_sysinfo_screen_sig   = 555,
+       pb_removed_sig          = -666,
 };
 
 static inline void nc_flush_keys(void)
diff --git a/ui/ncurses/nc-sysinfo.c b/ui/ncurses/nc-sysinfo.c
new file mode 100644 (file)
index 0000000..4cba9a9
--- /dev/null
@@ -0,0 +1,249 @@
+/*
+ *  Copyright (C) 2013 IBM Corporation
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#define _GNU_SOURCE
+
+
+#include <string.h>
+
+#include <talloc/talloc.h>
+#include <types/types.h>
+#include <log/log.h>
+#include <util/util.h>
+
+#include "config.h"
+#include "nc-cui.h"
+#include "nc-sysinfo.h"
+
+struct sysinfo_screen {
+       struct nc_scr   scr;
+       struct cui      *cui;
+       char            **lines;
+       int             n_lines;
+       int             n_alloc_lines;
+       int             scroll_y;
+       void            (*on_exit)(struct cui *);
+};
+
+static struct sysinfo_screen *sysinfo_screen_from_scr(struct nc_scr *scr)
+{
+       struct sysinfo_screen *sysinfo_screen;
+
+       assert(scr->sig == pb_sysinfo_screen_sig);
+       sysinfo_screen = (struct sysinfo_screen *)
+               ((char *)scr - (size_t)&((struct sysinfo_screen *)0)->scr);
+       assert(sysinfo_screen->scr.sig == pb_sysinfo_screen_sig);
+       return sysinfo_screen;
+}
+
+static void sysinfo_screen_draw(struct sysinfo_screen *screen)
+{
+       int max_y, i;
+
+       max_y = getmaxy(screen->scr.sub_ncw);
+
+       max_y = min(max_y, screen->scroll_y + screen->n_lines);
+
+       for (i = screen->scroll_y; i < max_y; i++)
+               mvwaddstr(screen->scr.sub_ncw, i, 1, screen->lines[i]);
+
+       wrefresh(screen->scr.sub_ncw);
+}
+
+static void sysinfo_screen_scroll(struct sysinfo_screen *screen, int key)
+{
+       int win_lines = getmaxy(screen->scr.sub_ncw);
+       int delta;
+
+       if (key == KEY_UP)
+               delta = -1;
+       else if (key == KEY_DOWN)
+               delta = 1;
+       else
+               return;
+
+       if (screen->scroll_y + delta < 0)
+               return;
+       if (screen->scroll_y + delta + win_lines > screen->n_lines - 1)
+               return;
+
+       screen->scroll_y += delta;
+       wscrl(screen->scr.sub_ncw, delta);
+
+       if (delta > 0) {
+               mvwaddstr(screen->scr.sub_ncw, win_lines - 1, 1,
+                               screen->lines[screen->scroll_y+win_lines-1]);
+       } else if (delta < 0) {
+               mvwaddstr(screen->scr.sub_ncw, 0, 1,
+                               screen->lines[screen->scroll_y]);
+       }
+
+       wrefresh(screen->scr.sub_ncw);
+}
+
+static void sysinfo_clear(struct sysinfo_screen *screen)
+{
+       talloc_free(screen->lines);
+       screen->n_lines = 0;
+       screen->n_alloc_lines = 16;
+       screen->lines = talloc_array(screen, char *, screen->n_alloc_lines);
+}
+
+static __attribute__((format(printf, 2, 3))) void sysinfo_screen_append_line(
+               struct sysinfo_screen *screen, const char *fmt, ...)
+{
+       char *line;
+       va_list ap;
+
+       if (fmt) {
+               va_start(ap, fmt);
+               line = talloc_vasprintf(screen->lines, fmt, ap);
+               va_end(ap);
+       } else {
+               line = "";
+       }
+
+       if (screen->n_lines == screen->n_alloc_lines) {
+               screen->n_alloc_lines *= 2;
+               screen->lines = talloc_realloc(screen, screen->lines,
+                                               char *, screen->n_alloc_lines);
+       }
+
+       screen->lines[screen->n_lines] = line;
+       screen->n_lines++;
+}
+
+static void mac_str(struct interface_info *info, char *buf, unsigned int buflen)
+{
+       unsigned int i;
+       char *pos;
+
+       assert(buflen > sizeof("unknown"));
+
+       if (!info->hwaddr_size || info->hwaddr_size * 3 + 1 > buflen) {
+               strcpy(buf, "unknown");
+               return;
+       }
+
+       pos = buf;
+
+       for (i = 0; i < info->hwaddr_size; i++) {
+               snprintf(pos, 4, "%02x:", info->hwaddr[i]);
+               pos += 3;
+       }
+
+       *(pos - 1) = '\0';
+
+       return;
+}
+
+static void sysinfo_screen_populate(struct sysinfo_screen *screen,
+               const struct system_info *sysinfo)
+{
+       unsigned int i;
+
+       sysinfo_clear(screen);
+
+#define line(...) sysinfo_screen_append_line(screen, __VA_ARGS__)
+       if (!sysinfo) {
+               line("Waiting for system information...");
+               return;
+       }
+
+       line("%-12s %s", "System type:", sysinfo->type ?: "");
+       line("%-12s %s", "System id:",   sysinfo->identifier ?: "");
+
+       line(NULL);
+       if (sysinfo->n_interfaces)
+               line("Network interfaces");
+
+       for (i = 0; i < sysinfo->n_interfaces; i++) {
+               struct interface_info *info = sysinfo->interfaces[i];
+               char macbuf[32];
+
+               mac_str(info, macbuf, sizeof(macbuf));
+
+               line("%s:", info->name);
+               line(" MAC: %s", macbuf);
+               line(NULL);
+       }
+
+#undef line
+}
+
+static void sysinfo_screen_process_key(struct nc_scr *scr, int key)
+{
+       struct sysinfo_screen *screen = sysinfo_screen_from_scr(scr);
+
+       switch (key) {
+       case 'x':
+               screen->on_exit(screen->cui);
+               break;
+       case KEY_DOWN:
+       case KEY_UP:
+               sysinfo_screen_scroll(screen, key);
+               break;
+       default:
+               break;
+       }
+}
+
+static void sysinfo_screen_resize(struct nc_scr *scr)
+{
+       struct sysinfo_screen *screen = sysinfo_screen_from_scr(scr);
+       sysinfo_screen_draw(screen);
+}
+
+struct nc_scr *sysinfo_screen_scr(struct sysinfo_screen *screen)
+{
+       return &screen->scr;
+}
+
+void sysinfo_screen_update(struct sysinfo_screen *screen,
+               const struct system_info *sysinfo)
+{
+       sysinfo_screen_populate(screen, sysinfo);
+       sysinfo_screen_draw(screen);
+}
+
+struct sysinfo_screen *sysinfo_screen_init(struct cui *cui,
+               const struct system_info *sysinfo,
+               void (*on_exit)(struct cui *))
+{
+       struct sysinfo_screen *screen;
+
+       screen = talloc_zero(cui, struct sysinfo_screen);
+       nc_scr_init(&screen->scr, pb_sysinfo_screen_sig, 0,
+                       cui, sysinfo_screen_process_key,
+                       NULL, NULL, sysinfo_screen_resize);
+
+       screen->cui = cui;
+       screen->on_exit = on_exit;
+
+       screen->scr.frame.ltitle = talloc_strdup(screen,
+                       "Petitboot System Information");
+       screen->scr.frame.rtitle = NULL;
+       screen->scr.frame.help = talloc_strdup(screen, "x=exit");
+       nc_scr_frame_draw(&screen->scr);
+
+       sysinfo_screen_populate(screen, sysinfo);
+       wrefresh(screen->scr.main_ncw);
+       scrollok(screen->scr.sub_ncw, true);
+       sysinfo_screen_draw(screen);
+
+       return screen;
+}
diff --git a/ui/ncurses/nc-sysinfo.h b/ui/ncurses/nc-sysinfo.h
new file mode 100644 (file)
index 0000000..5407bf8
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ *  Copyright (C) 2013 IBM Corporation
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef _NC_SYSINFO_H
+#define _NC_SYSINFO_H
+
+#include "types/types.h"
+#include "nc-cui.h"
+
+struct sysinfo_screen;
+
+struct sysinfo_screen *sysinfo_screen_init(struct cui *cui,
+               const struct system_info *sysinfo,
+               void (*on_exit)(struct cui *));
+
+struct nc_scr *sysinfo_screen_scr(struct sysinfo_screen *screen);
+void sysinfo_screen_update(struct sysinfo_screen *screen,
+               const struct system_info *sysinfo);
+
+#endif /* defined _NC_SYSINFO_H */