ui/ncurses: Add block devices to system info screen
[petitboot] / ui / ncurses / nc-sysinfo.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 #define _GNU_SOURCE
19
20
21 #include <string.h>
22
23 #include <talloc/talloc.h>
24 #include <types/types.h>
25 #include <log/log.h>
26 #include <util/util.h>
27
28 #include "config.h"
29 #include "nc-cui.h"
30 #include "nc-sysinfo.h"
31
32 struct sysinfo_screen {
33         struct nc_scr   scr;
34         struct cui      *cui;
35         char            **lines;
36         int             n_lines;
37         int             n_alloc_lines;
38         int             scroll_y;
39         void            (*on_exit)(struct cui *);
40 };
41
42 static struct sysinfo_screen *sysinfo_screen_from_scr(struct nc_scr *scr)
43 {
44         struct sysinfo_screen *sysinfo_screen;
45
46         assert(scr->sig == pb_sysinfo_screen_sig);
47         sysinfo_screen = (struct sysinfo_screen *)
48                 ((char *)scr - (size_t)&((struct sysinfo_screen *)0)->scr);
49         assert(sysinfo_screen->scr.sig == pb_sysinfo_screen_sig);
50         return sysinfo_screen;
51 }
52
53 static void sysinfo_screen_draw(struct sysinfo_screen *screen)
54 {
55         int max_y, i;
56
57         max_y = getmaxy(screen->scr.sub_ncw);
58
59         max_y = min(max_y, screen->scroll_y + screen->n_lines);
60
61         for (i = screen->scroll_y; i < max_y; i++)
62                 mvwaddstr(screen->scr.sub_ncw, i, 1, screen->lines[i]);
63
64         wrefresh(screen->scr.sub_ncw);
65 }
66
67 static void sysinfo_screen_scroll(struct sysinfo_screen *screen, int key)
68 {
69         int win_lines = getmaxy(screen->scr.sub_ncw);
70         int delta;
71
72         if (key == KEY_UP)
73                 delta = -1;
74         else if (key == KEY_DOWN)
75                 delta = 1;
76         else
77                 return;
78
79         if (screen->scroll_y + delta < 0)
80                 return;
81         if (screen->scroll_y + delta + win_lines > screen->n_lines - 1)
82                 return;
83
84         screen->scroll_y += delta;
85         wscrl(screen->scr.sub_ncw, delta);
86
87         if (delta > 0) {
88                 mvwaddstr(screen->scr.sub_ncw, win_lines - 1, 1,
89                                 screen->lines[screen->scroll_y+win_lines-1]);
90         } else if (delta < 0) {
91                 mvwaddstr(screen->scr.sub_ncw, 0, 1,
92                                 screen->lines[screen->scroll_y]);
93         }
94
95         wrefresh(screen->scr.sub_ncw);
96 }
97
98 static void sysinfo_clear(struct sysinfo_screen *screen)
99 {
100         talloc_free(screen->lines);
101         screen->n_lines = 0;
102         screen->n_alloc_lines = 16;
103         screen->lines = talloc_array(screen, char *, screen->n_alloc_lines);
104 }
105
106 static __attribute__((format(printf, 2, 3))) void sysinfo_screen_append_line(
107                 struct sysinfo_screen *screen, const char *fmt, ...)
108 {
109         char *line;
110         va_list ap;
111
112         if (fmt) {
113                 va_start(ap, fmt);
114                 line = talloc_vasprintf(screen->lines, fmt, ap);
115                 va_end(ap);
116         } else {
117                 line = "";
118         }
119
120         if (screen->n_lines == screen->n_alloc_lines) {
121                 screen->n_alloc_lines *= 2;
122                 screen->lines = talloc_realloc(screen, screen->lines,
123                                                 char *, screen->n_alloc_lines);
124         }
125
126         screen->lines[screen->n_lines] = line;
127         screen->n_lines++;
128 }
129
130 static void mac_str(struct interface_info *info, char *buf, unsigned int buflen)
131 {
132         unsigned int i;
133         char *pos;
134
135         assert(buflen > sizeof("unknown"));
136
137         if (!info->hwaddr_size || info->hwaddr_size * 3 + 1 > buflen) {
138                 strcpy(buf, "unknown");
139                 return;
140         }
141
142         pos = buf;
143
144         for (i = 0; i < info->hwaddr_size; i++) {
145                 snprintf(pos, 4, "%02x:", info->hwaddr[i]);
146                 pos += 3;
147         }
148
149         *(pos - 1) = '\0';
150
151         return;
152 }
153
154 static void sysinfo_screen_populate(struct sysinfo_screen *screen,
155                 const struct system_info *sysinfo)
156 {
157         unsigned int i;
158
159         sysinfo_clear(screen);
160
161 #define line(...) sysinfo_screen_append_line(screen, __VA_ARGS__)
162         if (!sysinfo) {
163                 line("Waiting for system information...");
164                 return;
165         }
166
167         line("%-12s %s", "System type:", sysinfo->type ?: "");
168         line("%-12s %s", "System id:",   sysinfo->identifier ?: "");
169
170         if (sysinfo->n_blockdevs) {
171                 line(NULL);
172                 line("Storage devices");
173         }
174
175         for (i = 0; i < sysinfo->n_blockdevs; i++) {
176                 struct blockdev_info *info = sysinfo->blockdevs[i];
177
178                 line("%s:", info->name);
179                 line(" UUID:       %s", info->uuid);
180                 line(" mounted at: %s", info->mountpoint);
181                 line(NULL);
182         }
183
184         if (sysinfo->n_interfaces) {
185                 line(NULL);
186                 line("Network interfaces");
187         }
188
189         for (i = 0; i < sysinfo->n_interfaces; i++) {
190                 struct interface_info *info = sysinfo->interfaces[i];
191                 char macbuf[32];
192
193                 mac_str(info, macbuf, sizeof(macbuf));
194
195                 line("%s:", info->name);
196                 line(" MAC: %s", macbuf);
197                 line(NULL);
198         }
199
200 #undef line
201 }
202
203 static void sysinfo_screen_process_key(struct nc_scr *scr, int key)
204 {
205         struct sysinfo_screen *screen = sysinfo_screen_from_scr(scr);
206
207         switch (key) {
208         case 'x':
209                 screen->on_exit(screen->cui);
210                 break;
211         case KEY_DOWN:
212         case KEY_UP:
213                 sysinfo_screen_scroll(screen, key);
214                 break;
215         default:
216                 break;
217         }
218 }
219
220 static void sysinfo_screen_resize(struct nc_scr *scr)
221 {
222         struct sysinfo_screen *screen = sysinfo_screen_from_scr(scr);
223         sysinfo_screen_draw(screen);
224 }
225
226 struct nc_scr *sysinfo_screen_scr(struct sysinfo_screen *screen)
227 {
228         return &screen->scr;
229 }
230
231 void sysinfo_screen_update(struct sysinfo_screen *screen,
232                 const struct system_info *sysinfo)
233 {
234         sysinfo_screen_populate(screen, sysinfo);
235         sysinfo_screen_draw(screen);
236 }
237
238 struct sysinfo_screen *sysinfo_screen_init(struct cui *cui,
239                 const struct system_info *sysinfo,
240                 void (*on_exit)(struct cui *))
241 {
242         struct sysinfo_screen *screen;
243
244         screen = talloc_zero(cui, struct sysinfo_screen);
245         nc_scr_init(&screen->scr, pb_sysinfo_screen_sig, 0,
246                         cui, sysinfo_screen_process_key,
247                         NULL, NULL, sysinfo_screen_resize);
248
249         screen->cui = cui;
250         screen->on_exit = on_exit;
251
252         screen->scr.frame.ltitle = talloc_strdup(screen,
253                         "Petitboot System Information");
254         screen->scr.frame.rtitle = NULL;
255         screen->scr.frame.help = talloc_strdup(screen, "x=exit");
256         nc_scr_frame_draw(&screen->scr);
257
258         sysinfo_screen_populate(screen, sysinfo);
259         wrefresh(screen->scr.main_ncw);
260         scrollok(screen->scr.sub_ncw, true);
261         sysinfo_screen_draw(screen);
262
263         return screen;
264 }