]> git.ipfire.org Git - thirdparty/util-linux.git/blame - fdisks/cfdisk.c
cfdisk: update menu according to the current partition
[thirdparty/util-linux.git] / fdisks / cfdisk.c
CommitLineData
6dbe3af9
KZ
1#include <stdlib.h>
2#include <stdio.h>
6dbe3af9 3#include <errno.h>
8c3a5a44 4#include <signal.h>
00b4f26a 5#include <ctype.h>
541e6934
KZ
6
7#ifdef HAVE_SLANG_H
8#include <slang.h>
9#elif defined(HAVE_SLANG_SLANG_H)
10#include <slang/slang.h>
11#endif
12
48d7b13a
KZ
13#ifdef HAVE_SLCURSES_H
14#include <slcurses.h>
15#elif defined(HAVE_SLANG_SLCURSES_H)
16#include <slang/slcurses.h>
30c97bb8
MF
17#elif defined(HAVE_NCURSESW_NCURSES_H) && defined(HAVE_WIDECHAR)
18#include <ncursesw/ncurses.h>
48d7b13a
KZ
19#elif defined(HAVE_NCURSES_H)
20#include <ncurses.h>
21#elif defined(HAVE_NCURSES_NCURSES_H)
22#include <ncurses/ncurses.h>
2b6fc908 23#endif
541e6934 24
5f94ca33
KZ
25#ifdef HAVE_WIDECHAR
26#include <wctype.h>
27#endif
28
8c3a5a44 29#include "c.h"
b2d28533 30#include "closestream.h"
7eda085c 31#include "nls.h"
8abcf290 32#include "strutils.h"
8c3a5a44 33#include "xalloc.h"
5f94ca33 34#include "mbsalign.h"
6dbe3af9 35
8c3a5a44
KZ
36#include "fdiskP.h"
37
38#define ARROW_CURSOR_STRING ">>> "
39#define ARROW_CURSOR_DUMMY " "
40#define ARROW_CURSOR_WIDTH (sizeof(ARROW_CURSOR_STRING) - 1)
41
42#define MENU_PADDING 2
43#define TABLE_START_LINE 4
44#define MENU_START_LINE (LINES - 5)
45
8460875d
KZ
46struct cfdisk;
47typedef int (menu_callback_t)(struct cfdisk *, int);
48
49static int menu_cb_main(struct cfdisk *cf, int key);
50
8c3a5a44
KZ
51
52struct cfdisk_menudesc {
53 int key; /* keyboard shortcut */
54 const char *name; /* item name */
55 const char *desc; /* item description */
749af4b6
KZ
56};
57
8c3a5a44
KZ
58struct cfdisk_menu {
59 struct cfdisk_menudesc *desc;
60 char *ignore;
61 size_t id;
62 size_t width;
63 size_t nitems;
8460875d
KZ
64
65 menu_callback_t *callback;
66
8c3a5a44 67 struct cfdisk_menu *prev;
749af4b6
KZ
68};
69
8c3a5a44
KZ
70static struct cfdisk_menudesc menu_main[] = {
71 { 'b', N_("Bootable"), N_("Toggle bootable flag of the current partition") },
72 { 'd', N_("Delete"), N_("Delete the current partition") },
73// { 'g', N_("Geometry"), N_("Change disk geometry (experts only)") },
74// { 'h', N_("Help"), N_("Print help screen") },
75// { 'm', N_("Maximize"), N_("Maximize disk usage of the current partition (experts only)") },
76 { 'n', N_("New"), N_("Create new partition from free space") },
77// { 'p', N_("Print"), N_("Print partition table to the screen or to a file") },
78 { 'q', N_("Quit"), N_("Quit program without writing partition table") },
79 { 't', N_("Type"), N_("Change the partition type") },
80// { 'u', N_("Units"), N_("Change units of the partition size display (MB, sect, cyl)") },
81 { 'W', N_("Write"), N_("Write partition table to disk (this might destroy data)") },
82 { 0, NULL, NULL }
83};
6dbe3af9 84
8c3a5a44
KZ
85enum {
86 CFDISK_MENU_MAIN = 0,
5c36a0eb
KZ
87};
88
8c3a5a44
KZ
89static struct cfdisk_menudesc *menus[] = {
90 [CFDISK_MENU_MAIN] = menu_main
91};
7eda085c 92
8460875d
KZ
93static menu_callback_t *menu_callbacks[] = {
94 [CFDISK_MENU_MAIN] = menu_cb_main
95};
96
97
8c3a5a44
KZ
98struct cfdisk {
99 struct fdisk_context *cxt; /* libfdisk context */
100 struct fdisk_table *table; /* partition table */
7eda085c 101
8c3a5a44
KZ
102 struct cfdisk_menu *menu; /* the current menu */
103 size_t menu_idx;
7eda085c 104
8c3a5a44
KZ
105 int *cols; /* output columns */
106 size_t ncols; /* number of columns */
7eda085c 107
8c3a5a44
KZ
108 char *linesbuf; /* table as string */
109 size_t linesbufsz; /* size of the tb_buf */
7eda085c 110
8c3a5a44
KZ
111 char **lines; /* array with lines */
112 size_t nlines; /* number of lines */
113 size_t lines_idx; /* current line <0..N>, exclude header */
5c36a0eb 114
8c3a5a44
KZ
115 unsigned int ui_enabled : 1;
116};
5c36a0eb 117
8c3a5a44
KZ
118static int cols_init(struct cfdisk *cf)
119{
120 assert(cf);
5c36a0eb 121
8c3a5a44
KZ
122 free(cf->cols);
123 cf->cols = NULL;
124 cf->ncols = 0;
5c36a0eb 125
8c3a5a44 126 return fdisk_get_columns(cf->cxt, 0, &cf->cols, &cf->ncols);
5c36a0eb
KZ
127}
128
8c3a5a44
KZ
129/* It would be possible to use fdisk_table_to_string(), but we want some
130 * extension to the output format, so let's do it without libfdisk
131 */
132static char *table_to_string(struct cfdisk *cf, struct fdisk_table *tb)
133{
134 struct fdisk_partition *pa;
135 const struct fdisk_column *col;
136 struct fdisk_label *lb;
137 struct fdisk_iter *itr = NULL;
138 struct tt *tt = NULL;
139 char *res = NULL;
140 size_t i;
141
142 DBG(FRONTEND, dbgprint("table: convert to string"));
143
144 assert(cf);
145 assert(cf->cxt);
146 assert(cf->cols);
147 assert(tb);
148
149 lb = fdisk_context_get_label(cf->cxt, NULL);
150 assert(lb);
151
152 tt = tt_new_table(TT_FL_FREEDATA | TT_FL_MAX);
153 if (!tt)
154 goto done;
155 itr = fdisk_new_iter(FDISK_ITER_FORWARD);
156 if (!itr)
157 goto done;
5c36a0eb 158
8c3a5a44
KZ
159 /* headers */
160 for (i = 0; i < cf->ncols; i++) {
161 col = fdisk_label_get_column(lb, cf->cols[i]);
162 if (col)
163 tt_define_column(tt, col->name,
164 col->width,
165 col->tt_flags);
166 }
167
168 /* data */
169 while (fdisk_table_next_partition(tb, itr, &pa) == 0) {
170 struct tt_line *ln = tt_add_line(tt, NULL);
171 if (!ln)
172 goto done;
173 for (i = 0; i < cf->ncols; i++) {
174 char *cdata = NULL;
175
176 col = fdisk_label_get_column(lb, cf->cols[i]);
177 if (!col)
178 continue;
179 if (fdisk_partition_to_string(pa, cf->cxt, col->id, &cdata))
180 continue;
181 tt_line_set_data(ln, i, cdata);
182 }
183 }
6dbe3af9 184
8c3a5a44
KZ
185 if (!tt_is_empty(tt)) {
186 tt_set_termreduce(tt, ARROW_CURSOR_WIDTH);
187 tt_print_table_to_string(tt, &res);
188 }
189done:
190 tt_free_table(tt);
191 fdisk_free_iter(itr);
6dbe3af9 192
8c3a5a44 193 return res;
2b6fc908
KZ
194}
195
8460875d 196static int lines_refresh(struct cfdisk *cf)
8c3a5a44
KZ
197{
198 int rc;
199 char *p;
200 size_t i;
7eda085c 201
8c3a5a44 202 assert(cf);
2b6fc908 203
8c3a5a44 204 DBG(FRONTEND, dbgprint("refresing buffer"));
c64061c9 205
8c3a5a44
KZ
206 free(cf->linesbuf);
207 free(cf->lines);
208 cf->linesbuf = NULL;
209 cf->linesbufsz = 0;
210 cf->lines = NULL;
211 cf->nlines = 0;
6dbe3af9 212
8c3a5a44
KZ
213 fdisk_unref_table(cf->table);
214 fdisk_context_enable_freespace(cf->cxt, 1);
6dbe3af9 215
8c3a5a44
KZ
216 rc = fdisk_get_table(cf->cxt, &cf->table);
217 if (rc)
218 return rc;
0d8589c5 219
8c3a5a44
KZ
220 cf->linesbuf = table_to_string(cf, cf->table);
221 if (!cf->linesbuf)
222 return -ENOMEM;
6dbe3af9 223
8c3a5a44
KZ
224 cf->linesbufsz = strlen(cf->linesbuf);
225 cf->nlines = fdisk_table_get_nents(cf->table) + 1; /* 1 for header line */
6dbe3af9 226
8c3a5a44
KZ
227 cf->lines = calloc(cf->nlines, sizeof(char *));
228 if (!cf->lines)
229 return -ENOMEM;
6dbe3af9 230
8c3a5a44
KZ
231 for (p = cf->linesbuf, i = 0; p && i < cf->nlines; i++) {
232 cf->lines[i] = p;
233 p = strchr(p, '\n');
234 if (p) {
235 *p = '\0';
236 p++;
237 }
238 }
6dbe3af9 239
8c3a5a44 240 return 0;
6dbe3af9
KZ
241}
242
00b4f26a
KZ
243static struct fdisk_partition *get_current_partition(struct cfdisk *cf)
244{
245 assert(cf);
246 assert(cf->table);
247
248 return fdisk_table_get_partition(cf->table, cf->lines_idx);
249}
250
8c3a5a44
KZ
251static int ask_callback(struct fdisk_context *cxt, struct fdisk_ask *ask,
252 void *data __attribute__((__unused__)))
253{
254 int rc = 0;
6dbe3af9 255
8c3a5a44
KZ
256 assert(cxt);
257 assert(ask);
6dbe3af9 258
8c3a5a44
KZ
259 switch(fdisk_ask_get_type(ask)) {
260 case FDISK_ASKTYPE_INFO:
261 fputs(fdisk_ask_print_get_mesg(ask), stdout);
262 fputc('\n', stdout);
263 break;
264 case FDISK_ASKTYPE_WARNX:
265 fputs(fdisk_ask_print_get_mesg(ask), stderr);
266 fputc('\n', stderr);
267 break;
268 case FDISK_ASKTYPE_WARN:
269 fputs(fdisk_ask_print_get_mesg(ask), stderr);
270 errno = fdisk_ask_print_get_errno(ask);
271 fprintf(stderr, ": %m\n");
272 break;
273 default:
274 warnx(_("internal error: unsupported dialog type %d"), fdisk_ask_get_type(ask));
275 return -EINVAL;
276 }
277 return rc;
fd6b7a7f 278}
6dbe3af9 279
6dbe3af9 280
8c3a5a44
KZ
281static int ui_end(struct cfdisk *cf)
282{
283 if (cf && !cf->ui_enabled)
284 return -EINVAL;
285
48d7b13a 286#if defined(HAVE_SLCURSES_H) || defined(HAVE_SLANG_SLCURSES_H)
8c3a5a44
KZ
287 SLsmg_gotorc(LINES - 1, 0);
288 SLsmg_refresh();
2b6fc908 289#else
8c3a5a44 290 mvcur(0, COLS - 1, LINES-1, 0);
2b6fc908 291#endif
8c3a5a44
KZ
292 nl();
293 endwin();
294 printf("\n");
295 return 0;
6dbe3af9
KZ
296}
297
8c3a5a44 298static void ui_print_center(int line, const char *fmt, ...)
f609e92e 299{
8c3a5a44
KZ
300 size_t width;
301 va_list ap;
302 char *buf = NULL;
f609e92e 303
8c3a5a44
KZ
304 move(line, 0);
305 clrtoeol();
f609e92e 306
8c3a5a44
KZ
307 va_start(ap, fmt);
308 xvasprintf(&buf, fmt, ap);
309 va_end(ap);
fd6b7a7f 310
8c3a5a44
KZ
311 width = strlen(buf); /* TODO: count cells! */
312 mvaddstr(line, (COLS - width) / 2, buf);
313 free(buf);
6dbe3af9
KZ
314}
315
6dbe3af9 316
8c3a5a44
KZ
317static void die_on_signal(int dummy __attribute__((__unused__)))
318{
319 ui_end(NULL);
320 exit(EXIT_FAILURE);
6dbe3af9
KZ
321}
322
8c3a5a44
KZ
323static void menu_update_ignore(struct cfdisk *cf)
324{
00b4f26a
KZ
325 char ignore[128] = { 0 };
326 int i = 0;
327 struct fdisk_partition *pa;
8c3a5a44
KZ
328 struct cfdisk_menu *m;
329 struct cfdisk_menudesc *d;
6dbe3af9 330
8c3a5a44 331 assert(cf);
6dbe3af9 332
8c3a5a44
KZ
333 m = cf->menu;
334 DBG(FRONTEND, dbgprint("menu: update menu ignored keys"));
6dbe3af9 335
8c3a5a44
KZ
336 switch (m->id) {
337 case CFDISK_MENU_MAIN:
00b4f26a
KZ
338 pa = get_current_partition(cf);
339 if (!pa)
340 break;
341 if (fdisk_partition_is_freespace(pa)) {
342 ignore[i++] = 'd'; /* delete */
343 ignore[i++] = 't'; /* set type */
344 ignore[i++] = 'b'; /* set bootable */
345 } else
346 ignore[i++] = 'n';
347
8c3a5a44 348 break;
fd6b7a7f 349 }
6dbe3af9 350
00b4f26a
KZ
351 ignore[i] = '\0';
352
8c3a5a44 353 /* return if no change */
00b4f26a
KZ
354 if ( (!m->ignore && !*ignore)
355 || (m->ignore && *ignore && strcmp(m->ignore, ignore) == 0)) {
8c3a5a44 356 return;
fd6b7a7f 357 }
6dbe3af9 358
8c3a5a44 359 free(m->ignore);
8460875d 360 m->ignore = xstrdup(ignore);
8c3a5a44 361 m->nitems = 0;
6dbe3af9 362
8c3a5a44
KZ
363 for (d = m->desc; d->name; d++) {
364 if (m->ignore && strchr(m->ignore, d->key))
8460875d
KZ
365 continue;
366 m->nitems++;
8c3a5a44 367 }
6dbe3af9
KZ
368}
369
8c3a5a44
KZ
370static struct cfdisk_menu *menu_push(struct cfdisk *cf, size_t id)
371{
372 struct cfdisk_menu *m = xcalloc(1, sizeof(*m));
373 struct cfdisk_menudesc *d;
6dbe3af9 374
8c3a5a44
KZ
375 assert(cf);
376 assert(id < ARRAY_SIZE(menus));
6dbe3af9 377
8c3a5a44 378 DBG(FRONTEND, dbgprint("menu: new menu"));
6dbe3af9 379
8c3a5a44
KZ
380 m->prev = cf->menu;
381 m->id = id;
382 m->desc = menus[id];
8460875d 383 m->callback = menu_callbacks[id];
6dbe3af9 384
8c3a5a44
KZ
385 for (d = m->desc; d->name; d++) {
386 const char *name = _(d->name);
387 size_t len = strlen(name); /* TODO: we care about cells! */
388 if (len > m->width)
389 m->width = len;
390 m->nitems++;
391 }
6dbe3af9 392
8c3a5a44
KZ
393 cf->menu = m;
394 return m;
6dbe3af9
KZ
395}
396
8c3a5a44 397static struct cfdisk_menu *menu_pop(struct cfdisk *cf)
6dbe3af9 398{
8c3a5a44 399 struct cfdisk_menu *m = NULL;
6dbe3af9 400
8c3a5a44 401 assert(cf);
7eda085c 402
8c3a5a44 403 DBG(FRONTEND, dbgprint("menu: rem menu"));
7eda085c 404
8c3a5a44
KZ
405 if (cf->menu) {
406 m = cf->menu->prev;
407 free(cf->menu->ignore);
408 free(cf->menu);
c07ebfa1 409 }
8c3a5a44
KZ
410 cf->menu = m;
411 return cf->menu;
6dbe3af9
KZ
412}
413
8460875d
KZ
414/* returns: error: < 0, success: 0, quit: 1 */
415static int menu_cb_main(struct cfdisk *cf, int key)
416{
417 switch (key) {
418 case 'd': /* Delete */
419 break;
420 case 'n': /* New */
421 break;
422 case 'q': /* Quit */
423 return 1;
424 case 't': /* Type */
425 break;
426 case 'W': /* Write */
427 break;
428 default:
429 return -EINVAL;
430 }
431 return 0;
432}
7eda085c 433
8c3a5a44
KZ
434static int ui_init(struct cfdisk *cf)
435{
436 struct sigaction sa;
6dbe3af9 437
8c3a5a44 438 DBG(FRONTEND, dbgprint("ui: init"));
6dbe3af9 439
8c3a5a44
KZ
440 /* setup SIGCHLD handler */
441 sigemptyset(&sa.sa_mask);
442 sa.sa_flags = 0;
443 sa.sa_handler = die_on_signal;
444 sigaction(SIGINT, &sa, NULL);
445 sigaction(SIGTERM, &sa, NULL);
6dbe3af9 446
8c3a5a44
KZ
447 cf->ui_enabled = 1;
448 initscr();
6dbe3af9 449
8c3a5a44
KZ
450 cbreak();
451 noecho();
452 nonl();
453 curs_set(0);
454 keypad(stdscr, TRUE);
6dbe3af9 455
8c3a5a44 456 return 0;
7eda085c
KZ
457}
458
8c3a5a44
KZ
459static size_t menuitem_get_line(struct cfdisk *cf, size_t idx)
460{
461 size_t len = cf->menu->width + 4 + MENU_PADDING; /* item width */
462 size_t items = COLS / len; /* items per line */
7eda085c 463
8c3a5a44 464 return MENU_START_LINE + ((idx / items));
7eda085c
KZ
465}
466
8c3a5a44
KZ
467static int menuitem_get_column(struct cfdisk *cf, size_t idx)
468{
469 size_t len = cf->menu->width + 4 + MENU_PADDING; /* item width */
470 size_t items = COLS / len; /* items per line */
471 size_t extra = items < cf->menu->nitems ? /* extra space on line */
472 COLS % len : /* - multi-line menu */
473 COLS - (cf->menu->nitems * len); /* - one line menu */
df1dddf9 474
8c3a5a44 475 extra += MENU_PADDING; /* add padding after last item to extra */
e66ac5d3 476
8c3a5a44
KZ
477 if (idx < items)
478 return (idx * len) + (extra / 2);
479 return ((idx % items) * len) + (extra / 2);
df1dddf9
KZ
480}
481
8c3a5a44
KZ
482static struct cfdisk_menudesc *menu_get_menuitem(struct cfdisk *cf, size_t idx)
483{
484 struct cfdisk_menudesc *d;
485 size_t i;
7eda085c 486
8c3a5a44
KZ
487 for (i = 0, d = cf->menu->desc; d->name; d++) {
488 if (cf->menu->ignore && strchr(cf->menu->ignore, d->key))
489 continue;
490 if (i++ == idx)
491 return d;
d26aa358 492 }
7eda085c 493
8c3a5a44 494 return NULL;
6dbe3af9
KZ
495}
496
8c3a5a44
KZ
497static void ui_draw_menuitem(struct cfdisk *cf,
498 struct cfdisk_menudesc *d,
499 size_t idx)
500{
501 char buf[80 * MB_CUR_MAX];
502 const char *name;
503 size_t width = cf->menu->width + 2; /* 2 = blank around string */
504 int ln, cl;
505
506 name = _(d->name);
507 mbsalign(name, buf, sizeof(buf), &width, MBS_ALIGN_CENTER, 0);
508
509 ln = menuitem_get_line(cf, idx);
510 cl = menuitem_get_column(cf, idx);
511
512 DBG(FRONTEND, dbgprint("ui: menuitem: cl=%d, ln=%d, item='%s'",
513 cl, ln, buf));
514
515 if (cf->menu_idx == idx) {
516 standout();
517 mvprintw(ln, cl, "[%s]", buf);
518 standend();
519 if (d->desc)
520 ui_print_center(LINES - 1, d->desc);
521 } else
522 mvprintw(ln, cl, "[%s]", buf);
6dbe3af9
KZ
523}
524
8c3a5a44
KZ
525static void ui_draw_menu(struct cfdisk *cf)
526{
527 struct cfdisk_menudesc *d;
528 size_t i = 0;
7eda085c 529
8c3a5a44
KZ
530 assert(cf);
531 assert(cf->menu);
fd6b7a7f 532
8c3a5a44 533 DBG(FRONTEND, dbgprint("ui: menu: draw start"));
6dbe3af9 534
00b4f26a
KZ
535 for (i = MENU_START_LINE; i < (size_t) LINES - 1; i++) {
536 move(i, 0);
537 clrtoeol();
538 }
539
8c3a5a44 540 menu_update_ignore(cf);
6dbe3af9 541
00b4f26a 542 i = 0;
8c3a5a44
KZ
543 while ((d = menu_get_menuitem(cf, i)))
544 ui_draw_menuitem(cf, d, i++);
6dbe3af9 545
8c3a5a44 546 DBG(FRONTEND, dbgprint("ui: menu: draw end."));
6dbe3af9
KZ
547}
548
8c3a5a44
KZ
549static void ui_menu_goto(struct cfdisk *cf, int where)
550{
551 struct cfdisk_menudesc *d;
552 size_t old;
553
554 if (where < 0)
555 where = cf->menu->nitems - 1;
556 else if ((size_t) where > cf->menu->nitems - 1)
557 where = 0;
558 if ((size_t) where == cf->menu_idx)
559 return;
6dbe3af9 560
8c3a5a44
KZ
561 old = cf->menu_idx;
562 cf->menu_idx = where;
6dbe3af9 563
8c3a5a44
KZ
564 d = menu_get_menuitem(cf, old);
565 ui_draw_menuitem(cf, d, old);
6dbe3af9 566
8c3a5a44
KZ
567 d = menu_get_menuitem(cf, where);
568 ui_draw_menuitem(cf, d, where);
6dbe3af9
KZ
569}
570
8460875d 571/* returns: error: < 0, success: 0, quit: 1 */
8c3a5a44
KZ
572static int ui_menu_action(struct cfdisk *cf, int key)
573{
8460875d
KZ
574 assert(cf);
575 assert(cf->menu);
576 assert(cf->menu->callback);
577
578 if (key == 0) {
579 struct cfdisk_menudesc *d = menu_get_menuitem(cf, cf->menu_idx);
580 if (!d)
581 return 0;
582 key = d->key;
00b4f26a
KZ
583
584 } else if (key != 'w' && key != 'W')
585 key = tolower(key); /* case insensitive except 'W'rite */
8460875d
KZ
586
587 DBG(FRONTEND, dbgprint("ui: menu action: key=%c", key));
588
589 if (cf->menu->ignore && strchr(cf->menu->ignore, key)) {
590 DBG(FRONTEND, dbgprint(" ignore '%c'", key));
591 return 0;
592 }
593
594 return cf->menu->callback(cf, key);
6dbe3af9
KZ
595}
596
8c3a5a44
KZ
597static void ui_draw_partition(struct cfdisk *cf, size_t i)
598{
599 int ln = TABLE_START_LINE + 1 + i; /* skip table header */
600 int cl = ARROW_CURSOR_WIDTH; /* we need extra space for cursor */
6dbe3af9 601
8c3a5a44 602 DBG(FRONTEND, dbgprint("ui: draw partition %zu", i));
6dbe3af9 603
8c3a5a44
KZ
604 if (cf->lines_idx == i) {
605 standout();
606 mvaddstr(ln, 0, ARROW_CURSOR_STRING);
607 mvaddstr(ln, cl, cf->lines[i + 1]);
608 standend();
6dbe3af9 609 } else {
8c3a5a44
KZ
610 mvaddstr(ln, 0, ARROW_CURSOR_DUMMY);
611 mvaddstr(ln, cl, cf->lines[i + 1]);
6dbe3af9
KZ
612 }
613
6dbe3af9
KZ
614}
615
8c3a5a44
KZ
616static int ui_draw_table(struct cfdisk *cf)
617{
618 int cl = ARROW_CURSOR_WIDTH;
619 size_t i, nparts = fdisk_table_get_nents(cf->table);
7eda085c 620
8c3a5a44 621 DBG(FRONTEND, dbgprint("ui: draw table"));
6dbe3af9 622
8c3a5a44
KZ
623 if (cf->nlines - 2 < cf->lines_idx)
624 cf->lines_idx = cf->nlines - 2; /* don't count header */
6dbe3af9 625
8c3a5a44
KZ
626 /* print header */
627 attron(A_BOLD);
628 mvaddstr(TABLE_START_LINE, cl, cf->lines[0]);
629 attroff(A_BOLD);
6dbe3af9 630
8c3a5a44
KZ
631 /* print partitions */
632 for (i = 0; i < nparts; i++)
633 ui_draw_partition(cf, i);
6dbe3af9 634
8c3a5a44 635 return 0;
6dbe3af9
KZ
636}
637
8c3a5a44
KZ
638static int ui_table_goto(struct cfdisk *cf, int where)
639{
640 size_t old;
641 size_t nparts = fdisk_table_get_nents(cf->table);
6dbe3af9 642
8c3a5a44 643 DBG(FRONTEND, dbgprint("ui: goto table %d", where));
6dbe3af9 644
8c3a5a44
KZ
645 if (where < 0)
646 where = 0;
647 else if ((size_t) where > nparts - 1)
648 where = nparts - 1;
6dbe3af9 649
8c3a5a44
KZ
650 if ((size_t) where == cf->lines_idx)
651 return 0;
6dbe3af9 652
8c3a5a44
KZ
653 old = cf->lines_idx;
654 cf->lines_idx = where;
6dbe3af9 655
8c3a5a44
KZ
656 ui_draw_partition(cf, old); /* cleanup old */
657 ui_draw_partition(cf, where); /* draw new */
658 ui_draw_menu(cf);
659 refresh();
660 return 0;
6dbe3af9
KZ
661}
662
8c3a5a44
KZ
663static int ui_refresh(struct cfdisk *cf)
664{
665 char *id = NULL;
666 uint64_t bytes = cf->cxt->total_sectors * cf->cxt->sector_size;
667 char *strsz = size_to_human_string(SIZE_SUFFIX_SPACE
668 | SIZE_SUFFIX_3LETTER, bytes);
669 erase();
670
671 if (!cf->ui_enabled)
672 return -EINVAL;
673
674 /* header */
675 attron(A_BOLD);
676 ui_print_center(0, _("Disk: %s"), cf->cxt->dev_path);
677 attroff(A_BOLD);
678 ui_print_center(1, _("Size: %s, %ju bytes, %ju sectors"),
679 strsz, bytes, (uintmax_t) cf->cxt->total_sectors);
680 if (fdisk_get_disklabel_id(cf->cxt, &id) == 0 && id)
681 ui_print_center(2, _("Label: %s, identifier: %s"),
682 cf->cxt->label->name, id);
7eda085c 683 else
8c3a5a44
KZ
684 ui_print_center(2, _("Label: %s"));
685 free(strsz);
6dbe3af9 686
8c3a5a44
KZ
687 ui_draw_table(cf);
688 ui_draw_menu(cf);
6dbe3af9 689 refresh();
8c3a5a44 690 return 0;
6dbe3af9
KZ
691}
692
8c3a5a44
KZ
693static int ui_run(struct cfdisk *cf)
694{
695 int rc;
6dbe3af9 696
8c3a5a44 697 DBG(FRONTEND, dbgprint("ui: start COLS=%d, LINES=%d", COLS, LINES));
6dbe3af9 698
8c3a5a44 699 menu_push(cf, CFDISK_MENU_MAIN);
6dbe3af9 700
8c3a5a44
KZ
701 rc = ui_refresh(cf);
702 if (rc)
703 return rc;
6dbe3af9 704
8c3a5a44 705 do {
8460875d 706 int rc = 0, key = getch();
6dbe3af9 707
8c3a5a44
KZ
708 switch (key) {
709 case KEY_DOWN:
710 case '\016': /* ^N */
711 case 'j': /* Vi-like alternative */
712 ui_table_goto(cf, cf->lines_idx + 1);
713 break;
714 case KEY_UP:
715 case '\020': /* ^P */
716 case 'k': /* Vi-like alternative */
717 ui_table_goto(cf, cf->lines_idx - 1);
718 break;
719 case KEY_HOME:
720 ui_table_goto(cf, 0);
721 break;
722 case KEY_END:
723 ui_table_goto(cf, cf->nlines - 1);
724 break;
725 ui_menu_action(cf, 0);
726 break;
727 case KEY_LEFT:
728#ifdef KEY_BTAB
729 case KEY_BTAB:
6dbe3af9 730#endif
8c3a5a44
KZ
731 ui_menu_goto(cf, cf->menu_idx - 1);
732 break;
733 case KEY_RIGHT:
734 case '\t':
735 ui_menu_goto(cf, cf->menu_idx + 1);
736 break;
737 case KEY_ENTER:
738 case '\n':
739 case '\r':
8460875d 740 rc = ui_menu_action(cf, 0);
8c3a5a44
KZ
741 break;
742 default:
8460875d
KZ
743 rc = ui_menu_action(cf, key);
744 if (rc < 0)
8c3a5a44
KZ
745 beep();
746 break;
747 }
8460875d
KZ
748
749 if (rc == 1)
750 break; /* quit */
8c3a5a44 751 } while (1);
6dbe3af9 752
8c3a5a44 753 menu_pop(cf);
6dbe3af9 754
8c3a5a44
KZ
755 DBG(FRONTEND, dbgprint("ui: end"));
756
757 return 0;
758}
6dbe3af9 759
8c3a5a44
KZ
760int main(int argc, char *argv[])
761{
762 struct cfdisk _cf = { .lines_idx = 0 },
763 *cf = &_cf;
6dbe3af9 764
8c3a5a44
KZ
765 setlocale(LC_ALL, "");
766 bindtextdomain(PACKAGE, LOCALEDIR);
767 textdomain(PACKAGE);
768 atexit(close_stdout);
6dbe3af9 769
8c3a5a44
KZ
770 fdisk_init_debug(0);
771 cf->cxt = fdisk_new_context();
772 if (!cf->cxt)
773 err(EXIT_FAILURE, _("failed to allocate libfdisk context"));
6dbe3af9 774
8c3a5a44
KZ
775 fdisk_context_set_ask(cf->cxt, ask_callback, (void *) cf);
776 fdisk_context_enable_freespace(cf->cxt, 1);
6dbe3af9 777
8c3a5a44
KZ
778 if (argc != 2)
779 err(EXIT_FAILURE, "usage: %s <device>", argv[0]);
6dbe3af9 780
8c3a5a44
KZ
781 if (fdisk_context_assign_device(cf->cxt, argv[optind], 0) != 0)
782 err(EXIT_FAILURE, _("cannot open %s"), argv[optind]);
6dbe3af9 783
8c3a5a44 784 cols_init(cf);
fd6b7a7f 785
8460875d 786 if (lines_refresh(cf))
8c3a5a44 787 errx(EXIT_FAILURE, _("failed to read partitions"));
6dbe3af9 788
8c3a5a44
KZ
789 /* Don't use err(), warn() from this point */
790 ui_init(cf);
791 ui_run(cf);
792 ui_end(cf);
6dbe3af9 793
8c3a5a44
KZ
794 free(cf->lines);
795 free(cf->linesbuf);
796 fdisk_unref_table(cf->table);
797 fdisk_free_context(cf->cxt);
798 return EXIT_SUCCESS;
6dbe3af9 799}