1 #include <nm_core.h>
2 #include <nm_form.h>
3 #include <nm_utils.h>
4 #include <nm_string.h>
5 #include <nm_window.h>
6 #include <nm_ncurses.h>
7 #include <nm_database.h>
8 #include <nm_cfg_file.h>
9 #include <nm_usb_plug.h>
10 #include <nm_stat_usage.h>
11
12 static float nm_window_scale = 0.7;
13
14 static void nm_init_window__(nm_window_t *w, const char *msg);
15 static void nm_print_help_lines(const char **msg, size_t objs, int err);
16 static void nm_print_help__(const char **keys, const char **values,
17 size_t hotkey_num, size_t maxlen);
18
19 #if defined (NM_OS_LINUX)
20 #if defined (NM_WITH_OVF_SUPPORT)
21 #define NM_HELP_MSG \
22 "q:Quit", "I:Install VM", "O:Import OVA", "A:Import image", "N:Network", "?:Help"
23 #else
24 #define NM_HELP_MSG \
25 "q:Quit", "I:Install VM", "A:Import image", "N:Network", "?:Help"
26 #endif
27 #else
28 #if defined (NM_WITH_OVF_SUPPORT)
29 #define NM_HELP_MSG \
30 "q:Quit", "I:Install VM", "O:Import OVA", "A:Import image", "?:Help"
31 #else
32 #define NM_HELP_MSG \
33 "q:Quit", "I:Install VM", "A:Import image", "?:Help"
34 #endif
35 #endif
36
37 #if defined (NM_WITH_NETWORK_MAP)
38 #define NM_LAN_MSG \
39 "q:Back", "e:Export SVG map", "?:Help"
40 #else
41 #define NM_LAN_MSG \
42 "q:Back", "?:Help"
43 #endif
44
45 #define X_NM_HELP_GEN \
46 X(main, NM_HELP_MSG) \
47 X(lan, NM_LAN_MSG) \
48 X(edit, "esc:Cancel", "enter:Save") \
49 X(import, "esc:Cancel", "enter:Import") \
50 X(install, "esc:Cancel", "enter:Install") \
51 X(iface, "q:Back", "enter:Edit") \
52 X(clone, "esc:Cancel", "enter:Clone") \
53 X(export, "esc:Cancel", "enter:Export") \
54 X(delete, "q:Back", "enter:Delete")
55
56 #define X(name, ...) \
57 void nm_init_help_ ## name(void) { \
58 const char *msg[] = { __VA_ARGS__ }; \
59 nm_print_help_lines(msg, nm_arr_len(msg), NM_FALSE); \
60 }
61 X_NM_HELP_GEN
62 #undef X
63
nm_create_windows(void)64 void nm_create_windows(void)
65 {
66 int action_cols, screen_x, screen_y;
67 nm_cord_t help_size;
68 nm_cord_t side_size;
69 nm_cord_t action_size;
70
71 getmaxyx(stdscr, screen_y, screen_x);
72 action_cols = screen_x * nm_window_scale;
73
74 help_size = NM_SET_POS(1, screen_x, 0, 0);
75 side_size = NM_SET_POS(screen_y - 1, screen_x - action_cols, 0, 1);
76 action_size = NM_SET_POS(screen_y - 1, action_cols, screen_x - action_cols, 1);
77
78 help_window = nm_init_window(&help_size);
79 side_window = nm_init_window(&side_size);
80 action_window = nm_init_window(&action_size);
81
82 help_panel = new_panel(help_window);
83 side_panel = new_panel(side_window);
84 action_panel = new_panel(action_window);
85 }
86
nm_init_help(const char * msg,int err)87 void nm_init_help(const char *msg, int err)
88 {
89 nm_print_help_lines(&msg, 1, err);
90 }
91
nm_print_help_lines(const char ** msg,size_t objs,int err)92 static void nm_print_help_lines(const char **msg, size_t objs, int err)
93 {
94 if (!msg)
95 return;
96
97 int x = 1, y = 0;
98 int use_glyph = nm_cfg_get()->glyphs.separator;
99
100 wbkgd(help_window, COLOR_PAIR(err ? NM_COLOR_RED : NM_COLOR_BLACK));
101
102 for (size_t n = 0; n < objs; n++) {
103 if (n > 0) {
104 x++;
105 if (use_glyph) {
106 mvwprintw(help_window, y, x, NM_GLYPH_SEP);
107 } else {
108 mvwaddch(help_window, y, x, ACS_VLINE);
109 }
110 x+=2;
111 }
112
113 mvwprintw(help_window, y, x, _(msg[n]));
114 x += mbstowcs(NULL, _(msg[n]), strlen(_(msg[n])));
115
116 if (use_glyph && (n == objs - 1)) {
117 x++;
118 mvwprintw(help_window, y, x, NM_GLYPH_SEP);
119 }
120 }
121
122 wrefresh(help_window);
123 }
124
nm_init_side(void)125 void nm_init_side(void)
126 {
127 nm_str_t title = NM_INIT_STR;
128
129 wattroff(side_window, COLOR_PAIR(NM_COLOR_HIGHLIGHT));
130
131 if (nm_filter.type == NM_FILTER_GROUP) {
132 nm_str_format(&title, "VM list [%s]", nm_filter.query.data);
133 nm_init_window__(side_window, _(title.data));
134 nm_str_free(&title);
135 } else {
136 nm_init_window__(side_window, _("VM list"));
137 }
138
139 wtimeout(side_window, 500);
140 }
141
nm_init_side_lan(void)142 void nm_init_side_lan(void)
143 {
144 wattroff(side_window, COLOR_PAIR(NM_COLOR_HIGHLIGHT));
145 nm_init_window__(side_window, _("veth list"));
146 wtimeout(side_window, -1);
147 }
148
nm_init_side_if_list(void)149 void nm_init_side_if_list(void)
150 {
151 wattroff(side_window, COLOR_PAIR(NM_COLOR_HIGHLIGHT));
152 nm_init_window__(side_window, _("Iface list"));
153 wtimeout(side_window, -1);
154 }
155
nm_init_side_drives(void)156 void nm_init_side_drives(void)
157 {
158 wattroff(side_window, COLOR_PAIR(NM_COLOR_HIGHLIGHT));
159 nm_init_window__(side_window, _("Drive list"));
160 wtimeout(side_window, -1);
161 }
162
nm_init_action(const char * msg)163 void nm_init_action(const char *msg)
164 {
165 nm_init_window__(action_window, msg ? msg : _("Properties"));
166 }
167
nm_init_window__(nm_window_t * w,const char * msg)168 static void nm_init_window__(nm_window_t *w, const char *msg)
169 {
170 int cols = getmaxx(w);
171 size_t mb_len = mbstowcs(NULL, msg, strlen(msg));
172
173 box(w, 0, 0);
174 mvwprintw(w, 1, (cols - mb_len) / 2, msg);
175 mvwaddch(w, 2, 0, ACS_LTEE);
176 mvwhline(w, 2, 1, ACS_HLINE, cols - 2);
177 mvwaddch(w, 2, cols - 1, ACS_RTEE);
178 wrefresh(w);
179 }
180
nm_destroy_windows(void)181 void nm_destroy_windows(void)
182 {
183 del_panel(help_panel);
184 del_panel(side_panel);
185 del_panel(action_panel);
186
187 delwin(help_window);
188 delwin(side_window);
189 delwin(action_window);
190
191 help_window = NULL;
192 side_window = NULL;
193 action_window = NULL;
194 }
195
nm_print_cmd(const nm_str_t * name)196 void nm_print_cmd(const nm_str_t *name)
197 {
198 nm_str_t buf = NM_INIT_STR;
199 nm_vect_t argv = NM_INIT_VECT;
200 nm_vect_t res = NM_INIT_VECT;
201 nm_vmctl_data_t vm = NM_VMCTL_INIT_DATA;
202 int off, start = 3, flags = 0;
203
204 int col = getmaxx(stdscr);
205 flags |= NM_VMCTL_INFO;
206
207 nm_vmctl_get_data(name, &vm);
208
209 nm_vmctl_gen_cmd(&argv, &vm, name, &flags, NULL, NULL);
210
211 /* pre checking */
212 for (size_t n = 0; n < argv.n_memb; n++) {
213 off = strlen((char *) nm_vect_at(&argv, n));
214 off += 2; /* count ' \' */
215
216 if (off >= col) {
217 nm_str_format(&buf, "%s", _("window to small"));
218 nm_clear_screen();
219 mvprintw(1, (col - name->len) / 2, "%s", name->data);
220 mvprintw(3, 0, "%s", buf.data);
221 goto out;
222 }
223 }
224
225 for (size_t n = 0; n < argv.n_memb; n++) {
226 const char *arg = nm_vect_at(&argv, n);
227 off = buf.len;
228 off += strlen(arg);
229 off += 2;
230
231 if (off > col) {
232 nm_str_t tmp = NM_INIT_STR;
233 nm_str_append_format(&tmp, "%s\\", buf.data);
234 nm_vect_insert_cstr(&res, tmp.data);
235 nm_str_trunc(&buf, 0);
236 if (n + 1 != argv.n_memb) {
237 nm_str_append_format(&buf, "%s ", arg);
238 } else {
239 nm_vect_insert_cstr(&res, arg);
240 }
241 nm_str_free(&tmp);
242 } else if (off <= col && n + 1 < argv.n_memb) {
243 nm_str_append_format(&buf, "%s ", arg);
244 } else {
245 nm_str_append_format(&buf, "%s ", arg);
246 nm_vect_insert_cstr(&res, buf.data);
247 }
248 }
249
250 nm_clear_screen();
251 mvprintw(1, (col - name->len) / 2, "%s", name->data);
252
253 for (size_t n = 0; n < res.n_memb; n++) {
254 mvprintw(start + n, 0, "%s", (char *) nm_vect_at(&res, n));
255 }
256
257 out:
258 nm_str_free(&buf);
259 nm_vect_free(&argv, NULL);
260 nm_vect_free(&res, NULL);
261 nm_vmctl_free_data(&vm);
262
263 refresh();
264 getch();
265 }
266
nm_print_snapshots(const nm_vect_t * v)267 void nm_print_snapshots(const nm_vect_t *v)
268 {
269 nm_str_t buf = NM_INIT_STR;
270 size_t count = v->n_memb / 5;
271 size_t y = 7, x = 2;
272 size_t cols, rows;
273 chtype ch1, ch2;
274 ch1 = ch2 = 0;
275
276 getmaxyx(action_window, rows, cols);
277
278 enum {
279 NM_SQL_VMSNAP_NAME = 2,
280 NM_SQL_VMSNAP_TIME = 4
281 };
282
283 for (size_t n = 0; n < count; n++) {
284 size_t idx_shift = 5 * n;
285
286 if (n && n < count) {
287 ch1 = (n != (count - 1)) ? ACS_LTEE : ACS_LLCORNER;
288 ch2 = ACS_HLINE;
289 }
290
291 nm_str_format(&buf, "%s (%s)",
292 nm_vect_str_ctx(v, NM_SQL_VMSNAP_NAME + idx_shift),
293 nm_vect_str_ctx(v, NM_SQL_VMSNAP_TIME + idx_shift));
294 NM_PR_VM_INFO();
295 }
296
297 nm_str_free(&buf);
298 }
299
nm_print_drive_info(const nm_vect_t * v,size_t idx)300 void nm_print_drive_info(const nm_vect_t *v, size_t idx)
301 {
302 if (!idx)
303 return;
304
305 nm_str_t buf = NM_INIT_STR;
306 size_t y = 3, x = 2;
307 size_t cols, rows;
308 size_t idx_shift;
309 chtype ch1, ch2;
310 ch1 = ch2 = 0;
311
312 idx_shift = 2 * (--idx);
313
314 getmaxyx(action_window, rows, cols);
315
316 nm_str_format(&buf, "%-12s%sGb", "capacity: ",
317 nm_vect_str_ctx(v, 1 + idx_shift));
318 NM_PR_VM_INFO();
319
320 nm_str_free(&buf);
321 }
322
nm_print_iface_info(const nm_vmctl_data_t * vm,size_t idx)323 void nm_print_iface_info(const nm_vmctl_data_t *vm, size_t idx)
324 {
325 if (!idx)
326 return;
327
328 nm_str_t buf = NM_INIT_STR;
329 size_t y = 3, x = 2;
330 size_t cols, rows;
331 size_t idx_shift, mvtap_idx = 0;
332 chtype ch1, ch2;
333 ch1 = ch2 = 0;
334
335 idx_shift = NM_IFS_IDX_COUNT * (--idx);
336
337 getmaxyx(action_window, rows, cols);
338
339 if (nm_str_cmp_st(nm_vect_str(&vm->ifs, NM_SQL_IF_USR + idx_shift),
340 NM_ENABLE) == NM_OK) {
341 nm_str_format(&buf, "%-12s%s", "User mode: ", "enabled");
342 NM_PR_VM_INFO();
343
344 if (nm_vect_str_len(&vm->ifs, NM_SQL_IF_FWD + idx_shift) != 0) {
345 nm_str_format(&buf, "%-12s%s", "hostfwd: ",
346 nm_vect_str_ctx(&vm->ifs, NM_SQL_IF_FWD + idx_shift));
347 NM_PR_VM_INFO();
348 }
349 if (nm_vect_str_len(&vm->ifs, NM_SQL_IF_SMB + idx_shift) != 0) {
350 nm_str_format(&buf, "%-12s%s", "smb: ",
351 nm_vect_str_ctx(&vm->ifs, NM_SQL_IF_SMB + idx_shift));
352 NM_PR_VM_INFO();
353 }
354
355 goto out;
356 }
357
358 nm_str_format(&buf, "%-12s%s", "hwaddr: ",
359 nm_vect_str_ctx(&vm->ifs, NM_SQL_IF_MAC + idx_shift));
360 NM_PR_VM_INFO();
361
362 nm_str_format(&buf, "%-12s%s", "driver: ",
363 nm_vect_str_ctx(&vm->ifs, NM_SQL_IF_DRV + idx_shift));
364 NM_PR_VM_INFO();
365
366 if (nm_vect_str_len(&vm->ifs, NM_SQL_IF_IP4 + idx_shift) > 0) {
367 nm_str_format(&buf, "%-12s%s", "host addr: ",
368 nm_vect_str_ctx(&vm->ifs, NM_SQL_IF_IP4 + idx_shift));
369 NM_PR_VM_INFO();
370 }
371
372 nm_str_format(&buf, "%-12s%s", "vhost: ",
373 (nm_str_cmp_st(nm_vect_str(&vm->ifs, NM_SQL_IF_VHO + idx_shift),
374 NM_ENABLE) == NM_OK) ? "yes" : "no");
375 NM_PR_VM_INFO();
376
377 mvtap_idx = nm_str_stoui(nm_vect_str(&vm->ifs, NM_SQL_IF_MVT + idx_shift), 10);
378 if (!mvtap_idx)
379 nm_str_format(&buf, "%-12s%s", "MacVTap: ", nm_form_macvtap[mvtap_idx]);
380 else
381 nm_str_format(&buf, "%-12s%s [iface: %s]", "MacVTap: ", nm_form_macvtap[mvtap_idx],
382 nm_vect_str_ctx(&vm->ifs, NM_SQL_IF_PET + idx_shift));
383 NM_PR_VM_INFO();
384 out:
385 nm_str_free(&buf);
386 }
387
nm_print_vm_info(const nm_str_t * name,const nm_vmctl_data_t * vm,int status)388 void nm_print_vm_info(const nm_str_t *name, const nm_vmctl_data_t *vm, int status)
389 {
390 nm_str_t buf = NM_INIT_STR;
391 size_t y = 3, x = 2;
392 size_t cols, rows;
393 size_t ifs_count, drives_count;
394 chtype ch1, ch2;
395 nm_cpu_t cpu = NM_INIT_CPU;
396 ch1 = ch2 = 0;
397
398 static const nm_str_t *name_ = NULL;
399 static const nm_vmctl_data_t *vm_ = NULL;
400 static int status_ = 0;
401
402 if (name && vm) {
403 name_ = name;
404 vm_ = vm;
405 status_ = status;
406 }
407
408 if (!name_ || !vm_)
409 return;
410
411 getmaxyx(action_window, rows, cols);
412
413 nm_str_format(&buf, "%-12s%s", "arch: ",
414 nm_vect_str_ctx(&vm_->main, NM_SQL_ARCH));
415 NM_PR_VM_INFO();
416
417 nm_parse_smp(&cpu, nm_vect_str_ctx(&vm_->main, NM_SQL_SMP));
418 nm_str_format(&buf, "%-12s%zu %s (%zu %s), threads %zu", "cpu: ",
419 (cpu.sockets) ? cpu.sockets : cpu.smp,
420 (cpu.sockets > 1) ? "cpus" : "cpu",
421 (cpu.cores) ? cpu.cores : 1,
422 (cpu.cores > 1) ? "cores" : "core",
423 cpu.smp);
424 NM_PR_VM_INFO();
425
426 nm_str_format(&buf, "%-12s%s %s", "memory: ",
427 nm_vect_str_ctx(&vm_->main, NM_SQL_MEM), "Mb");
428 NM_PR_VM_INFO();
429
430 if (nm_str_cmp_st(nm_vect_str(&vm_->main, NM_SQL_KVM), NM_ENABLE) == NM_OK) {
431 if (nm_str_cmp_st(nm_vect_str(&vm_->main, NM_SQL_HCPU), NM_ENABLE) == NM_OK)
432 nm_str_format(&buf, "%-12s%s", "kvm: ", "enabled [+hostcpu]");
433 else
434 nm_str_format(&buf, "%-12s%s", "kvm: ", "enabled");
435 } else {
436 nm_str_format(&buf, "%-12s%s", "kvm: ", "disabled");
437 }
438 NM_PR_VM_INFO();
439
440 if (nm_str_cmp_st(nm_vect_str(&vm_->main, NM_SQL_USBF), "1") == NM_OK) {
441 nm_str_format(&buf, "%-12s%s [%s]", "usb: ", "enabled",
442 nm_vect_str_ctx(&vm_->main, NM_SQL_USBT));
443 } else {
444 nm_str_format(&buf, "%-12s%s", "usb: ", "disabled");
445 }
446 NM_PR_VM_INFO();
447
448 {
449 nm_vect_t usb_names = NM_INIT_VECT;
450
451 nm_usb_unplug_list(&vm_->usb, &usb_names, false);
452
453 for (size_t n = 0; n < usb_names.n_memb; n++) {
454 ch1 = (n != (usb_names.n_memb - 1)) ? ACS_LTEE : ACS_LLCORNER;
455 ch2 = ACS_HLINE;
456 nm_str_format(&buf, "%s", (char *) usb_names.data[n]);
457 NM_PR_VM_INFO();
458 }
459
460 nm_vect_free(&usb_names, NULL);
461 ch1 = ch2 = 0;
462 }
463
464 nm_str_format(&buf, "%-12s%s [%u]", "vnc port: ",
465 nm_vect_str_ctx(&vm_->main, NM_SQL_VNC),
466 nm_str_stoui(nm_vect_str(&vm_->main, NM_SQL_VNC), 10) + NM_STARTING_VNC_PORT);
467 NM_PR_VM_INFO();
468
469 /* print network interfaces info */
470 ifs_count = vm_->ifs.n_memb / NM_IFS_IDX_COUNT;
471
472 for (size_t n = 0; n < ifs_count; n++) {
473 size_t idx_shift = NM_IFS_IDX_COUNT * n;
474 if (nm_str_cmp_st(nm_vect_str(&vm_->ifs, NM_SQL_IF_USR + idx_shift),
475 NM_ENABLE) == NM_OK) {
476 nm_str_format(&buf, "eth%zu%-8s%s [user mode]",
477 n, ":",
478 nm_vect_str_ctx(&vm_->ifs, NM_SQL_IF_NAME + idx_shift));
479 } else {
480 nm_str_format(&buf, "eth%zu%-8s%s [%s %s%s]",
481 n, ":",
482 nm_vect_str_ctx(&vm_->ifs, NM_SQL_IF_NAME + idx_shift),
483 nm_vect_str_ctx(&vm_->ifs, NM_SQL_IF_MAC + idx_shift),
484 nm_vect_str_ctx(&vm_->ifs, NM_SQL_IF_DRV + idx_shift),
485 (nm_str_cmp_st(nm_vect_str(&vm_->ifs, NM_SQL_IF_VHO + idx_shift),
486 NM_ENABLE) == NM_OK) ? "+vhost" : "");
487 }
488
489 NM_PR_VM_INFO();
490 }
491
492 /* print drives info */
493 drives_count = vm_->drives.n_memb / NM_DRV_IDX_COUNT;
494
495 for (size_t n = 0; n < drives_count; n++) {
496 size_t idx_shift = NM_DRV_IDX_COUNT * n;
497 int boot = 0;
498
499 if (nm_str_cmp_st(nm_vect_str(&vm_->drives, NM_SQL_DRV_BOOT + idx_shift),
500 NM_ENABLE) == NM_OK) {
501 boot = 1;
502 }
503
504 nm_str_format(&buf, "disk%zu%-7s%s [%sGb %s discard=%s] %s", n, ":",
505 nm_vect_str_ctx(&vm_->drives, NM_SQL_DRV_NAME + idx_shift),
506 nm_vect_str_ctx(&vm_->drives, NM_SQL_DRV_SIZE + idx_shift),
507 nm_vect_str_ctx(&vm_->drives, NM_SQL_DRV_TYPE + idx_shift),
508 (nm_str_cmp_st(nm_vect_str(&vm_->drives, NM_SQL_DRV_DISC + idx_shift),
509 NM_ENABLE) == NM_OK) ? "on" : "off",
510 boot ? "*" : "");
511 NM_PR_VM_INFO();
512 }
513
514 /* print 9pfs info */
515 if (nm_str_cmp_st(nm_vect_str(&vm_->main, NM_SQL_9FLG), "1") == NM_OK) {
516 nm_str_format(&buf, "%-12s%s [%s]", "9pfs: ",
517 nm_vect_str_ctx(&vm_->main, NM_SQL_9PTH),
518 nm_vect_str_ctx(&vm_->main, NM_SQL_9ID));
519 NM_PR_VM_INFO();
520 }
521
522 /* generate guest boot settings info */
523 if (nm_vect_str_len(&vm_->main, NM_SQL_MACH)) {
524 nm_str_format(&buf, "%-12s%s", "machine: ",
525 nm_vect_str_ctx(&vm_->main, NM_SQL_MACH));
526 NM_PR_VM_INFO();
527 }
528 if (nm_vect_str_len(&vm_->main, NM_SQL_BIOS)) {
529 nm_str_format(&buf,"%-12s%s", "bios: ",
530 nm_vect_str_ctx(&vm_->main, NM_SQL_BIOS));
531 NM_PR_VM_INFO();
532 }
533 if (nm_vect_str_len(&vm_->main, NM_SQL_KERN)) {
534 nm_str_format(&buf,"%-12s%s", "kernel: ",
535 nm_vect_str_ctx(&vm_->main, NM_SQL_KERN));
536 NM_PR_VM_INFO();
537 }
538 if (nm_vect_str_len(&vm_->main, NM_SQL_KAPP)) {
539 nm_str_format(&buf, "%-12s%s", "cmdline: ",
540 nm_vect_str_ctx(&vm_->main, NM_SQL_KAPP));
541 NM_PR_VM_INFO();
542 }
543 if (nm_vect_str_len(&vm_->main, NM_SQL_INIT)) {
544 nm_str_format(&buf, "%-12s%s", "initrd: ",
545 nm_vect_str_ctx(&vm_->main, NM_SQL_INIT));
546 NM_PR_VM_INFO();
547 }
548 if (nm_vect_str_len(&vm_->main, NM_SQL_TTY)) {
549 nm_str_format(&buf, "%-12s%s", "tty: ",
550 nm_vect_str_ctx(&vm_->main, NM_SQL_TTY));
551 NM_PR_VM_INFO();
552 }
553 if (nm_vect_str_len(&vm_->main, NM_SQL_SOCK)) {
554 nm_str_format(&buf, "%-12s%s", "socket: ",
555 nm_vect_str_ctx(&vm_->main, NM_SQL_SOCK));
556 NM_PR_VM_INFO();
557 }
558 if (nm_vect_str_len(&vm_->main, NM_SQL_DEBP)) {
559 nm_str_format(&buf, "%-12s%s", "gdb port: ",
560 nm_vect_str_ctx(&vm_->main, NM_SQL_DEBP));
561 NM_PR_VM_INFO();
562 }
563 if (nm_str_cmp_st(nm_vect_str(&vm_->main, NM_SQL_DEBF), NM_ENABLE) == NM_OK) {
564 nm_str_format(&buf, "%-12s", "freeze cpu: yes");
565 NM_PR_VM_INFO();
566 }
567 if (nm_vect_str_len(&vm_->main, NM_SQL_ARGS)) {
568 nm_str_format(&buf,"%-12s%s", "extra args: ",
569 nm_vect_str_ctx(&vm_->main, NM_SQL_ARGS));
570 NM_PR_VM_INFO();
571 }
572 if (nm_vect_str_len(&vm_->main, NM_SQL_GROUP)) {
573 nm_str_format(&buf,"%-12s%s", "group: ",
574 nm_vect_str_ctx(&vm_->main, NM_SQL_GROUP));
575 NM_PR_VM_INFO();
576 }
577
578 /* print host IP addresses for TAP ints */
579 for (size_t n = 0; n < ifs_count; n++) {
580 size_t idx_shift = NM_IFS_IDX_COUNT * n;
581
582 if (!nm_vect_str_len(&vm_->ifs, NM_SQL_IF_IP4 + idx_shift))
583 continue;
584
585 nm_str_format(&buf, "%-12s%s [%s]", "host IP: ",
586 nm_vect_str_ctx(&vm_->ifs, NM_SQL_IF_NAME + idx_shift),
587 nm_vect_str_ctx(&vm_->ifs, NM_SQL_IF_IP4 + idx_shift));
588 NM_PR_VM_INFO();
589
590 }
591
592 /* print PID */
593 {
594 int fd;
595 nm_str_t pid_path = NM_INIT_STR;
596
597 nm_str_format(&pid_path, "%s/%s/%s",
598 nm_cfg_get()->vm_dir.data, name_->data, NM_VM_PID_FILE);
599
600 if ((status_ && (fd = open(pid_path.data, O_RDONLY)) != -1)) {
601 char pid[10];
602 ssize_t nread;
603 int pid_num = 0;
604
605 if ((nread = read(fd, pid, sizeof(pid))) > 0) {
606 pid[nread - 1] = '\0';
607 pid_num = atoi(pid);
608
609 nm_str_format(&buf, "%-12s%d", "pid: ", pid_num);
610 NM_PR_VM_INFO();
611 }
612 close(fd);
613
614 #if defined (NM_OS_LINUX)
615 if (pid_num) {
616 double usage = nm_stat_get_usage(pid_num);
617 nm_str_format(&buf, "%-12s%0.1f%%", "cpu usage: ", usage);
618 mvwhline(action_window, y, 1, ' ', cols - 4);
619 NM_PR_VM_INFO();
620 }
621 #else
622 (void) pid_num;
623 #endif
624 } else { /* clear PID file info and cpu usage data */
625 if (y < (rows - 2)) {
626 mvwhline(action_window, y, 1, ' ', cols - 4);
627 mvwhline(action_window, y + 1, 1, ' ', cols - 4);
628 }
629 NM_STAT_CLEAN();
630 }
631
632 nm_str_free(&pid_path);
633 }
634
635 nm_str_free(&buf);
636 }
637
nm_lan_help(void)638 void nm_lan_help(void)
639 {
640 const char *keys[] = {
641 "a", "r", "u", "d"
642 };
643
644 const char *values[] = {
645 "add veth interface",
646 "remove veth interface",
647 "up veth interface",
648 "down veth interface",
649 NULL
650 };
651
652 size_t hotkey_num = nm_arr_len(keys);
653 size_t maxlen = nm_max_msg_len(values);
654
655 nm_print_help__(keys, values, hotkey_num, maxlen);
656 }
657
nm_print_help(void)658 void nm_print_help(void)
659 {
660 const char *keys[] = {
661 "r", "t",
662 #if defined(NM_WITH_VNC_CLIENT) || defined(NM_WITH_SPICE)
663 "c",
664 #endif
665 "p", "z", "f", "d", "y", "e",
666 "i", "C", "a", "l", "b", "h",
667 "m", "v", "u", "P", "R", "S",
668 "X", "D",
669 #if defined (NM_OS_LINUX)
670 "+", "-",
671 #endif
672 "k", "/"
673 };
674
675 const char *values[] = {
676 "start vm",
677 "start vm in temporary mode",
678 #if defined(NM_WITH_VNC_CLIENT) || defined(NM_WITH_SPICE)
679 "connect to vm",
680 #endif
681 "powerdown vm",
682 "reset vm",
683 "force stop vm",
684 "delete vm",
685 "rename vm",
686 "edit vm settings",
687 "edit network settings",
688 "edit viewer settings",
689 "add virtual disk",
690 "clone vm",
691 "edit boot settings",
692 "share host filesystem",
693 "show command",
694 "delete virtual disk",
695 "delete unused tap interfaces",
696 "pause vm",
697 "resume vm",
698 "take vm snapshot",
699 "revert vm snapshot",
700 "delete vm snapshot",
701 #if defined (NM_OS_LINUX)
702 "attach usb device",
703 "detach usb device",
704 #endif
705 "kill vm process",
706 "search vm, filters",
707 NULL
708 };
709
710 size_t hotkey_num = nm_arr_len(keys);
711 size_t maxlen = nm_max_msg_len(values);
712
713 nm_print_help__(keys, values, hotkey_num, maxlen);
714 }
715
716 static void
nm_print_help__(const char ** keys,const char ** values,size_t hotkey_num,size_t maxlen)717 nm_print_help__(const char **keys, const char **values,
718 size_t hotkey_num, size_t maxlen)
719 {
720 size_t cols, rows;
721 size_t n = 0;
722 int perc;
723 nm_str_t help_title = NM_INIT_STR;
724
725 getmaxyx(action_window, rows, cols);
726 rows -= 4;
727 cols -= 2;
728
729 if (maxlen + 10 > cols) {
730 nm_warn(_(NM_MSG_SMALL_WIN));
731 return;
732 }
733
734 perc = (hotkey_num > rows) ? ((rows * 100) / hotkey_num) : 100;
735 if (perc == 100)
736 nm_str_format(&help_title, _("nEMU %s - help [all]"), NM_VERSION);
737 else
738 nm_str_format(&help_title, _("nEMU %s - help [%d%%]") , NM_VERSION, perc);
739
740 werase(action_window);
741 nm_init_action(help_title.data);
742
743 for (size_t y = 3; n < rows && n < hotkey_num; n++, y++)
744 mvwprintw(action_window, y, 2, "%-10s%s", keys[n], values[n]);
745
746 if (perc != 100) {
747 size_t shift = 0;
748
749 for (;;) {
750 int ch = wgetch(action_window);
751
752 if (ch == NM_KEY_ENTER) {
753 size_t last = 0;
754
755 shift++;
756 n = shift;
757 werase(action_window);
758
759 for (size_t y = 3, l = 0; l < rows && n < hotkey_num; n++, y++, l++)
760 mvwprintw(action_window, y, 2, "%-10s%s", keys[n], values[n]);
761
762 last = n;
763 if (last < hotkey_num) {
764 perc = 100 * last / hotkey_num;
765 nm_str_format(&help_title, _("nEMU %s - help [%d%%]") , NM_VERSION, perc);
766 } else {
767 nm_str_format(&help_title, _("nEMU %s - help [end]"), NM_VERSION);
768 }
769
770 nm_init_action(help_title.data);
771
772 if (last >= hotkey_num) {
773 wgetch(action_window);
774 break;
775 }
776 } else {
777 break;
778 }
779 }
780 } else {
781 wgetch(action_window);
782 }
783
784 wrefresh(action_window);
785 nm_init_action(NULL);
786 nm_str_free(&help_title);
787 }
788
nm_align2line(nm_str_t * str,size_t line_len)789 void nm_align2line(nm_str_t *str, size_t line_len)
790 {
791 if (line_len <= 4)
792 return;
793
794 if (str->len > (line_len - 4)) {
795 nm_str_trunc(str, line_len - 7);
796 nm_str_add_text(str, "...");
797 }
798 }
799
nm_max_msg_len(const char ** msg)800 size_t nm_max_msg_len(const char **msg)
801 {
802 if (!msg)
803 return 0;
804
805 size_t len = 0;
806
807 while (*msg) {
808 size_t mb_len = mbstowcs(NULL, _(*msg), strlen(_(*msg)));
809 len = (mb_len > len) ? mb_len : len;
810 msg++;
811 }
812
813 return len;
814 }
815
nm_warn__(const char * msg,int red)816 static int nm_warn__(const char *msg, int red)
817 {
818 if (!msg)
819 return ERR;
820
821 int ch;
822
823 werase(help_window);
824 nm_init_help(msg, red);
825 while ((ch = wgetch(help_window)) == KEY_RESIZE);
826 werase(help_window);
827 nm_init_help_main();
828
829 return ch;
830 }
831
nm_warn(const char * msg)832 int nm_warn(const char *msg)
833 {
834 return nm_warn__(msg, NM_TRUE);
835 }
836
nm_notify(const char * msg)837 int nm_notify(const char *msg)
838 {
839 return nm_warn__(msg, NM_FALSE);
840 }
841
nm_window_scale_inc(void)842 int nm_window_scale_inc(void)
843 {
844 if (nm_window_scale > 0.8)
845 return NM_ERR;
846
847 nm_window_scale += 0.02;
848
849 return NM_OK;
850 }
851
nm_window_scale_dec(void)852 int nm_window_scale_dec(void)
853 {
854 if (nm_window_scale < 0.2)
855 return NM_ERR;
856
857 nm_window_scale -= 0.02;
858
859 return NM_OK;
860 }
861
862 /* vim:set ts=4 sw=4: */
863