]> git.ipfire.org Git - thirdparty/util-linux.git/blame - disk-utils/cfdisk.c
fdisk: print table header as bold
[thirdparty/util-linux.git] / disk-utils / 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>
04915c3f 6#include <getopt.h>
baa3b270 7#include <libsmartcols.h>
541e6934
KZ
8
9#ifdef HAVE_SLANG_H
3b411726 10# include <slang.h>
541e6934 11#elif defined(HAVE_SLANG_SLANG_H)
3b411726 12# include <slang/slang.h>
541e6934
KZ
13#endif
14
48d7b13a 15#ifdef HAVE_SLCURSES_H
3b411726 16# include <slcurses.h>
48d7b13a 17#elif defined(HAVE_SLANG_SLCURSES_H)
3b411726 18# include <slang/slcurses.h>
30c97bb8 19#elif defined(HAVE_NCURSESW_NCURSES_H) && defined(HAVE_WIDECHAR)
3b411726 20# include <ncursesw/ncurses.h>
48d7b13a 21#elif defined(HAVE_NCURSES_H)
3b411726 22# include <ncurses.h>
48d7b13a 23#elif defined(HAVE_NCURSES_NCURSES_H)
3b411726 24# include <ncurses/ncurses.h>
2b6fc908 25#endif
541e6934 26
5f94ca33 27#ifdef HAVE_WIDECHAR
3b411726 28# include <wctype.h>
f1512be8 29# include <wchar.h>
5f94ca33
KZ
30#endif
31
8c3a5a44 32#include "c.h"
b2d28533 33#include "closestream.h"
7eda085c 34#include "nls.h"
8abcf290 35#include "strutils.h"
8c3a5a44 36#include "xalloc.h"
5f94ca33 37#include "mbsalign.h"
04915c3f 38#include "colors.h"
6dbe3af9 39
8c3a5a44
KZ
40#include "fdiskP.h"
41
c743bf74 42#define ARROW_CURSOR_STRING ">> "
8c3a5a44
KZ
43#define ARROW_CURSOR_DUMMY " "
44#define ARROW_CURSOR_WIDTH (sizeof(ARROW_CURSOR_STRING) - 1)
45
46#define MENU_PADDING 2
47#define TABLE_START_LINE 4
a6f69126
KZ
48#define MENU_START_LINE ((size_t) LINES - 5)
49#define INFO_LINE ((size_t) LINES - 2)
50#define HINT_LINE ((size_t) LINES - 1)
b1f58330
KZ
51
52#define CFDISK_ERR_ESC 5000
53
54#ifndef KEY_ESC
55# define KEY_ESC '\033'
56#endif
57#ifndef KEY_DELETE
58# define KEY_DELETE '\177'
59#endif
1af8003b
KZ
60
61/* colors */
62enum {
63 CFDISK_CL_NONE = 0,
45333e9d
KZ
64 CFDISK_CL_WARNING,
65 CFDISK_CL_FREESPACE,
1af8003b
KZ
66};
67static const int color_pairs[][2] = {
68 /* color foreground, background */
45333e9d
KZ
69 [CFDISK_CL_WARNING] = { COLOR_RED, -1 },
70 [CFDISK_CL_FREESPACE] = { COLOR_GREEN, -1 }
1af8003b 71};
8c3a5a44 72
8460875d 73struct cfdisk;
8460875d 74
3b411726
KZ
75static struct cfdisk_menuitem *menu_get_menuitem(struct cfdisk *cf, size_t idx);
76static struct cfdisk_menuitem *menu_get_menuitem_by_key(struct cfdisk *cf, int key, size_t *idx);
77static struct cfdisk_menu *menu_push(struct cfdisk *cf, struct cfdisk_menuitem *item);
b1f58330 78static struct cfdisk_menu *menu_pop(struct cfdisk *cf);
83fa0f80 79
1af8003b 80static int ui_refresh(struct cfdisk *cf);
83fa0f80
KZ
81static void ui_warnx(const char *fmt, ...);
82static void ui_warn(const char *fmt, ...);
83static void ui_info(const char *fmt, ...);
b1f58330 84static void ui_draw_menu(struct cfdisk *cf);
ac27ea5c
KZ
85static int ui_menu_move(struct cfdisk *cf, int key);
86
b1f58330
KZ
87static int ui_get_size(struct cfdisk *cf, const char *prompt, uintmax_t *res,
88 uintmax_t low, uintmax_t up);
8460875d 89
83fa0f80 90static int ui_enabled;
8c3a5a44 91
88942179 92/* menu item */
3b411726 93struct cfdisk_menuitem {
8c3a5a44
KZ
94 int key; /* keyboard shortcut */
95 const char *name; /* item name */
88942179 96 const char *desc; /* item description (hint) */
6fed9601 97 void *userdata;
749af4b6
KZ
98};
99
88942179 100/* menu */
8c3a5a44 101struct cfdisk_menu {
88942179
KZ
102 char *title; /* optional menu title */
103 struct cfdisk_menuitem *items; /* array with menu items */
104 char *ignore;/* string with keys to ignore */
105 size_t width; /* maximal width of the menu item */
106 size_t nitems; /* number of the active menu items */
107 size_t page_sz;/* when menu longer than screen */
108 size_t idx; /* the current menu item */
8c3a5a44 109 struct cfdisk_menu *prev;
88942179
KZ
110
111 /* @ignore keys generator */
63128bbf 112 int (*ignore_cb) (struct cfdisk *, char *, size_t);
8a726114 113
88942179 114 unsigned int vertical : 1; /* enable vertical mode */
749af4b6
KZ
115};
116
88942179 117/* main menu */
3b411726 118static struct cfdisk_menuitem main_menuitems[] = {
8c3a5a44
KZ
119 { 'b', N_("Bootable"), N_("Toggle bootable flag of the current partition") },
120 { 'd', N_("Delete"), N_("Delete the current partition") },
8c3a5a44 121 { 'n', N_("New"), N_("Create new partition from free space") },
8c3a5a44
KZ
122 { 'q', N_("Quit"), N_("Quit program without writing partition table") },
123 { 't', N_("Type"), N_("Change the partition type") },
314a0dd8 124 { 'h', N_("Help"), N_("Print help screen") },
8c3a5a44
KZ
125 { 'W', N_("Write"), N_("Write partition table to disk (this might destroy data)") },
126 { 0, NULL, NULL }
127};
6dbe3af9 128
88942179 129/* top level control struct */
8c3a5a44
KZ
130struct cfdisk {
131 struct fdisk_context *cxt; /* libfdisk context */
132 struct fdisk_table *table; /* partition table */
a6f69126 133 struct cfdisk_menu *menu; /* the current menu */
7eda085c 134
8c3a5a44
KZ
135 int *cols; /* output columns */
136 size_t ncols; /* number of columns */
7eda085c 137
8c3a5a44
KZ
138 char *linesbuf; /* table as string */
139 size_t linesbufsz; /* size of the tb_buf */
7eda085c 140
8c3a5a44
KZ
141 char **lines; /* array with lines */
142 size_t nlines; /* number of lines */
a6f69126
KZ
143 size_t lines_idx; /* current line <0..N>, exclude header */
144 size_t page_sz;
8c3a5a44 145};
5c36a0eb 146
88942179
KZ
147/* Initialize output columns -- we follow libcfdisk columns (usually specific
148 * to the label type.
149 */
8c3a5a44
KZ
150static int cols_init(struct cfdisk *cf)
151{
152 assert(cf);
5c36a0eb 153
8c3a5a44
KZ
154 free(cf->cols);
155 cf->cols = NULL;
156 cf->ncols = 0;
5c36a0eb 157
8c3a5a44 158 return fdisk_get_columns(cf->cxt, 0, &cf->cols, &cf->ncols);
5c36a0eb
KZ
159}
160
c743bf74
KZ
161/* Reads partition in tree-like order from scols
162 */
163static int partition_from_scols(struct fdisk_table *tb,
164 struct libscols_line *ln)
165{
166 struct fdisk_partition *pa = scols_line_get_userdata(ln);
167
168 fdisk_table_add_partition(tb, pa);
169 fdisk_unref_partition(pa);
170
171 if (scols_line_has_children(ln)) {
172 struct libscols_line *chln;
173 struct libscols_iter *itr = scols_new_iter(SCOLS_ITER_FORWARD);
174
175 if (!itr)
176 return -EINVAL;
177 while (scols_line_next_child(ln, itr, &chln) == 0)
178 partition_from_scols(tb, chln);
179 }
180 return 0;
181}
182
8c3a5a44
KZ
183/* It would be possible to use fdisk_table_to_string(), but we want some
184 * extension to the output format, so let's do it without libfdisk
185 */
186static char *table_to_string(struct cfdisk *cf, struct fdisk_table *tb)
187{
8c3a5a44 188 const struct fdisk_column *col;
8903f7df 189 struct fdisk_partition *pa;
8c3a5a44
KZ
190 struct fdisk_label *lb;
191 struct fdisk_iter *itr = NULL;
baa3b270
OO
192 struct libscols_table *table = NULL;
193 struct libscols_iter *s_itr = NULL;
8c3a5a44 194 char *res = NULL;
8903f7df 195 size_t i;
45333e9d 196 int tree = 0;
baa3b270 197 struct libscols_line *ln, *ln_cont = NULL;
8c3a5a44 198
88141067 199 DBG(FRONTEND, ul_debug("table: convert to string"));
8c3a5a44
KZ
200
201 assert(cf);
202 assert(cf->cxt);
203 assert(cf->cols);
204 assert(tb);
205
206 lb = fdisk_context_get_label(cf->cxt, NULL);
207 assert(lb);
208
8c3a5a44
KZ
209 itr = fdisk_new_iter(FDISK_ITER_FORWARD);
210 if (!itr)
211 goto done;
5c36a0eb 212
45333e9d
KZ
213 /* get container (e.g. extended partition) */
214 while (fdisk_table_next_partition(tb, itr, &pa) == 0) {
215 if (fdisk_partition_is_nested(pa)) {
88141067 216 DBG(FRONTEND, ul_debug("table: nested detected, using tree"));
baa3b270 217 tree = SCOLS_FL_TREE;
45333e9d
KZ
218 break;
219 }
220 }
45333e9d 221
baa3b270
OO
222 table = scols_new_table(NULL);
223 if (!table)
45333e9d 224 goto done;
baa3b270
OO
225 scols_table_set_max(table, 1);
226 scols_table_set_tree(table, tree);
45333e9d 227
8c3a5a44
KZ
228 /* headers */
229 for (i = 0; i < cf->ncols; i++) {
230 col = fdisk_label_get_column(lb, cf->cols[i]);
45333e9d 231 if (col) {
baa3b270 232 int fl = col->scols_flags;
45333e9d 233 if (tree && col->id == FDISK_COL_DEVICE)
baa3b270
OO
234 fl |= SCOLS_FL_TREE;
235 if (!scols_table_new_column(table, col->name, col->width, fl))
236 goto done;
45333e9d 237 }
8c3a5a44
KZ
238 }
239
240 /* data */
8903f7df
KZ
241 fdisk_reset_iter(itr, FDISK_ITER_FORWARD);
242
8c3a5a44 243 while (fdisk_table_next_partition(tb, itr, &pa) == 0) {
baa3b270 244 struct libscols_line *parent = fdisk_partition_is_nested(pa) ? ln_cont : NULL;
8903f7df 245
baa3b270 246 ln = scols_table_new_line(table, parent);
8c3a5a44
KZ
247 if (!ln)
248 goto done;
249 for (i = 0; i < cf->ncols; i++) {
250 char *cdata = NULL;
8c3a5a44
KZ
251 col = fdisk_label_get_column(lb, cf->cols[i]);
252 if (!col)
253 continue;
254 if (fdisk_partition_to_string(pa, cf->cxt, col->id, &cdata))
255 continue;
c743bf74 256 scols_line_refer_data(ln, i, cdata);
8c3a5a44 257 }
8903f7df 258 if (tree && fdisk_partition_is_container(pa))
45333e9d 259 ln_cont = ln;
d051ea93 260
baa3b270 261 scols_line_set_userdata(ln, (void *) pa);
d051ea93 262 fdisk_ref_partition(pa);
8c3a5a44 263 }
6dbe3af9 264
baa3b270 265 if (scols_table_is_empty(table))
d051ea93
KZ
266 goto done;
267
baa3b270
OO
268 scols_table_reduce_termwidth(table, ARROW_CURSOR_WIDTH);
269 scols_print_table_to_string(table, &res);
d051ea93 270
baa3b270 271 /* scols_* code might reorder lines, let's reorder @tb according to the
d051ea93
KZ
272 * final output (it's no problem because partitions are addressed by
273 * parno stored within struct fdisk_partition) */
274
275 /* remove all */
276 fdisk_reset_iter(itr, FDISK_ITER_FORWARD);
277 while (fdisk_table_next_partition(tb, itr, &pa) == 0)
278 fdisk_table_remove_partition(tb, pa);
279
baa3b270
OO
280 s_itr = scols_new_iter(SCOLS_ITER_FORWARD);
281 if (!s_itr)
282 goto done;
283
c743bf74 284 /* add all in the right order (don't forget the output is tree) */
baa3b270 285 while (scols_table_next_line(table, s_itr, &ln) == 0) {
c743bf74
KZ
286 if (scols_line_get_parent(ln))
287 continue;
288 if (partition_from_scols(tb, ln))
289 break;
8c3a5a44
KZ
290 }
291done:
baa3b270
OO
292 scols_unref_table(table);
293 scols_free_iter(s_itr);
8c3a5a44 294 fdisk_free_iter(itr);
6dbe3af9 295
8c3a5a44 296 return res;
2b6fc908
KZ
297}
298
88942179
KZ
299/*
300 * Read data about partitions from libfdisk and prepare output lines.
301 */
8460875d 302static int lines_refresh(struct cfdisk *cf)
8c3a5a44
KZ
303{
304 int rc;
305 char *p;
306 size_t i;
7eda085c 307
8c3a5a44 308 assert(cf);
2b6fc908 309
88141067 310 DBG(FRONTEND, ul_debug("refreshing buffer"));
c64061c9 311
8c3a5a44
KZ
312 free(cf->linesbuf);
313 free(cf->lines);
314 cf->linesbuf = NULL;
315 cf->linesbufsz = 0;
316 cf->lines = NULL;
317 cf->nlines = 0;
6dbe3af9 318
8c3a5a44 319 fdisk_unref_table(cf->table);
1af8003b 320 cf->table = NULL;
6dbe3af9 321
2cec7949
KZ
322 /* read partitions and free spaces into cf->table */
323 rc = fdisk_get_partitions(cf->cxt, &cf->table);
324 if (!rc)
325 rc = fdisk_get_freespaces(cf->cxt, &cf->table);
8c3a5a44
KZ
326 if (rc)
327 return rc;
0d8589c5 328
8c3a5a44
KZ
329 cf->linesbuf = table_to_string(cf, cf->table);
330 if (!cf->linesbuf)
331 return -ENOMEM;
6dbe3af9 332
8c3a5a44
KZ
333 cf->linesbufsz = strlen(cf->linesbuf);
334 cf->nlines = fdisk_table_get_nents(cf->table) + 1; /* 1 for header line */
a6f69126
KZ
335 cf->page_sz = 0;
336
337 if (MENU_START_LINE - TABLE_START_LINE < cf->nlines)
338 cf->page_sz = MENU_START_LINE - TABLE_START_LINE - 1;
6dbe3af9 339
6d6d9c1a 340 cf->lines = xcalloc(cf->nlines, sizeof(char *));
6dbe3af9 341
8c3a5a44
KZ
342 for (p = cf->linesbuf, i = 0; p && i < cf->nlines; i++) {
343 cf->lines[i] = p;
344 p = strchr(p, '\n');
345 if (p) {
346 *p = '\0';
347 p++;
348 }
349 }
6dbe3af9 350
8c3a5a44 351 return 0;
6dbe3af9
KZ
352}
353
00b4f26a
KZ
354static struct fdisk_partition *get_current_partition(struct cfdisk *cf)
355{
356 assert(cf);
357 assert(cf->table);
358
359 return fdisk_table_get_partition(cf->table, cf->lines_idx);
360}
361
45333e9d
KZ
362static int is_freespace(struct cfdisk *cf, size_t i)
363{
364 struct fdisk_partition *pa;
365
366 assert(cf);
367 assert(cf->table);
368
369 pa = fdisk_table_get_partition(cf->table, i);
370 return fdisk_partition_is_freespace(pa);
371}
372
b1f58330
KZ
373/* converts libfdisk FDISK_ASKTYPE_MENU to cfdisk menu and returns user's
374 * responseback to libfdisk
375 */
376static int ask_menu(struct fdisk_ask *ask, struct cfdisk *cf)
377{
3b411726 378 struct cfdisk_menuitem *d, *cm;
b1f58330
KZ
379 int key;
380 size_t i = 0, nitems;
381 const char *name, *desc;
382
383 assert(ask);
384 assert(cf);
385
386 /* create cfdisk menu according to libfdisk ask-menu, note that the
387 * last cm[] item has to be empty -- so nitems + 1 */
388 nitems = fdisk_ask_menu_get_nitems(ask);
3b411726 389 cm = xcalloc(nitems + 1, sizeof(struct cfdisk_menuitem));
b1f58330
KZ
390
391 for (i = 0; i < nitems; i++) {
392 if (fdisk_ask_menu_get_item(ask, i, &key, &name, &desc))
393 break;
394 cm[i].key = key;
395 cm[i].desc = desc;
396 cm[i].name = name;
397 }
398
399 /* make the new menu active */
63128bbf 400 menu_push(cf, cm);
b1f58330
KZ
401 ui_draw_menu(cf);
402 refresh();
403
404 /* wait for keys */
405 do {
ac27ea5c
KZ
406 int key = getch();
407
408 if (ui_menu_move(cf, key) == 0)
409 continue;
410
411 switch (key) {
b1f58330
KZ
412 case KEY_ENTER:
413 case '\n':
414 case '\r':
6fed9601 415 d = menu_get_menuitem(cf, cf->menu->idx);
b1f58330
KZ
416 if (d)
417 fdisk_ask_menu_set_result(ask, d->key);
418 menu_pop(cf);
419 free(cm);
420 return 0;
421 }
422 } while (1);
423
424 menu_pop(cf);
425 free(cm);
426 return -1;
427}
428
88942179
KZ
429/* libfdisk callback
430 */
8c3a5a44
KZ
431static int ask_callback(struct fdisk_context *cxt, struct fdisk_ask *ask,
432 void *data __attribute__((__unused__)))
433{
434 int rc = 0;
6dbe3af9 435
8c3a5a44
KZ
436 assert(cxt);
437 assert(ask);
6dbe3af9 438
8c3a5a44
KZ
439 switch(fdisk_ask_get_type(ask)) {
440 case FDISK_ASKTYPE_INFO:
83fa0f80 441 ui_info(fdisk_ask_print_get_mesg(ask));
8c3a5a44
KZ
442 break;
443 case FDISK_ASKTYPE_WARNX:
83fa0f80 444 ui_warnx(fdisk_ask_print_get_mesg(ask));
8c3a5a44
KZ
445 break;
446 case FDISK_ASKTYPE_WARN:
83fa0f80 447 ui_warn(fdisk_ask_print_get_mesg(ask));
8c3a5a44 448 break;
b1f58330
KZ
449 case FDISK_ASKTYPE_MENU:
450 ask_menu(ask, (struct cfdisk *) data);
451 break;
8c3a5a44 452 default:
83fa0f80
KZ
453 ui_warnx(_("internal error: unsupported dialog type %d"),
454 fdisk_ask_get_type(ask));
8c3a5a44
KZ
455 return -EINVAL;
456 }
457 return rc;
fd6b7a7f 458}
6dbe3af9 459
7aa0d529 460static int ui_end(void)
8c3a5a44 461{
7aa0d529 462 if (!ui_enabled)
8c3a5a44
KZ
463 return -EINVAL;
464
48d7b13a 465#if defined(HAVE_SLCURSES_H) || defined(HAVE_SLANG_SLCURSES_H)
8c3a5a44
KZ
466 SLsmg_gotorc(LINES - 1, 0);
467 SLsmg_refresh();
2b6fc908 468#else
8c3a5a44 469 mvcur(0, COLS - 1, LINES-1, 0);
2b6fc908 470#endif
8c3a5a44
KZ
471 nl();
472 endwin();
473 printf("\n");
7aa0d529 474 ui_enabled = 0;
8c3a5a44 475 return 0;
6dbe3af9
KZ
476}
477
1af8003b 478static void ui_vprint_center(int line, int attrs, const char *fmt, va_list ap)
f609e92e 479{
8c3a5a44 480 size_t width;
8c3a5a44 481 char *buf = NULL;
f609e92e 482
8c3a5a44
KZ
483 move(line, 0);
484 clrtoeol();
f609e92e 485
8c3a5a44 486 xvasprintf(&buf, fmt, ap);
fd6b7a7f 487
b1f58330 488 width = mbs_safe_width(buf);
91ba41ca
KZ
489 if (width > (size_t) COLS) {
490 char *p = strrchr(buf + COLS, ' ');
491 if (!p)
492 p = buf + COLS;
493 *p = '\0';
494 if (line + 1 >= LINES)
495 line--;
496 attron(attrs);
497 mvaddstr(line, 0, buf);
498 mvaddstr(line + 1, 0, p+1);
499 attroff(attrs);
500 } else {
501 attron(attrs);
502 mvaddstr(line, (COLS - width) / 2, buf);
503 attroff(attrs);
504 }
8c3a5a44 505 free(buf);
6dbe3af9
KZ
506}
507
1af8003b
KZ
508static void ui_center(int line, const char *fmt, ...)
509{
510 va_list ap;
511 va_start(ap, fmt);
512 ui_vprint_center(line, 0, fmt, ap);
513 va_end(ap);
514}
515
83fa0f80
KZ
516static void ui_warnx(const char *fmt, ...)
517{
518 va_list ap;
519 va_start(ap, fmt);
520 if (ui_enabled)
f1512be8
KZ
521 ui_vprint_center(INFO_LINE,
522 colors_wanted() ? COLOR_PAIR(CFDISK_CL_WARNING) : 0,
523 fmt, ap);
83fa0f80
KZ
524 else
525 vfprintf(stderr, fmt, ap);
526 va_end(ap);
527}
528
529static void ui_warn(const char *fmt, ...)
1af8003b 530{
83fa0f80 531 char *fmt_m;
1af8003b 532 va_list ap;
83fa0f80
KZ
533
534 xasprintf(&fmt_m, "%s: %m", fmt);
535
1af8003b 536 va_start(ap, fmt);
83fa0f80 537 if (ui_enabled)
f1512be8
KZ
538 ui_vprint_center(INFO_LINE,
539 colors_wanted() ? COLOR_PAIR(CFDISK_CL_WARNING) : 0,
540 fmt_m, ap);
83fa0f80
KZ
541 else
542 vfprintf(stderr, fmt_m, ap);
1af8003b 543 va_end(ap);
83fa0f80 544 free(fmt_m);
1af8003b
KZ
545}
546
7aa0d529
KZ
547static int __attribute__((__noreturn__)) ui_errx(int rc, const char *fmt, ...)
548 {
549 va_list ap;
550 ui_end();
551
552 va_start(ap, fmt);
553 fprintf(stderr, "%s: ", program_invocation_short_name);
554 vfprintf(stderr, fmt, ap);
555 va_end(ap);
556
557 exit(rc);
558}
559
1af8003b
KZ
560static void ui_info(const char *fmt, ...)
561{
562 va_list ap;
563 va_start(ap, fmt);
83fa0f80
KZ
564 if (ui_enabled)
565 ui_vprint_center(INFO_LINE, A_BOLD, fmt, ap);
566 else
567 vfprintf(stdout, fmt, ap);
1af8003b
KZ
568 va_end(ap);
569}
570
571static void ui_clean_info(void)
572{
573 move(INFO_LINE, 0);
574 clrtoeol();
575}
6dbe3af9 576
b1f58330
KZ
577static void ui_hint(const char *fmt, ...)
578{
579 va_list ap;
580 va_start(ap, fmt);
581 if (ui_enabled)
582 ui_vprint_center(HINT_LINE, A_BOLD, fmt, ap);
583 else
584 vfprintf(stdout, fmt, ap);
585 va_end(ap);
586}
587
588static void ui_clean_hint(void)
589{
590 move(HINT_LINE, 0);
591 clrtoeol();
592}
593
8c3a5a44
KZ
594static void die_on_signal(int dummy __attribute__((__unused__)))
595{
88141067 596 DBG(FRONTEND, ul_debug("die on signal."));
7aa0d529 597 ui_end();
8c3a5a44 598 exit(EXIT_FAILURE);
6dbe3af9
KZ
599}
600
8c3a5a44
KZ
601static void menu_update_ignore(struct cfdisk *cf)
602{
00b4f26a
KZ
603 char ignore[128] = { 0 };
604 int i = 0;
8c3a5a44 605 struct cfdisk_menu *m;
3b411726 606 struct cfdisk_menuitem *d, *org;
83fa0f80 607 size_t idx;
6dbe3af9 608
8c3a5a44 609 assert(cf);
63128bbf
KZ
610 assert(cf->menu);
611 assert(cf->menu->ignore_cb);
6dbe3af9 612
8c3a5a44 613 m = cf->menu;
6fed9601 614 org = menu_get_menuitem(cf, m->idx);
83fa0f80 615
88141067 616 DBG(FRONTEND, ul_debug("menu: update menu ignored keys"));
6dbe3af9 617
63128bbf 618 i = m->ignore_cb(cf, ignore, sizeof(ignore));
00b4f26a
KZ
619 ignore[i] = '\0';
620
8c3a5a44 621 /* return if no change */
00b4f26a
KZ
622 if ( (!m->ignore && !*ignore)
623 || (m->ignore && *ignore && strcmp(m->ignore, ignore) == 0)) {
8c3a5a44 624 return;
fd6b7a7f 625 }
6dbe3af9 626
8c3a5a44 627 free(m->ignore);
8460875d 628 m->ignore = xstrdup(ignore);
8c3a5a44 629 m->nitems = 0;
6dbe3af9 630
3b411726 631 for (d = m->items; d->name; d++) {
8c3a5a44 632 if (m->ignore && strchr(m->ignore, d->key))
8460875d
KZ
633 continue;
634 m->nitems++;
8c3a5a44 635 }
83fa0f80
KZ
636
637 /* refresh menu index to be at the same menuitem or go to the first */
638 if (org && menu_get_menuitem_by_key(cf, org->key, &idx))
6fed9601 639 m->idx = idx;
83fa0f80 640 else
6fed9601
KZ
641 m->idx = 0;
642
643 m->page_sz = m->nitems / (LINES - 4) ? LINES - 4 : 0;
6dbe3af9
KZ
644}
645
b1f58330
KZ
646static struct cfdisk_menu *menu_push(
647 struct cfdisk *cf,
3b411726 648 struct cfdisk_menuitem *items)
8c3a5a44
KZ
649{
650 struct cfdisk_menu *m = xcalloc(1, sizeof(*m));
3b411726 651 struct cfdisk_menuitem *d;
6dbe3af9 652
8c3a5a44 653 assert(cf);
6dbe3af9 654
88141067 655 DBG(FRONTEND, ul_debug("menu: new menu"));
6dbe3af9 656
8c3a5a44 657 m->prev = cf->menu;
3b411726 658 m->items = items;
6dbe3af9 659
3b411726 660 for (d = m->items; d->name; d++) {
8c3a5a44 661 const char *name = _(d->name);
b1f58330 662 size_t len = mbs_safe_width(name);
8c3a5a44
KZ
663 if (len > m->width)
664 m->width = len;
665 m->nitems++;
666 }
6dbe3af9 667
8c3a5a44 668 cf->menu = m;
6fed9601 669 m->page_sz = m->nitems / (LINES - 4) ? LINES - 4 : 0;
8c3a5a44 670 return m;
6dbe3af9
KZ
671}
672
8c3a5a44 673static struct cfdisk_menu *menu_pop(struct cfdisk *cf)
6dbe3af9 674{
8c3a5a44 675 struct cfdisk_menu *m = NULL;
6dbe3af9 676
8c3a5a44 677 assert(cf);
7eda085c 678
88141067 679 DBG(FRONTEND, ul_debug("menu: rem menu"));
7eda085c 680
8c3a5a44
KZ
681 if (cf->menu) {
682 m = cf->menu->prev;
683 free(cf->menu->ignore);
8a726114 684 free(cf->menu->title);
8c3a5a44 685 free(cf->menu);
c07ebfa1 686 }
8c3a5a44
KZ
687 cf->menu = m;
688 return cf->menu;
6dbe3af9
KZ
689}
690
8a726114
KZ
691static void menu_set_title(struct cfdisk_menu *m, const char *title)
692{
693 char *str = NULL;
694
695 if (title) {
696 size_t len = mbs_safe_width(title);
697 if (len + 3 > m->width)
698 m->width = len + 3;
699 str = xstrdup(title);
700 }
701 m->title = str;
702}
703
704
b1f58330 705static int ui_init(struct cfdisk *cf __attribute__((__unused__)))
8c3a5a44
KZ
706{
707 struct sigaction sa;
6dbe3af9 708
88141067 709 DBG(FRONTEND, ul_debug("ui: init"));
6dbe3af9 710
8c3a5a44
KZ
711 /* setup SIGCHLD handler */
712 sigemptyset(&sa.sa_mask);
713 sa.sa_flags = 0;
714 sa.sa_handler = die_on_signal;
715 sigaction(SIGINT, &sa, NULL);
716 sigaction(SIGTERM, &sa, NULL);
6dbe3af9 717
83fa0f80 718 ui_enabled = 1;
8c3a5a44 719 initscr();
6dbe3af9 720
f1512be8 721#ifdef HAVE_USE_DEFAULT_COLORS
04915c3f 722 if (colors_wanted() && has_colors()) {
1af8003b
KZ
723 size_t i;
724
725 start_color();
726 use_default_colors();
1af8003b
KZ
727 for (i = 1; i < ARRAY_SIZE(color_pairs); i++) /* yeah, start from 1! */
728 init_pair(i, color_pairs[i][0], color_pairs[i][1]);
729 }
f1512be8 730#else
03f2226e 731 colors_init(UL_COLORMODE_NEVER, "cfdisk");
f1512be8 732#endif
1af8003b 733
8c3a5a44
KZ
734 cbreak();
735 noecho();
736 nonl();
737 curs_set(0);
738 keypad(stdscr, TRUE);
6dbe3af9 739
8c3a5a44 740 return 0;
7eda085c
KZ
741}
742
8c3a5a44
KZ
743static size_t menuitem_get_line(struct cfdisk *cf, size_t idx)
744{
6fed9601
KZ
745 struct cfdisk_menu *m = cf->menu;
746
747 if (m->vertical) {
748 if (!m->page_sz) /* small menu */
749 return (LINES - (cf->menu->nitems + 1)) / 2 + idx;
750 return (idx % m->page_sz) + 1;
8a726114 751 } else {
6fed9601
KZ
752 size_t len = m->width + 4 + MENU_PADDING; /* item width */
753 size_t items = COLS / len; /* items per line */
8a726114
KZ
754
755 return MENU_START_LINE + ((idx / items));
756 }
7eda085c
KZ
757}
758
8c3a5a44
KZ
759static int menuitem_get_column(struct cfdisk *cf, size_t idx)
760{
8a726114
KZ
761 if (cf->menu->vertical) {
762 size_t nc = cf->menu->width + MENU_PADDING;
7aa0d529
KZ
763 if ((size_t) COLS <= nc)
764 return 0;
765 return (COLS - nc) / 2;
8a726114
KZ
766 } else {
767 size_t len = cf->menu->width + 4 + MENU_PADDING; /* item width */
768 size_t items = COLS / len; /* items per line */
769 size_t extra = items < cf->menu->nitems ? /* extra space on line */
770 COLS % len : /* - multi-line menu */
771 COLS - (cf->menu->nitems * len); /* - one line menu */
772
773 extra += MENU_PADDING; /* add padding after last item to extra */
e66ac5d3 774
8a726114
KZ
775 if (idx < items)
776 return (idx * len) + (extra / 2);
777 return ((idx % items) * len) + (extra / 2);
778 }
df1dddf9
KZ
779}
780
6fed9601
KZ
781static int menuitem_on_page(struct cfdisk *cf, size_t idx)
782{
783 struct cfdisk_menu *m = cf->menu;
784
785 if (m->page_sz == 0 ||
786 m->idx / m->page_sz == idx / m->page_sz)
787 return 1;
788 return 0;
789}
790
3b411726 791static struct cfdisk_menuitem *menu_get_menuitem(struct cfdisk *cf, size_t idx)
8c3a5a44 792{
3b411726 793 struct cfdisk_menuitem *d;
8c3a5a44 794 size_t i;
7eda085c 795
3b411726 796 for (i = 0, d = cf->menu->items; d->name; d++) {
8c3a5a44
KZ
797 if (cf->menu->ignore && strchr(cf->menu->ignore, d->key))
798 continue;
799 if (i++ == idx)
800 return d;
d26aa358 801 }
7eda085c 802
8c3a5a44 803 return NULL;
6dbe3af9
KZ
804}
805
3b411726 806static struct cfdisk_menuitem *menu_get_menuitem_by_key(struct cfdisk *cf,
83fa0f80
KZ
807 int key, size_t *idx)
808{
3b411726 809 struct cfdisk_menuitem *d;
83fa0f80 810
3b411726 811 for (*idx = 0, d = cf->menu->items; d->name; d++) {
83fa0f80
KZ
812 if (cf->menu->ignore && strchr(cf->menu->ignore, d->key))
813 continue;
814 if (key == d->key)
815 return d;
816 (*idx)++;
817 }
818
819 return NULL;
820}
821
8c3a5a44 822static void ui_draw_menuitem(struct cfdisk *cf,
3b411726 823 struct cfdisk_menuitem *d,
8c3a5a44
KZ
824 size_t idx)
825{
826 char buf[80 * MB_CUR_MAX];
827 const char *name;
828 size_t width = cf->menu->width + 2; /* 2 = blank around string */
8a726114 829 int ln, cl, vert = cf->menu->vertical;
8c3a5a44 830
6fed9601
KZ
831 if (!menuitem_on_page(cf, idx))
832 return; /* no visible item */
833 ln = menuitem_get_line(cf, idx);
834 cl = menuitem_get_column(cf, idx);
835
8c3a5a44 836 name = _(d->name);
8a726114
KZ
837 mbsalign(name, buf, sizeof(buf), &width,
838 vert ? MBS_ALIGN_LEFT : MBS_ALIGN_CENTER,
839 0);
8c3a5a44 840
88141067 841 DBG(FRONTEND, ul_debug("ui: menuitem: cl=%d, ln=%d, item='%s'",
8c3a5a44
KZ
842 cl, ln, buf));
843
8a726114
KZ
844 if (vert) {
845 mvaddch(ln, cl - 1, ACS_VLINE);
846 mvaddch(ln, cl + cf->menu->width + 4, ACS_VLINE);
847 }
848
6fed9601 849 if (cf->menu->idx == idx) {
8c3a5a44 850 standout();
8a726114 851 mvprintw(ln, cl, vert ? " %s " : "[%s]", buf);
8c3a5a44
KZ
852 standend();
853 if (d->desc)
b1f58330 854 ui_hint(d->desc);
8c3a5a44 855 } else
8a726114 856 mvprintw(ln, cl, vert ? " %s " : "[%s]", buf);
6dbe3af9
KZ
857}
858
8c3a5a44
KZ
859static void ui_draw_menu(struct cfdisk *cf)
860{
3b411726 861 struct cfdisk_menuitem *d;
8a726114 862 struct cfdisk_menu *m;
6fed9601
KZ
863 size_t i = 0;
864 size_t ln = menuitem_get_line(cf, 0);
865 size_t nlines;
7eda085c 866
8c3a5a44
KZ
867 assert(cf);
868 assert(cf->menu);
fd6b7a7f 869
88141067 870 DBG(FRONTEND, ul_debug("ui: menu: draw start"));
6dbe3af9 871
8a726114
KZ
872 m = cf->menu;
873
6fed9601
KZ
874 if (m->vertical)
875 nlines = m->page_sz ? m->page_sz : m->nitems;
876 else
877 nlines = menuitem_get_line(cf, m->nitems);
878
879 for (i = ln; i <= ln + nlines; i++) {
00b4f26a
KZ
880 move(i, 0);
881 clrtoeol();
882 }
883
63128bbf
KZ
884 if (m->ignore_cb)
885 menu_update_ignore(cf);
00b4f26a 886 i = 0;
8c3a5a44
KZ
887 while ((d = menu_get_menuitem(cf, i)))
888 ui_draw_menuitem(cf, d, i++);
6dbe3af9 889
8a726114 890 if (m->vertical) {
8a726114 891 size_t cl = menuitem_get_column(cf, 0);
6fed9601 892 size_t curpg = m->page_sz ? m->idx / m->page_sz : 0;
8a726114 893
6fed9601 894 /* corners and horizontal lines */
8a726114
KZ
895 mvaddch(ln - 1, cl - 1, ACS_ULCORNER);
896 mvaddch(ln + nlines, cl - 1, ACS_LLCORNER);
897
898 for (i = 0; i < m->width + 4; i++) {
899 mvaddch(ln - 1, cl + i, ACS_HLINE);
900 mvaddch(ln + nlines, cl + i, ACS_HLINE);
901 }
6fed9601 902
8a726114
KZ
903 mvaddch(ln - 1, cl + i, ACS_URCORNER);
904 mvaddch(ln + nlines, cl + i, ACS_LRCORNER);
905
6fed9601
KZ
906 /* draw also lines around empty lines on last page */
907 if (m->page_sz &&
908 m->nitems / m->page_sz == m->idx / m->page_sz) {
909 for (i = m->nitems % m->page_sz + 1; i <= m->page_sz; i++) {
910 mvaddch(i, cl - 1, ACS_VLINE);
911 mvaddch(i, cl + cf->menu->width + 4, ACS_VLINE);
912 }
913 }
8a726114
KZ
914 if (m->title) {
915 attron(A_BOLD);
916 mvprintw(ln - 1, cl, " %s ", m->title);
917 attroff(A_BOLD);
918 }
6fed9601
KZ
919 if (curpg != 0)
920 mvaddch(ln - 1, cl + m->width + 3, ACS_UARROW);
921 if (m->page_sz && curpg < m->nitems / m->page_sz)
922 mvaddch(ln + nlines, cl + m->width + 3, ACS_DARROW);
8a726114
KZ
923 }
924
88141067 925 DBG(FRONTEND, ul_debug("ui: menu: draw end."));
6dbe3af9
KZ
926}
927
8c3a5a44
KZ
928static void ui_menu_goto(struct cfdisk *cf, int where)
929{
3b411726 930 struct cfdisk_menuitem *d;
8c3a5a44
KZ
931 size_t old;
932
f019ce1f
KZ
933 /* stop and begin/end for vertical menus */
934 if (cf->menu->vertical) {
935 if (where < 0)
936 where = 0;
937 else if (where > (int) cf->menu->nitems - 1)
938 where = cf->menu->nitems - 1;
939 } else {
940 /* continue from begin/end */
941 if (where < 0)
942 where = cf->menu->nitems - 1;
943 else if ((size_t) where > cf->menu->nitems - 1)
944 where = 0;
945 }
6fed9601 946 if ((size_t) where == cf->menu->idx)
8c3a5a44 947 return;
6dbe3af9 948
1af8003b
KZ
949 ui_clean_info();
950
6fed9601
KZ
951 old = cf->menu->idx;
952 cf->menu->idx = where;
953
954 if (!menuitem_on_page(cf, old)) {
955 ui_draw_menu(cf);
956 return;
957 }
6dbe3af9 958
8c3a5a44
KZ
959 d = menu_get_menuitem(cf, old);
960 ui_draw_menuitem(cf, d, old);
6dbe3af9 961
8c3a5a44
KZ
962 d = menu_get_menuitem(cf, where);
963 ui_draw_menuitem(cf, d, where);
6dbe3af9
KZ
964}
965
ac27ea5c
KZ
966static int ui_menu_move(struct cfdisk *cf, int key)
967{
f019ce1f
KZ
968 struct cfdisk_menu *m;
969
ac27ea5c
KZ
970 assert(cf);
971 assert(cf->menu);
972
f019ce1f
KZ
973 m = cf->menu;
974
88141067 975 DBG(FRONTEND, ul_debug("ui: menu move key >%c<.", key));
f019ce1f
KZ
976
977 if (m->vertical)
ac27ea5c
KZ
978 {
979 switch (key) {
980 case KEY_DOWN:
981 case '\016': /* ^N */
982 case 'j': /* Vi-like alternative */
f019ce1f 983 ui_menu_goto(cf, m->idx + 1);
ac27ea5c
KZ
984 return 0;
985 case KEY_UP:
986 case '\020': /* ^P */
987 case 'k': /* Vi-like alternative */
f019ce1f 988 ui_menu_goto(cf, (int) m->idx - 1);
ac27ea5c 989 return 0;
f019ce1f
KZ
990 case KEY_PPAGE:
991 if (m->page_sz) {
992 ui_menu_goto(cf, (int) m->idx - m->page_sz);
993 return 0;
994 }
ac27ea5c
KZ
995 case KEY_HOME:
996 ui_menu_goto(cf, 0);
997 return 0;
f019ce1f
KZ
998 case KEY_NPAGE:
999 if (m->page_sz) {
1000 ui_menu_goto(cf, m->idx + m->page_sz);
1001 return 0;
1002 }
ac27ea5c 1003 case KEY_END:
f019ce1f 1004 ui_menu_goto(cf, m->nitems);
ac27ea5c
KZ
1005 return 0;
1006 }
1007 } else {
1008 switch (key) {
1009 case KEY_RIGHT:
1010 case '\t':
f019ce1f 1011 ui_menu_goto(cf, m->idx + 1);
ac27ea5c
KZ
1012 return 0;
1013 case KEY_LEFT:
1014#ifdef KEY_BTAB
1015 case KEY_BTAB:
1016#endif
f019ce1f 1017 ui_menu_goto(cf, (int) m->idx - 1);
ac27ea5c
KZ
1018 return 0;
1019 }
1020 }
1021
1022 return 1; /* key irrelevant for menu move */
1023}
1024
a6f69126
KZ
1025static int partition_on_page(struct cfdisk *cf, size_t i)
1026{
1027 if (cf->page_sz == 0 ||
1028 cf->lines_idx / cf->page_sz == i / cf->page_sz)
1029 return 1;
1030 return 0;
1031}
1032
8c3a5a44
KZ
1033static void ui_draw_partition(struct cfdisk *cf, size_t i)
1034{
1035 int ln = TABLE_START_LINE + 1 + i; /* skip table header */
1036 int cl = ARROW_CURSOR_WIDTH; /* we need extra space for cursor */
a6f69126
KZ
1037 int cur = cf->lines_idx == i;
1038 size_t curpg = 0;
1039
1040 if (cf->page_sz) {
1041 if (!partition_on_page(cf, i))
1042 return;
1043 ln = TABLE_START_LINE + (i % cf->page_sz) + 1;
1044 curpg = cf->lines_idx / cf->page_sz;
1045 }
6dbe3af9 1046
88141067 1047 DBG(FRONTEND, ul_debug(
a6f69126
KZ
1048 "ui: draw partition %zu [page_sz=%zu, "
1049 "line=%d, idx=%zu]",
1050 i, cf->page_sz, ln, cf->lines_idx));
6dbe3af9 1051
a6f69126
KZ
1052 if (cur) {
1053 attron(A_REVERSE);
8c3a5a44
KZ
1054 mvaddstr(ln, 0, ARROW_CURSOR_STRING);
1055 mvaddstr(ln, cl, cf->lines[i + 1]);
a6f69126 1056 attroff(A_REVERSE);
6dbe3af9 1057 } else {
45333e9d
KZ
1058 int at = 0;
1059
f1512be8 1060 if (colors_wanted() && is_freespace(cf, i)) {
45333e9d
KZ
1061 attron(COLOR_PAIR(CFDISK_CL_FREESPACE));
1062 at = 1;
1063 }
8c3a5a44
KZ
1064 mvaddstr(ln, 0, ARROW_CURSOR_DUMMY);
1065 mvaddstr(ln, cl, cf->lines[i + 1]);
45333e9d
KZ
1066 if (at)
1067 attroff(COLOR_PAIR(CFDISK_CL_FREESPACE));
6dbe3af9
KZ
1068 }
1069
a6f69126
KZ
1070 if ((size_t) ln == MENU_START_LINE - 1 &&
1071 cf->page_sz && curpg < cf->nlines / cf->page_sz) {
1072 if (cur)
1073 attron(A_REVERSE);
1074 mvaddch(ln, COLS - 1, ACS_DARROW);
1075 mvaddch(ln, 0, ACS_DARROW);
1076 if (cur)
1077 attroff(A_REVERSE);
1078 }
6dbe3af9
KZ
1079}
1080
8c3a5a44
KZ
1081static int ui_draw_table(struct cfdisk *cf)
1082{
1083 int cl = ARROW_CURSOR_WIDTH;
1084 size_t i, nparts = fdisk_table_get_nents(cf->table);
a6f69126 1085 size_t curpg = cf->page_sz ? cf->lines_idx / cf->page_sz : 0;
7eda085c 1086
88141067 1087 DBG(FRONTEND, ul_debug("ui: draw table"));
6dbe3af9 1088
a6f69126
KZ
1089 for (i = TABLE_START_LINE; i <= TABLE_START_LINE + cf->page_sz; i++) {
1090 move(i, 0);
1091 clrtoeol();
1092 }
6dbe3af9 1093
b2301179
KZ
1094 if ((size_t) cf->lines_idx > nparts - 1)
1095 cf->lines_idx = nparts ? nparts - 1 : 0;
1096
8c3a5a44
KZ
1097 /* print header */
1098 attron(A_BOLD);
1099 mvaddstr(TABLE_START_LINE, cl, cf->lines[0]);
1100 attroff(A_BOLD);
6dbe3af9 1101
8c3a5a44
KZ
1102 /* print partitions */
1103 for (i = 0; i < nparts; i++)
1104 ui_draw_partition(cf, i);
6dbe3af9 1105
a6f69126
KZ
1106 if (curpg != 0) {
1107 mvaddch(TABLE_START_LINE, COLS - 1, ACS_UARROW);
1108 mvaddch(TABLE_START_LINE, 0, ACS_UARROW);
1109 }
1110 if (cf->page_sz && curpg < cf->nlines / cf->page_sz) {
1111 mvaddch(MENU_START_LINE - 1, COLS - 1, ACS_DARROW);
1112 mvaddch(MENU_START_LINE - 1, 0, ACS_DARROW);
1113 }
8c3a5a44 1114 return 0;
6dbe3af9
KZ
1115}
1116
8c3a5a44
KZ
1117static int ui_table_goto(struct cfdisk *cf, int where)
1118{
1119 size_t old;
1120 size_t nparts = fdisk_table_get_nents(cf->table);
6dbe3af9 1121
88141067 1122 DBG(FRONTEND, ul_debug("ui: goto table %d", where));
6dbe3af9 1123
8c3a5a44
KZ
1124 if (where < 0)
1125 where = 0;
1126 else if ((size_t) where > nparts - 1)
1127 where = nparts - 1;
6dbe3af9 1128
8c3a5a44
KZ
1129 if ((size_t) where == cf->lines_idx)
1130 return 0;
6dbe3af9 1131
8c3a5a44
KZ
1132 old = cf->lines_idx;
1133 cf->lines_idx = where;
6dbe3af9 1134
a6f69126
KZ
1135 if (!partition_on_page(cf, old) ||!partition_on_page(cf, where))
1136 ui_draw_table(cf);
1137 else {
1138 ui_draw_partition(cf, old); /* cleanup old */
1139 ui_draw_partition(cf, where); /* draw new */
1140 }
1af8003b 1141 ui_clean_info();
8c3a5a44
KZ
1142 ui_draw_menu(cf);
1143 refresh();
1144 return 0;
6dbe3af9
KZ
1145}
1146
8c3a5a44
KZ
1147static int ui_refresh(struct cfdisk *cf)
1148{
1149 char *id = NULL;
1150 uint64_t bytes = cf->cxt->total_sectors * cf->cxt->sector_size;
1151 char *strsz = size_to_human_string(SIZE_SUFFIX_SPACE
1152 | SIZE_SUFFIX_3LETTER, bytes);
1153 erase();
1154
83fa0f80 1155 if (!ui_enabled)
8c3a5a44
KZ
1156 return -EINVAL;
1157
1158 /* header */
1159 attron(A_BOLD);
1af8003b 1160 ui_center(0, _("Disk: %s"), cf->cxt->dev_path);
8c3a5a44 1161 attroff(A_BOLD);
1af8003b 1162 ui_center(1, _("Size: %s, %ju bytes, %ju sectors"),
8c3a5a44
KZ
1163 strsz, bytes, (uintmax_t) cf->cxt->total_sectors);
1164 if (fdisk_get_disklabel_id(cf->cxt, &id) == 0 && id)
1af8003b 1165 ui_center(2, _("Label: %s, identifier: %s"),
8c3a5a44 1166 cf->cxt->label->name, id);
7eda085c 1167 else
33867d3b 1168 ui_center(2, _("Label: %s"), cf->cxt->label->name);
8c3a5a44 1169 free(strsz);
6dbe3af9 1170
8c3a5a44
KZ
1171 ui_draw_table(cf);
1172 ui_draw_menu(cf);
6dbe3af9 1173 refresh();
8c3a5a44 1174 return 0;
6dbe3af9
KZ
1175}
1176
b1f58330
KZ
1177static ssize_t ui_get_string(struct cfdisk *cf, const char *prompt,
1178 const char *hint, char *buf, size_t len)
1179{
1180 size_t cells = 0;
1181 ssize_t i = 0, rc = -1;
1182 wint_t c;
1183 int ln = MENU_START_LINE, cl = 1;
1184
1185 assert(cf);
1186 assert(buf);
1187 assert(len);
1188
1189 move(ln, 0);
1190 clrtoeol();
1191
1192 if (prompt) {
f1512be8 1193 mvaddstr(ln, cl, (char *) prompt);
b1f58330
KZ
1194 cl += mbs_safe_width(prompt);
1195 }
1196
1197 /* default value */
1198 if (*buf) {
1199 i = strlen(buf);
1200 cells = mbs_safe_width(buf);
1201 mvaddstr(ln, cl, buf);
1202 }
1203
1204 if (hint)
1205 ui_hint(hint);
1206 else
1207 ui_clean_hint();
1208
1209 move(ln, cl + cells);
1210 curs_set(1);
1211 refresh();
1212
1213 while (1) {
1214#if !defined(HAVE_SLCURSES_H) && !defined(HAVE_SLANG_SLCURSES_H) && \
1215 defined(HAVE_LIBNCURSESW) && defined(HAVE_WIDECHAR)
1216 if (get_wch(&c) == ERR) {
1217#else
1218 if ((c = getch()) == ERR) {
1219#endif
1220 if (!isatty(STDIN_FILENO))
1221 exit(2);
1222 else
1223 goto done;
1224 }
1225 if (c == '\r' || c == '\n' || c == KEY_ENTER)
1226 break;
1227
1228 switch (c) {
1229 case KEY_ESC:
1230 rc = -CFDISK_ERR_ESC;
1231 goto done;
1232 case KEY_DELETE:
1233 case '\b':
1234 case KEY_BACKSPACE:
1235 if (i > 0) {
1236 cells--;
1237 i = mbs_truncate(buf, &cells);
1238 if (i < 0)
1239 goto done;
1240 mvaddch(ln, cl + cells, ' ');
1241 move(ln, cl + cells);
1242 } else
1243 beep();
1244 break;
1245 default:
1246#if defined(HAVE_LIBNCURSESW) && defined(HAVE_WIDECHAR)
1247 if (i + 1 < (ssize_t) len && iswprint(c)) {
1248 wchar_t wc = (wchar_t) c;
1249 char s[MB_CUR_MAX + 1];
1250 int sz = wctomb(s, wc);
1251
1252 if (sz > 0 && sz + i < (ssize_t) len) {
1253 s[sz] = '\0';
1254 mvaddnstr(ln, cl + cells, s, sz);
1255 memcpy(buf + i, s, sz);
1256 i += sz;
1257 buf[i] = '\0';
1258 cells += wcwidth(wc);
1259 } else
1260 beep();
1261 }
1262#else
1263 if (i + 1 < (ssize_t) len && isprint(c)) {
1264 mvaddch(ln, cl + cells, c);
f0fb84ab
RM
1265 buf[i++] = c;
1266 buf[i] = '\0';
b1f58330
KZ
1267 cells++;
1268 }
1269#endif
1270 else
1271 beep();
1272 }
1273 refresh();
1274 }
1275
1276 rc = i; /* success */
1277done:
1278 move(ln, 0);
1279 clrtoeol();
1280 curs_set(0);
1281 refresh();
1282
1283 return rc;
1284}
1285
1286/* @res is default value as well as result in bytes */
1287static int ui_get_size(struct cfdisk *cf, const char *prompt, uintmax_t *res,
1288 uintmax_t low, uintmax_t up)
1289{
1290 char buf[128];
1291 uintmax_t user = 0;
1292 ssize_t rc;
1293 char *dflt = size_to_human_string(0, *res);
1294
88141067 1295 DBG(FRONTEND, ul_debug("ui: get_size (default=%ju)", *res));
b1f58330
KZ
1296
1297 ui_clean_info();
1298
1299 do {
91ba41ca 1300 int pwr = 0, insec = 0;
b1f58330
KZ
1301
1302 snprintf(buf, sizeof(buf), "%s", dflt);
1303 rc = ui_get_string(cf, prompt,
5139eca7 1304 _("May be followed by {M,B,G,T}iB "
91ba41ca 1305 "(the \"iB\" is optional) or S for sectors."),
b1f58330
KZ
1306 buf, sizeof(buf));
1307 if (rc == 0) {
1308 ui_warnx(_("Please, specify size."));
1309 continue; /* nothing specified */
1310 } else if (rc == -CFDISK_ERR_ESC)
1311 break; /* cancel dialog */
1312
91ba41ca
KZ
1313 if (strcmp(buf, dflt) == 0)
1314 user = *res, rc = 0; /* no change, use default */
1315 else {
1316 size_t len = strlen(buf);
1317 if (buf[len - 1] == 'S') {
1318 insec = 1;
1319 buf[len - 1] = '\0';
1320 }
1321 rc = parse_size(buf, &user, &pwr); /* parse */
1322 }
1323
b1f58330 1324 if (rc == 0) {
88141067 1325 DBG(FRONTEND, ul_debug("ui: get_size user=%ju, power=%d, sectors=%s",
91ba41ca
KZ
1326 user, pwr, insec ? "yes" : "no"));
1327 if (insec)
1328 user *= cf->cxt->sector_size;
b1f58330
KZ
1329 if (user < low) {
1330 ui_warnx(_("Minimal size is %ju"), low);
1331 rc = -ERANGE;
1332 }
1333 if (user > up && pwr && user < up + (1ULL << pwr * 10))
1334 /* ignore when the user specified size overflow
1335 * with in range specified by suffix (e.g. MiB) */
1336 user = up;
1337
1338 if (user > up) {
1339 ui_warnx(_("Maximal size is %ju bytes."), up);
1340 rc = -ERANGE;
1341 }
2cec7949
KZ
1342 } else
1343 ui_warnx(_("Failed to parse size."));
b1f58330
KZ
1344 } while (rc != 0);
1345
1346 if (rc == 0)
1347 *res = user;
1348 free(dflt);
1349
88141067 1350 DBG(FRONTEND, ul_debug("ui: get_size (result=%ju, rc=%zd)", *res, rc));
b1f58330
KZ
1351 return rc;
1352}
1353
6d6d9c1a
KZ
1354static struct fdisk_parttype *ui_get_parttype(struct cfdisk *cf,
1355 struct fdisk_parttype *cur)
6fed9601 1356{
3b411726 1357 struct cfdisk_menuitem *d, *cm;
6d6d9c1a 1358 size_t i = 0, nitems, idx = 0;
6fed9601 1359 struct fdisk_parttype *t = NULL;
6d6d9c1a 1360 int has_typestr = 0;
6fed9601 1361
88141067 1362 DBG(FRONTEND, ul_debug("ui: asking for parttype."));
6fed9601
KZ
1363
1364 /* create cfdisk menu according to label types, note that the
1365 * last cm[] item has to be empty -- so nitems + 1 */
1366 nitems = cf->cxt->label->nparttypes;
6d6d9c1a
KZ
1367 if (!nitems)
1368 return NULL;
3b411726 1369 cm = xcalloc(nitems + 1, sizeof(struct cfdisk_menuitem));
6fed9601
KZ
1370 if (!cm)
1371 return NULL;
1372
6d6d9c1a
KZ
1373 has_typestr = cf->cxt->label->parttypes[0].typestr &&
1374 *cf->cxt->label->parttypes[0].typestr;
1375
6fed9601
KZ
1376 for (i = 0; i < nitems; i++) {
1377 struct fdisk_parttype *x = &cf->cxt->label->parttypes[i];
6d6d9c1a 1378 char *name;
6fed9601 1379
6d6d9c1a
KZ
1380 if (!x || !x->name)
1381 continue;
6fed9601 1382 cm[i].userdata = x;
6d6d9c1a
KZ
1383 if (!has_typestr)
1384 xasprintf(&name, "%2x %s", x->type, x->name);
1385 else {
1386 name = (char *) x->name;
1387 cm[i].desc = x->typestr;
1388 }
1389 cm[i].name = name;
1390 if (x == cur)
1391 idx = i;
6fed9601
KZ
1392 }
1393
1394 /* make the new menu active */
1395 menu_push(cf, cm);
1396 cf->menu->vertical = 1;
6d6d9c1a 1397 cf->menu->idx = idx;
6fed9601
KZ
1398 menu_set_title(cf->menu, _("Select partition type"));
1399 ui_draw_menu(cf);
1400 refresh();
1401
1402 do {
1403 int key = getch();
f019ce1f 1404
6fed9601
KZ
1405 if (ui_menu_move(cf, key) == 0)
1406 continue;
f019ce1f 1407
6fed9601
KZ
1408 switch (key) {
1409 case KEY_ENTER:
1410 case '\n':
1411 case '\r':
1412 d = menu_get_menuitem(cf, cf->menu->idx);
1413 if (d)
1414 t = (struct fdisk_parttype *) d->userdata;
1415 goto done;
1416 case 'q':
1417 case 'Q':
1418 goto done;
1419 }
1420 } while (1);
1421
1422done:
1423 menu_pop(cf);
6d6d9c1a
KZ
1424 if (!has_typestr) {
1425 for (i = 0; i < nitems; i++)
1426 free((char *) cm[i].name);
1427 }
6fed9601 1428 free(cm);
88141067 1429 DBG(FRONTEND, ul_debug("ui: get parrtype done [type=%s] ", t ? t->name : NULL));
6fed9601
KZ
1430 return t;
1431}
1432
7aa0d529
KZ
1433/* prints menu with libfdisk labels and waits for users response */
1434static int ui_create_label(struct cfdisk *cf)
1435{
3b411726 1436 struct cfdisk_menuitem *d, *cm;
7aa0d529
KZ
1437 int rc = 1;
1438 size_t i = 0, nitems;
1439 struct fdisk_label *lb = NULL;
1440
1441 assert(cf);
1442
88141067 1443 DBG(FRONTEND, ul_debug("ui: asking for new disklabe."));
7aa0d529
KZ
1444
1445 /* create cfdisk menu according to libfdisk labels, note that the
1446 * last cm[] item has to be empty -- so nitems + 1 */
1447 nitems = fdisk_context_get_nlabels(cf->cxt);
3b411726 1448 cm = xcalloc(nitems + 1, sizeof(struct cfdisk_menuitem));
7aa0d529
KZ
1449
1450 for (i = 0; i < nitems; i++) {
1451 if (fdisk_context_next_label(cf->cxt, &lb))
1452 break;
1453 cm[i].name = lb->name;
1454 }
1455
1456 erase();
1457 ui_center(LINES - 4,
1458 _("Device does not contain a recognized partition table."));
1459 ui_center(LINES - 3,
1460 _("Please, select a type to create a new disk label."));
1461
1462 /* make the new menu active */
63128bbf 1463 menu_push(cf, cm);
7aa0d529
KZ
1464 cf->menu->vertical = 1;
1465 menu_set_title(cf->menu, _("Select label type"));
1466 ui_draw_menu(cf);
1467 refresh();
1468
1469 do {
1470 int key = getch();
1471 if (ui_menu_move(cf, key) == 0)
1472 continue;
1473 switch (key) {
1474 case KEY_ENTER:
1475 case '\n':
1476 case '\r':
6fed9601 1477 d = menu_get_menuitem(cf, cf->menu->idx);
7aa0d529
KZ
1478 if (d)
1479 rc = fdisk_create_disklabel(cf->cxt, d->name);
1480 goto done;
1481 case 'q':
1482 case 'Q':
1483 goto done;
1484 }
1485 } while (1);
1486
1487done:
1488 menu_pop(cf);
1489 free(cm);
88141067 1490 DBG(FRONTEND, ul_debug("ui: create label done [rc=%d] ", rc));
7aa0d529
KZ
1491 return rc;
1492}
1493
314a0dd8
KZ
1494static int ui_help(void)
1495{
1496 size_t i;
314a0dd8
KZ
1497 static const char *help[] = {
1498 N_("Help Screen for cfdisk"),
1499 "",
1500 N_("This is cfdisk, a curses based disk partitioning program, which"),
1501 N_("allows you to create, delete and modify partitions on your hard"),
1502 N_("disk drive."),
1503 "",
1504 N_("Copyright (C) 2014 Karel Zak <kzak@redhat.com> "),
1505 N_("Based on the original cfdisk from Kevin E. Martin & aeb."),
1506 "",
1507 N_("Command Meaning"),
1508 N_("------- -------"),
1509 N_(" b Toggle bootable flag of the current partition"),
1510 N_(" d Delete the current partition"),
1511 N_(" h Print this screen"),
1512 N_(" n Create new partition from free space"),
1513 N_(" q Quit program without writing partition table"),
1514 N_(" t Change the partition type"),
1515 N_(" W Write partition table to disk (must enter upper case W)"),
1516 N_(" Since this might destroy data on the disk, you must"),
1517 N_(" either confirm or deny the write by entering `yes' or"),
1518 N_(" `no'"),
1519 N_("Up Arrow Move cursor to the previous partition"),
1520 N_("Down Arrow Move cursor to the next partition"),
1521 N_("Left Arrow Move cursor to the previous menu item"),
1522 N_("Right Arrow Move cursor to the next menu item"),
1523
1524 "",
1525 N_("Note: All of the commands can be entered with either upper or lower"),
1526 N_("case letters (except for Writes)."),
1527 "",
1528 N_("Use lsblk(8) or partx(8) to see more details about the device.")
1529 };
1530
1531 erase();
314a0dd8
KZ
1532 for (i = 0; i < ARRAY_SIZE(help); i++)
1533 mvaddstr(i, 1, _(help[i]));
1534
1535 ui_info(_("Press a key to continue."));
1536 getch();
1537 return 0;
1538}
1539
63128bbf
KZ
1540/* TODO: use @sz, now 128bytes */
1541static int main_menu_ignore_keys(struct cfdisk *cf, char *ignore,
1542 size_t sz __attribute__((__unused__)))
1543{
1544 struct fdisk_partition *pa = get_current_partition(cf);
1545 size_t i = 0;
1546
1547 if (!pa)
1548 return 0;
1549 if (fdisk_partition_is_freespace(pa)) {
1550 ignore[i++] = 'd'; /* delete */
1551 ignore[i++] = 't'; /* set type */
1552 ignore[i++] = 'b'; /* set bootable */
1553 } else {
1554 ignore[i++] = 'n';
1555 if (!fdisk_is_disklabel(cf->cxt, DOS) &&
1556 !fdisk_is_disklabel(cf->cxt, SGI))
1557 ignore[i++] = 'b';
1558 }
e146ae4e
KZ
1559
1560
1561 if (fdisk_context_is_readonly(cf->cxt))
1562 ignore[i++] = 'W';
63128bbf
KZ
1563 return i;
1564}
1565
1566
ed8a13e6
KZ
1567/* returns: error: < 0, success: 0, quit: 1 */
1568static int main_menu_action(struct cfdisk *cf, int key)
1569{
1570 size_t n;
1571 int ref = 0, rc;
1572 const char *info = NULL, *warn = NULL;
1573 struct fdisk_partition *pa;
1574
1575 assert(cf);
1576 assert(cf->cxt);
1577 assert(cf->menu);
1578
1579 if (key == 0) {
3b411726 1580 struct cfdisk_menuitem *d = menu_get_menuitem(cf, cf->menu->idx);
ed8a13e6
KZ
1581 if (!d)
1582 return 0;
1583 key = d->key;
1584
1585 } else if (key != 'w' && key != 'W')
1586 key = tolower(key); /* case insensitive except 'W'rite */
1587
88141067 1588 DBG(FRONTEND, ul_debug("ui: main menu action: key=%c", key));
ed8a13e6
KZ
1589
1590 if (cf->menu->ignore && strchr(cf->menu->ignore, key)) {
88141067 1591 DBG(FRONTEND, ul_debug(" ignore '%c'", key));
ed8a13e6
KZ
1592 return 0;
1593 }
1594
1595 pa = get_current_partition(cf);
1596 n = fdisk_partition_get_partno(pa);
1597
88141067 1598 DBG(FRONTEND, ul_debug("menu action on %p", pa));
7b1ffbc4
KZ
1599 ui_clean_hint();
1600 ui_clean_info();
ed8a13e6
KZ
1601
1602 switch (key) {
1603 case 'b': /* Bootable flag */
1604 {
1605 int fl = fdisk_is_disklabel(cf->cxt, DOS) ? DOS_FLAG_ACTIVE :
1606 fdisk_is_disklabel(cf->cxt, SGI) ? SGI_FLAG_BOOT : 0;
1607
1608 if (fl && fdisk_partition_toggle_flag(cf->cxt, n, fl))
1609 warn = _("Could not toggle the flag.");
1610 else if (fl)
1611 ref = 1;
1612 break;
1613 }
f1512be8 1614#ifdef KEY_DC
f019ce1f 1615 case KEY_DC:
f1512be8 1616#endif
ed8a13e6
KZ
1617 case 'd': /* Delete */
1618 if (fdisk_delete_partition(cf->cxt, n) != 0)
1619 warn = _("Could not delete partition %zu.");
1620 else
1621 info = _("Partition %zu has been deleted.");
1622 ref = 1;
1623 break;
314a0dd8
KZ
1624 case 'h': /* help */
1625 ui_help();
1626 ref = 1;
1627 break;
ed8a13e6
KZ
1628 case 'n': /* New */
1629 {
1630 uint64_t start, size, dflt_size;
1631 struct fdisk_partition *npa; /* the new partition */
1632
1633 if (!pa || !fdisk_partition_is_freespace(pa))
1634 return -EINVAL;
1635 npa = fdisk_new_partition();
1636 if (!npa)
1637 return -ENOMEM;
1638 /* free space range */
1639 start = fdisk_partition_get_start(pa);
1640 size = dflt_size = fdisk_partition_get_size(pa) * cf->cxt->sector_size;
1641
1642 if (ui_get_size(cf, _("Partition size: "), &size, 1, size)
1643 == -CFDISK_ERR_ESC)
1644 break;
1645
1646 if (dflt_size == size) /* default is to fillin all free space */
1647 fdisk_partition_end_follow_default(npa, 1);
1648 else /* set relative size of the partition */
1649 fdisk_partition_set_size(npa, size / cf->cxt->sector_size);
1650
1651 fdisk_partition_set_start(npa, start);
1652 fdisk_partition_partno_follow_default(npa, 1);
1653 /* add to disk label -- libfdisk will ask for missing details */
1654 rc = fdisk_add_partition(cf->cxt, npa);
1655 fdisk_unref_partition(npa);
1656 if (rc == 0)
1657 ref = 1;
1658 break;
1659 }
1660 case 'q': /* Quit */
1661 return 1;
1662 case 't': /* Type */
6fed9601 1663 {
6fed9601
KZ
1664 struct fdisk_parttype *t;
1665
1666 if (!pa || fdisk_partition_is_freespace(pa))
1667 return -EINVAL;
1668 t = (struct fdisk_parttype *) fdisk_partition_get_type(pa);
6d6d9c1a 1669 t = ui_get_parttype(cf, t);
6fed9601
KZ
1670 ref = 1;
1671
1672 if (t && fdisk_set_partition_type(cf->cxt, n, t) == 0)
7b1ffbc4 1673 info = _("Changed type of the partition %zu.");
6fed9601 1674 else
7b1ffbc4 1675 info = _("Type of the partition %zu is unchanged.");
ed8a13e6 1676 break;
6fed9601 1677 }
ed8a13e6 1678 case 'W': /* Write */
7b1ffbc4
KZ
1679 {
1680 char buf[64] = { 0 };
e146ae4e
KZ
1681 int rc;
1682
1683 if (fdisk_context_is_readonly(cf->cxt)) {
1684 ui_warnx(_("Device open in read-only mode"));
1685 break;
1686 }
1687
1688 rc = ui_get_string(cf,
7b1ffbc4
KZ
1689 _("Are you sure you want to write the partition "
1690 "table to disk? "),
1691 _("Type \"yes\" or \"no\" or press ESC to left dialog."),
1692 buf, sizeof(buf));
1693
1694 ref = 1;
1695 if (rc <= 0 || strcasecmp(buf, "yes") != 0
1696 || strcasecmp(buf, _("yes")) != 0) {
1697 info = _("Did not write partition table to disk");
1698 break;
1699 }
ed8a13e6
KZ
1700 rc = fdisk_write_disklabel(cf->cxt);
1701 if (rc)
7b1ffbc4
KZ
1702 warn = _("Failed to write disklabel");
1703 else {
1704 fdisk_reread_partition_table(cf->cxt);
1705 info = _("The partition table has been altered.");
1706 }
1707 break;
1708 }
1709 default:
ed8a13e6
KZ
1710 break;
1711 }
1712
1713 if (ref) {
1714 lines_refresh(cf);
1715 ui_refresh(cf);
1716 }
7b1ffbc4
KZ
1717
1718 ui_clean_hint();
ed8a13e6 1719 if (warn)
7b1ffbc4 1720 ui_warnx(warn, n + 1);
ed8a13e6 1721 else if (info)
7b1ffbc4 1722 ui_info(info, n + 1);
ed8a13e6
KZ
1723
1724 return 0;
1725}
1726
8c3a5a44
KZ
1727static int ui_run(struct cfdisk *cf)
1728{
7aa0d529 1729 int rc = 0;
6dbe3af9 1730
88141067 1731 DBG(FRONTEND, ul_debug("ui: start COLS=%d, LINES=%d", COLS, LINES));
6dbe3af9 1732
7aa0d529
KZ
1733 if (!fdisk_dev_has_disklabel(cf->cxt)) {
1734 rc = ui_create_label(cf);
1735 if (rc < 0)
1736 ui_errx(EXIT_FAILURE,
1737 _("failed to create a new disklabel"));
1738 if (rc)
1739 return rc;
1740 }
1741
1742 cols_init(cf);
1743 rc = lines_refresh(cf);
1744 if (rc)
1745 ui_errx(EXIT_FAILURE, _("failed to read partitions"));
6dbe3af9 1746
3b411726 1747 menu_push(cf, main_menuitems);
63128bbf
KZ
1748 cf->menu->ignore_cb = main_menu_ignore_keys;
1749
8c3a5a44
KZ
1750 rc = ui_refresh(cf);
1751 if (rc)
1752 return rc;
6dbe3af9 1753
e146ae4e
KZ
1754 if (fdisk_context_is_readonly(cf->cxt))
1755 ui_warnx(_("Device open in read-only mode."));
1756
8c3a5a44 1757 do {
8460875d 1758 int rc = 0, key = getch();
6dbe3af9 1759
ac27ea5c
KZ
1760 if (ui_menu_move(cf, key) == 0)
1761 continue;
1762
88141067 1763 DBG(FRONTEND, ul_debug("ui: main action key >%c<.", key));
f019ce1f 1764
8c3a5a44
KZ
1765 switch (key) {
1766 case KEY_DOWN:
1767 case '\016': /* ^N */
1768 case 'j': /* Vi-like alternative */
1769 ui_table_goto(cf, cf->lines_idx + 1);
1770 break;
1771 case KEY_UP:
1772 case '\020': /* ^P */
1773 case 'k': /* Vi-like alternative */
f019ce1f 1774 ui_table_goto(cf, (int) cf->lines_idx - 1);
8c3a5a44 1775 break;
f019ce1f
KZ
1776 case KEY_PPAGE:
1777 if (cf->page_sz) {
1778 ui_table_goto(cf, (int) cf->lines_idx - cf->page_sz);
1779 break;
1780 }
8c3a5a44
KZ
1781 case KEY_HOME:
1782 ui_table_goto(cf, 0);
1783 break;
f019ce1f
KZ
1784 case KEY_NPAGE:
1785 if (cf->page_sz) {
1786 ui_table_goto(cf, cf->lines_idx + cf->page_sz);
1787 break;
1788 }
8c3a5a44 1789 case KEY_END:
f019ce1f 1790 ui_table_goto(cf, (int) cf->nlines - 1);
8c3a5a44 1791 break;
8c3a5a44
KZ
1792 case KEY_ENTER:
1793 case '\n':
1794 case '\r':
ed8a13e6 1795 rc = main_menu_action(cf, 0);
8c3a5a44
KZ
1796 break;
1797 default:
ed8a13e6 1798 rc = main_menu_action(cf, key);
8460875d 1799 if (rc < 0)
8c3a5a44
KZ
1800 beep();
1801 break;
1802 }
8460875d
KZ
1803
1804 if (rc == 1)
1805 break; /* quit */
8c3a5a44 1806 } while (1);
6dbe3af9 1807
8c3a5a44 1808 menu_pop(cf);
6dbe3af9 1809
88141067 1810 DBG(FRONTEND, ul_debug("ui: end"));
8c3a5a44
KZ
1811
1812 return 0;
1813}
6dbe3af9 1814
04915c3f
KZ
1815static void __attribute__ ((__noreturn__)) usage(FILE *out)
1816{
1817 fputs(USAGE_HEADER, out);
1818
1819 fprintf(out,
1820 _(" %1$s [options] <disk>\n"), program_invocation_short_name);
1821
1822 fputs(USAGE_OPTIONS, out);
1823 fputs(_(" -L --color[=<when>] colorize output (auto, always or never)\n"), out);
1824
1825 fputs(USAGE_SEPARATOR, out);
1826 fputs(USAGE_HELP, out);
1827 fputs(USAGE_VERSION, out);
1828
1829 fprintf(out, USAGE_MAN_TAIL("cfdisk(8)"));
1830 exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
1831}
1832
8c3a5a44
KZ
1833int main(int argc, char *argv[])
1834{
ad9fe47e 1835 int rc, c, colormode = UL_COLORMODE_UNDEF;
8c3a5a44
KZ
1836 struct cfdisk _cf = { .lines_idx = 0 },
1837 *cf = &_cf;
6dbe3af9 1838
04915c3f
KZ
1839 static const struct option longopts[] = {
1840 { "color", optional_argument, NULL, 'L' },
1841 { "help", no_argument, NULL, 'h' },
1842 { "version", no_argument, NULL, 'V' },
1843 { NULL, 0, 0, 0 },
1844 };
1845
8c3a5a44
KZ
1846 setlocale(LC_ALL, "");
1847 bindtextdomain(PACKAGE, LOCALEDIR);
1848 textdomain(PACKAGE);
1849 atexit(close_stdout);
6dbe3af9 1850
04915c3f
KZ
1851 while((c = getopt_long(argc, argv, "L::hV", longopts, NULL)) != -1) {
1852 switch(c) {
1853 case 'h':
1854 usage(stdout);
1855 break;
1856 case 'L':
1857 colormode = UL_COLORMODE_AUTO;
1858 if (optarg)
1859 colormode = colormode_or_err(optarg,
1860 _("unsupported color mode"));
1861 break;
1862 case 'V':
1863 printf(_("%s from %s\n"), program_invocation_short_name,
1864 PACKAGE_STRING);
1865 return EXIT_SUCCESS;
1866 }
1867 }
1868
f1512be8
KZ
1869
1870
210bb492 1871 colors_init(colormode, "cfdisk");
04915c3f 1872
8c3a5a44
KZ
1873 fdisk_init_debug(0);
1874 cf->cxt = fdisk_new_context();
1875 if (!cf->cxt)
1876 err(EXIT_FAILURE, _("failed to allocate libfdisk context"));
6dbe3af9 1877
8c3a5a44 1878 fdisk_context_set_ask(cf->cxt, ask_callback, (void *) cf);
6dbe3af9 1879
04915c3f
KZ
1880 if (optind == argc)
1881 usage(stderr);
6dbe3af9 1882
e146ae4e
KZ
1883 rc = fdisk_context_assign_device(cf->cxt, argv[optind], 0);
1884 if (rc == -EACCES)
1885 rc = fdisk_context_assign_device(cf->cxt, argv[optind], 1);
1886 if (rc != 0)
8c3a5a44 1887 err(EXIT_FAILURE, _("cannot open %s"), argv[optind]);
6dbe3af9 1888
8c3a5a44
KZ
1889 /* Don't use err(), warn() from this point */
1890 ui_init(cf);
1891 ui_run(cf);
7aa0d529 1892 ui_end();
6dbe3af9 1893
8c3a5a44
KZ
1894 free(cf->lines);
1895 free(cf->linesbuf);
1896 fdisk_unref_table(cf->table);
ed8a13e6
KZ
1897
1898 rc = fdisk_context_deassign_device(cf->cxt);
8c3a5a44 1899 fdisk_free_context(cf->cxt);
88141067 1900 DBG(FRONTEND, ul_debug("bye! [rc=%d]", rc));
ed8a13e6 1901 return rc == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
6dbe3af9 1902}