]> git.ipfire.org Git - thirdparty/util-linux.git/blame - disk-utils/cfdisk.c
Merge branch 'misc-build-sys' of https://github.com/rudimeier/util-linux
[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
0925a9dd 222 table = scols_new_table();
baa3b270 223 if (!table)
45333e9d 224 goto done;
0925a9dd 225 scols_table_enable_maxout(table, 1);
45333e9d 226
8c3a5a44
KZ
227 /* headers */
228 for (i = 0; i < cf->ncols; i++) {
229 col = fdisk_label_get_column(lb, cf->cols[i]);
45333e9d 230 if (col) {
baa3b270 231 int fl = col->scols_flags;
45333e9d 232 if (tree && col->id == FDISK_COL_DEVICE)
baa3b270
OO
233 fl |= SCOLS_FL_TREE;
234 if (!scols_table_new_column(table, col->name, col->width, fl))
235 goto done;
45333e9d 236 }
8c3a5a44
KZ
237 }
238
239 /* data */
8903f7df
KZ
240 fdisk_reset_iter(itr, FDISK_ITER_FORWARD);
241
8c3a5a44 242 while (fdisk_table_next_partition(tb, itr, &pa) == 0) {
baa3b270 243 struct libscols_line *parent = fdisk_partition_is_nested(pa) ? ln_cont : NULL;
8903f7df 244
baa3b270 245 ln = scols_table_new_line(table, parent);
8c3a5a44
KZ
246 if (!ln)
247 goto done;
248 for (i = 0; i < cf->ncols; i++) {
249 char *cdata = NULL;
8c3a5a44
KZ
250 col = fdisk_label_get_column(lb, cf->cols[i]);
251 if (!col)
252 continue;
253 if (fdisk_partition_to_string(pa, cf->cxt, col->id, &cdata))
254 continue;
c743bf74 255 scols_line_refer_data(ln, i, cdata);
8c3a5a44 256 }
8903f7df 257 if (tree && fdisk_partition_is_container(pa))
45333e9d 258 ln_cont = ln;
d051ea93 259
baa3b270 260 scols_line_set_userdata(ln, (void *) pa);
d051ea93 261 fdisk_ref_partition(pa);
8c3a5a44 262 }
6dbe3af9 263
baa3b270 264 if (scols_table_is_empty(table))
d051ea93
KZ
265 goto done;
266
baa3b270
OO
267 scols_table_reduce_termwidth(table, ARROW_CURSOR_WIDTH);
268 scols_print_table_to_string(table, &res);
d051ea93 269
baa3b270 270 /* scols_* code might reorder lines, let's reorder @tb according to the
d051ea93
KZ
271 * final output (it's no problem because partitions are addressed by
272 * parno stored within struct fdisk_partition) */
273
274 /* remove all */
275 fdisk_reset_iter(itr, FDISK_ITER_FORWARD);
276 while (fdisk_table_next_partition(tb, itr, &pa) == 0)
277 fdisk_table_remove_partition(tb, pa);
278
baa3b270
OO
279 s_itr = scols_new_iter(SCOLS_ITER_FORWARD);
280 if (!s_itr)
281 goto done;
282
c743bf74 283 /* add all in the right order (don't forget the output is tree) */
baa3b270 284 while (scols_table_next_line(table, s_itr, &ln) == 0) {
c743bf74
KZ
285 if (scols_line_get_parent(ln))
286 continue;
287 if (partition_from_scols(tb, ln))
288 break;
8c3a5a44
KZ
289 }
290done:
baa3b270
OO
291 scols_unref_table(table);
292 scols_free_iter(s_itr);
8c3a5a44 293 fdisk_free_iter(itr);
6dbe3af9 294
8c3a5a44 295 return res;
2b6fc908
KZ
296}
297
88942179
KZ
298/*
299 * Read data about partitions from libfdisk and prepare output lines.
300 */
8460875d 301static int lines_refresh(struct cfdisk *cf)
8c3a5a44
KZ
302{
303 int rc;
304 char *p;
305 size_t i;
7eda085c 306
8c3a5a44 307 assert(cf);
2b6fc908 308
88141067 309 DBG(FRONTEND, ul_debug("refreshing buffer"));
c64061c9 310
8c3a5a44
KZ
311 free(cf->linesbuf);
312 free(cf->lines);
313 cf->linesbuf = NULL;
314 cf->linesbufsz = 0;
315 cf->lines = NULL;
316 cf->nlines = 0;
6dbe3af9 317
8c3a5a44 318 fdisk_unref_table(cf->table);
1af8003b 319 cf->table = NULL;
6dbe3af9 320
2cec7949
KZ
321 /* read partitions and free spaces into cf->table */
322 rc = fdisk_get_partitions(cf->cxt, &cf->table);
323 if (!rc)
324 rc = fdisk_get_freespaces(cf->cxt, &cf->table);
8c3a5a44
KZ
325 if (rc)
326 return rc;
0d8589c5 327
8c3a5a44
KZ
328 cf->linesbuf = table_to_string(cf, cf->table);
329 if (!cf->linesbuf)
330 return -ENOMEM;
6dbe3af9 331
8c3a5a44
KZ
332 cf->linesbufsz = strlen(cf->linesbuf);
333 cf->nlines = fdisk_table_get_nents(cf->table) + 1; /* 1 for header line */
a6f69126
KZ
334 cf->page_sz = 0;
335
336 if (MENU_START_LINE - TABLE_START_LINE < cf->nlines)
337 cf->page_sz = MENU_START_LINE - TABLE_START_LINE - 1;
6dbe3af9 338
6d6d9c1a 339 cf->lines = xcalloc(cf->nlines, sizeof(char *));
6dbe3af9 340
8c3a5a44
KZ
341 for (p = cf->linesbuf, i = 0; p && i < cf->nlines; i++) {
342 cf->lines[i] = p;
343 p = strchr(p, '\n');
344 if (p) {
345 *p = '\0';
346 p++;
347 }
348 }
6dbe3af9 349
8c3a5a44 350 return 0;
6dbe3af9
KZ
351}
352
00b4f26a
KZ
353static struct fdisk_partition *get_current_partition(struct cfdisk *cf)
354{
355 assert(cf);
356 assert(cf->table);
357
358 return fdisk_table_get_partition(cf->table, cf->lines_idx);
359}
360
45333e9d
KZ
361static int is_freespace(struct cfdisk *cf, size_t i)
362{
363 struct fdisk_partition *pa;
364
365 assert(cf);
366 assert(cf->table);
367
368 pa = fdisk_table_get_partition(cf->table, i);
369 return fdisk_partition_is_freespace(pa);
370}
371
b1f58330
KZ
372/* converts libfdisk FDISK_ASKTYPE_MENU to cfdisk menu and returns user's
373 * responseback to libfdisk
374 */
375static int ask_menu(struct fdisk_ask *ask, struct cfdisk *cf)
376{
3b411726 377 struct cfdisk_menuitem *d, *cm;
b1f58330
KZ
378 int key;
379 size_t i = 0, nitems;
380 const char *name, *desc;
381
382 assert(ask);
383 assert(cf);
384
385 /* create cfdisk menu according to libfdisk ask-menu, note that the
386 * last cm[] item has to be empty -- so nitems + 1 */
387 nitems = fdisk_ask_menu_get_nitems(ask);
3b411726 388 cm = xcalloc(nitems + 1, sizeof(struct cfdisk_menuitem));
b1f58330
KZ
389
390 for (i = 0; i < nitems; i++) {
391 if (fdisk_ask_menu_get_item(ask, i, &key, &name, &desc))
392 break;
393 cm[i].key = key;
394 cm[i].desc = desc;
395 cm[i].name = name;
396 }
397
398 /* make the new menu active */
63128bbf 399 menu_push(cf, cm);
b1f58330
KZ
400 ui_draw_menu(cf);
401 refresh();
402
403 /* wait for keys */
404 do {
ac27ea5c
KZ
405 int key = getch();
406
407 if (ui_menu_move(cf, key) == 0)
408 continue;
409
410 switch (key) {
b1f58330
KZ
411 case KEY_ENTER:
412 case '\n':
413 case '\r':
6fed9601 414 d = menu_get_menuitem(cf, cf->menu->idx);
b1f58330
KZ
415 if (d)
416 fdisk_ask_menu_set_result(ask, d->key);
417 menu_pop(cf);
418 free(cm);
419 return 0;
420 }
421 } while (1);
422
423 menu_pop(cf);
424 free(cm);
425 return -1;
426}
427
88942179
KZ
428/* libfdisk callback
429 */
8c3a5a44
KZ
430static int ask_callback(struct fdisk_context *cxt, struct fdisk_ask *ask,
431 void *data __attribute__((__unused__)))
432{
433 int rc = 0;
6dbe3af9 434
8c3a5a44
KZ
435 assert(cxt);
436 assert(ask);
6dbe3af9 437
8c3a5a44
KZ
438 switch(fdisk_ask_get_type(ask)) {
439 case FDISK_ASKTYPE_INFO:
83fa0f80 440 ui_info(fdisk_ask_print_get_mesg(ask));
8c3a5a44
KZ
441 break;
442 case FDISK_ASKTYPE_WARNX:
83fa0f80 443 ui_warnx(fdisk_ask_print_get_mesg(ask));
8c3a5a44
KZ
444 break;
445 case FDISK_ASKTYPE_WARN:
83fa0f80 446 ui_warn(fdisk_ask_print_get_mesg(ask));
8c3a5a44 447 break;
b1f58330
KZ
448 case FDISK_ASKTYPE_MENU:
449 ask_menu(ask, (struct cfdisk *) data);
450 break;
8c3a5a44 451 default:
83fa0f80
KZ
452 ui_warnx(_("internal error: unsupported dialog type %d"),
453 fdisk_ask_get_type(ask));
8c3a5a44
KZ
454 return -EINVAL;
455 }
456 return rc;
fd6b7a7f 457}
6dbe3af9 458
7aa0d529 459static int ui_end(void)
8c3a5a44 460{
7aa0d529 461 if (!ui_enabled)
8c3a5a44
KZ
462 return -EINVAL;
463
48d7b13a 464#if defined(HAVE_SLCURSES_H) || defined(HAVE_SLANG_SLCURSES_H)
8c3a5a44
KZ
465 SLsmg_gotorc(LINES - 1, 0);
466 SLsmg_refresh();
2b6fc908 467#else
8c3a5a44 468 mvcur(0, COLS - 1, LINES-1, 0);
2b6fc908 469#endif
8c3a5a44
KZ
470 nl();
471 endwin();
472 printf("\n");
7aa0d529 473 ui_enabled = 0;
8c3a5a44 474 return 0;
6dbe3af9
KZ
475}
476
1af8003b 477static void ui_vprint_center(int line, int attrs, const char *fmt, va_list ap)
f609e92e 478{
8c3a5a44 479 size_t width;
8c3a5a44 480 char *buf = NULL;
f609e92e 481
8c3a5a44
KZ
482 move(line, 0);
483 clrtoeol();
f609e92e 484
8c3a5a44 485 xvasprintf(&buf, fmt, ap);
fd6b7a7f 486
b1f58330 487 width = mbs_safe_width(buf);
91ba41ca
KZ
488 if (width > (size_t) COLS) {
489 char *p = strrchr(buf + COLS, ' ');
490 if (!p)
491 p = buf + COLS;
492 *p = '\0';
493 if (line + 1 >= LINES)
494 line--;
495 attron(attrs);
496 mvaddstr(line, 0, buf);
497 mvaddstr(line + 1, 0, p+1);
498 attroff(attrs);
499 } else {
500 attron(attrs);
501 mvaddstr(line, (COLS - width) / 2, buf);
502 attroff(attrs);
503 }
8c3a5a44 504 free(buf);
6dbe3af9
KZ
505}
506
1af8003b
KZ
507static void ui_center(int line, const char *fmt, ...)
508{
509 va_list ap;
510 va_start(ap, fmt);
511 ui_vprint_center(line, 0, fmt, ap);
512 va_end(ap);
513}
514
83fa0f80
KZ
515static void ui_warnx(const char *fmt, ...)
516{
517 va_list ap;
518 va_start(ap, fmt);
519 if (ui_enabled)
f1512be8
KZ
520 ui_vprint_center(INFO_LINE,
521 colors_wanted() ? COLOR_PAIR(CFDISK_CL_WARNING) : 0,
522 fmt, ap);
83fa0f80
KZ
523 else
524 vfprintf(stderr, fmt, ap);
525 va_end(ap);
526}
527
528static void ui_warn(const char *fmt, ...)
1af8003b 529{
83fa0f80 530 char *fmt_m;
1af8003b 531 va_list ap;
83fa0f80
KZ
532
533 xasprintf(&fmt_m, "%s: %m", fmt);
534
1af8003b 535 va_start(ap, fmt);
83fa0f80 536 if (ui_enabled)
f1512be8
KZ
537 ui_vprint_center(INFO_LINE,
538 colors_wanted() ? COLOR_PAIR(CFDISK_CL_WARNING) : 0,
539 fmt_m, ap);
83fa0f80
KZ
540 else
541 vfprintf(stderr, fmt_m, ap);
1af8003b 542 va_end(ap);
83fa0f80 543 free(fmt_m);
1af8003b
KZ
544}
545
7aa0d529
KZ
546static int __attribute__((__noreturn__)) ui_errx(int rc, const char *fmt, ...)
547 {
548 va_list ap;
549 ui_end();
550
551 va_start(ap, fmt);
552 fprintf(stderr, "%s: ", program_invocation_short_name);
553 vfprintf(stderr, fmt, ap);
554 va_end(ap);
555
556 exit(rc);
557}
558
1af8003b
KZ
559static void ui_info(const char *fmt, ...)
560{
561 va_list ap;
562 va_start(ap, fmt);
83fa0f80
KZ
563 if (ui_enabled)
564 ui_vprint_center(INFO_LINE, A_BOLD, fmt, ap);
565 else
566 vfprintf(stdout, fmt, ap);
1af8003b
KZ
567 va_end(ap);
568}
569
570static void ui_clean_info(void)
571{
572 move(INFO_LINE, 0);
573 clrtoeol();
574}
6dbe3af9 575
b1f58330
KZ
576static void ui_hint(const char *fmt, ...)
577{
578 va_list ap;
579 va_start(ap, fmt);
580 if (ui_enabled)
581 ui_vprint_center(HINT_LINE, A_BOLD, fmt, ap);
582 else
583 vfprintf(stdout, fmt, ap);
584 va_end(ap);
585}
586
587static void ui_clean_hint(void)
588{
589 move(HINT_LINE, 0);
590 clrtoeol();
591}
592
8c3a5a44
KZ
593static void die_on_signal(int dummy __attribute__((__unused__)))
594{
88141067 595 DBG(FRONTEND, ul_debug("die on signal."));
7aa0d529 596 ui_end();
8c3a5a44 597 exit(EXIT_FAILURE);
6dbe3af9
KZ
598}
599
8c3a5a44
KZ
600static void menu_update_ignore(struct cfdisk *cf)
601{
00b4f26a
KZ
602 char ignore[128] = { 0 };
603 int i = 0;
8c3a5a44 604 struct cfdisk_menu *m;
3b411726 605 struct cfdisk_menuitem *d, *org;
83fa0f80 606 size_t idx;
6dbe3af9 607
8c3a5a44 608 assert(cf);
63128bbf
KZ
609 assert(cf->menu);
610 assert(cf->menu->ignore_cb);
6dbe3af9 611
8c3a5a44 612 m = cf->menu;
6fed9601 613 org = menu_get_menuitem(cf, m->idx);
83fa0f80 614
88141067 615 DBG(FRONTEND, ul_debug("menu: update menu ignored keys"));
6dbe3af9 616
63128bbf 617 i = m->ignore_cb(cf, ignore, sizeof(ignore));
00b4f26a
KZ
618 ignore[i] = '\0';
619
8c3a5a44 620 /* return if no change */
00b4f26a
KZ
621 if ( (!m->ignore && !*ignore)
622 || (m->ignore && *ignore && strcmp(m->ignore, ignore) == 0)) {
8c3a5a44 623 return;
fd6b7a7f 624 }
6dbe3af9 625
8c3a5a44 626 free(m->ignore);
8460875d 627 m->ignore = xstrdup(ignore);
8c3a5a44 628 m->nitems = 0;
6dbe3af9 629
3b411726 630 for (d = m->items; d->name; d++) {
8c3a5a44 631 if (m->ignore && strchr(m->ignore, d->key))
8460875d
KZ
632 continue;
633 m->nitems++;
8c3a5a44 634 }
83fa0f80
KZ
635
636 /* refresh menu index to be at the same menuitem or go to the first */
637 if (org && menu_get_menuitem_by_key(cf, org->key, &idx))
6fed9601 638 m->idx = idx;
83fa0f80 639 else
6fed9601
KZ
640 m->idx = 0;
641
642 m->page_sz = m->nitems / (LINES - 4) ? LINES - 4 : 0;
6dbe3af9
KZ
643}
644
b1f58330
KZ
645static struct cfdisk_menu *menu_push(
646 struct cfdisk *cf,
3b411726 647 struct cfdisk_menuitem *items)
8c3a5a44
KZ
648{
649 struct cfdisk_menu *m = xcalloc(1, sizeof(*m));
3b411726 650 struct cfdisk_menuitem *d;
6dbe3af9 651
8c3a5a44 652 assert(cf);
6dbe3af9 653
88141067 654 DBG(FRONTEND, ul_debug("menu: new menu"));
6dbe3af9 655
8c3a5a44 656 m->prev = cf->menu;
3b411726 657 m->items = items;
6dbe3af9 658
3b411726 659 for (d = m->items; d->name; d++) {
8c3a5a44 660 const char *name = _(d->name);
b1f58330 661 size_t len = mbs_safe_width(name);
8c3a5a44
KZ
662 if (len > m->width)
663 m->width = len;
664 m->nitems++;
665 }
6dbe3af9 666
8c3a5a44 667 cf->menu = m;
6fed9601 668 m->page_sz = m->nitems / (LINES - 4) ? LINES - 4 : 0;
8c3a5a44 669 return m;
6dbe3af9
KZ
670}
671
8c3a5a44 672static struct cfdisk_menu *menu_pop(struct cfdisk *cf)
6dbe3af9 673{
8c3a5a44 674 struct cfdisk_menu *m = NULL;
6dbe3af9 675
8c3a5a44 676 assert(cf);
7eda085c 677
88141067 678 DBG(FRONTEND, ul_debug("menu: rem menu"));
7eda085c 679
8c3a5a44
KZ
680 if (cf->menu) {
681 m = cf->menu->prev;
682 free(cf->menu->ignore);
8a726114 683 free(cf->menu->title);
8c3a5a44 684 free(cf->menu);
c07ebfa1 685 }
8c3a5a44
KZ
686 cf->menu = m;
687 return cf->menu;
6dbe3af9
KZ
688}
689
8a726114
KZ
690static void menu_set_title(struct cfdisk_menu *m, const char *title)
691{
692 char *str = NULL;
693
694 if (title) {
695 size_t len = mbs_safe_width(title);
696 if (len + 3 > m->width)
697 m->width = len + 3;
698 str = xstrdup(title);
699 }
700 m->title = str;
701}
702
703
b1f58330 704static int ui_init(struct cfdisk *cf __attribute__((__unused__)))
8c3a5a44
KZ
705{
706 struct sigaction sa;
6dbe3af9 707
88141067 708 DBG(FRONTEND, ul_debug("ui: init"));
6dbe3af9 709
8c3a5a44
KZ
710 /* setup SIGCHLD handler */
711 sigemptyset(&sa.sa_mask);
712 sa.sa_flags = 0;
713 sa.sa_handler = die_on_signal;
714 sigaction(SIGINT, &sa, NULL);
715 sigaction(SIGTERM, &sa, NULL);
6dbe3af9 716
83fa0f80 717 ui_enabled = 1;
8c3a5a44 718 initscr();
6dbe3af9 719
f1512be8 720#ifdef HAVE_USE_DEFAULT_COLORS
04915c3f 721 if (colors_wanted() && has_colors()) {
1af8003b
KZ
722 size_t i;
723
724 start_color();
725 use_default_colors();
1af8003b
KZ
726 for (i = 1; i < ARRAY_SIZE(color_pairs); i++) /* yeah, start from 1! */
727 init_pair(i, color_pairs[i][0], color_pairs[i][1]);
728 }
f1512be8 729#else
e66a6627 730 colors_off();
f1512be8 731#endif
1af8003b 732
8c3a5a44
KZ
733 cbreak();
734 noecho();
735 nonl();
736 curs_set(0);
737 keypad(stdscr, TRUE);
6dbe3af9 738
8c3a5a44 739 return 0;
7eda085c
KZ
740}
741
8c3a5a44
KZ
742static size_t menuitem_get_line(struct cfdisk *cf, size_t idx)
743{
6fed9601
KZ
744 struct cfdisk_menu *m = cf->menu;
745
746 if (m->vertical) {
747 if (!m->page_sz) /* small menu */
748 return (LINES - (cf->menu->nitems + 1)) / 2 + idx;
749 return (idx % m->page_sz) + 1;
8a726114 750 } else {
6fed9601
KZ
751 size_t len = m->width + 4 + MENU_PADDING; /* item width */
752 size_t items = COLS / len; /* items per line */
8a726114
KZ
753
754 return MENU_START_LINE + ((idx / items));
755 }
7eda085c
KZ
756}
757
8c3a5a44
KZ
758static int menuitem_get_column(struct cfdisk *cf, size_t idx)
759{
8a726114
KZ
760 if (cf->menu->vertical) {
761 size_t nc = cf->menu->width + MENU_PADDING;
7aa0d529
KZ
762 if ((size_t) COLS <= nc)
763 return 0;
764 return (COLS - nc) / 2;
8a726114
KZ
765 } else {
766 size_t len = cf->menu->width + 4 + MENU_PADDING; /* item width */
767 size_t items = COLS / len; /* items per line */
768 size_t extra = items < cf->menu->nitems ? /* extra space on line */
769 COLS % len : /* - multi-line menu */
770 COLS - (cf->menu->nitems * len); /* - one line menu */
771
772 extra += MENU_PADDING; /* add padding after last item to extra */
e66ac5d3 773
8a726114
KZ
774 if (idx < items)
775 return (idx * len) + (extra / 2);
776 return ((idx % items) * len) + (extra / 2);
777 }
df1dddf9
KZ
778}
779
6fed9601
KZ
780static int menuitem_on_page(struct cfdisk *cf, size_t idx)
781{
782 struct cfdisk_menu *m = cf->menu;
783
784 if (m->page_sz == 0 ||
785 m->idx / m->page_sz == idx / m->page_sz)
786 return 1;
787 return 0;
788}
789
3b411726 790static struct cfdisk_menuitem *menu_get_menuitem(struct cfdisk *cf, size_t idx)
8c3a5a44 791{
3b411726 792 struct cfdisk_menuitem *d;
8c3a5a44 793 size_t i;
7eda085c 794
3b411726 795 for (i = 0, d = cf->menu->items; d->name; d++) {
8c3a5a44
KZ
796 if (cf->menu->ignore && strchr(cf->menu->ignore, d->key))
797 continue;
798 if (i++ == idx)
799 return d;
d26aa358 800 }
7eda085c 801
8c3a5a44 802 return NULL;
6dbe3af9
KZ
803}
804
3b411726 805static struct cfdisk_menuitem *menu_get_menuitem_by_key(struct cfdisk *cf,
83fa0f80
KZ
806 int key, size_t *idx)
807{
3b411726 808 struct cfdisk_menuitem *d;
83fa0f80 809
3b411726 810 for (*idx = 0, d = cf->menu->items; d->name; d++) {
83fa0f80
KZ
811 if (cf->menu->ignore && strchr(cf->menu->ignore, d->key))
812 continue;
813 if (key == d->key)
814 return d;
815 (*idx)++;
816 }
817
818 return NULL;
819}
820
8c3a5a44 821static void ui_draw_menuitem(struct cfdisk *cf,
3b411726 822 struct cfdisk_menuitem *d,
8c3a5a44
KZ
823 size_t idx)
824{
825 char buf[80 * MB_CUR_MAX];
826 const char *name;
827 size_t width = cf->menu->width + 2; /* 2 = blank around string */
8a726114 828 int ln, cl, vert = cf->menu->vertical;
8c3a5a44 829
6fed9601
KZ
830 if (!menuitem_on_page(cf, idx))
831 return; /* no visible item */
832 ln = menuitem_get_line(cf, idx);
833 cl = menuitem_get_column(cf, idx);
834
8c3a5a44 835 name = _(d->name);
8a726114
KZ
836 mbsalign(name, buf, sizeof(buf), &width,
837 vert ? MBS_ALIGN_LEFT : MBS_ALIGN_CENTER,
838 0);
8c3a5a44 839
88141067 840 DBG(FRONTEND, ul_debug("ui: menuitem: cl=%d, ln=%d, item='%s'",
8c3a5a44
KZ
841 cl, ln, buf));
842
8a726114
KZ
843 if (vert) {
844 mvaddch(ln, cl - 1, ACS_VLINE);
845 mvaddch(ln, cl + cf->menu->width + 4, ACS_VLINE);
846 }
847
6fed9601 848 if (cf->menu->idx == idx) {
8c3a5a44 849 standout();
8a726114 850 mvprintw(ln, cl, vert ? " %s " : "[%s]", buf);
8c3a5a44
KZ
851 standend();
852 if (d->desc)
b1f58330 853 ui_hint(d->desc);
8c3a5a44 854 } else
8a726114 855 mvprintw(ln, cl, vert ? " %s " : "[%s]", buf);
6dbe3af9
KZ
856}
857
8c3a5a44
KZ
858static void ui_draw_menu(struct cfdisk *cf)
859{
3b411726 860 struct cfdisk_menuitem *d;
8a726114 861 struct cfdisk_menu *m;
6fed9601
KZ
862 size_t i = 0;
863 size_t ln = menuitem_get_line(cf, 0);
864 size_t nlines;
7eda085c 865
8c3a5a44
KZ
866 assert(cf);
867 assert(cf->menu);
fd6b7a7f 868
88141067 869 DBG(FRONTEND, ul_debug("ui: menu: draw start"));
6dbe3af9 870
8a726114
KZ
871 m = cf->menu;
872
6fed9601
KZ
873 if (m->vertical)
874 nlines = m->page_sz ? m->page_sz : m->nitems;
875 else
876 nlines = menuitem_get_line(cf, m->nitems);
877
878 for (i = ln; i <= ln + nlines; i++) {
00b4f26a
KZ
879 move(i, 0);
880 clrtoeol();
881 }
882
63128bbf
KZ
883 if (m->ignore_cb)
884 menu_update_ignore(cf);
00b4f26a 885 i = 0;
8c3a5a44
KZ
886 while ((d = menu_get_menuitem(cf, i)))
887 ui_draw_menuitem(cf, d, i++);
6dbe3af9 888
8a726114 889 if (m->vertical) {
8a726114 890 size_t cl = menuitem_get_column(cf, 0);
6fed9601 891 size_t curpg = m->page_sz ? m->idx / m->page_sz : 0;
8a726114 892
6fed9601 893 /* corners and horizontal lines */
8a726114
KZ
894 mvaddch(ln - 1, cl - 1, ACS_ULCORNER);
895 mvaddch(ln + nlines, cl - 1, ACS_LLCORNER);
896
897 for (i = 0; i < m->width + 4; i++) {
898 mvaddch(ln - 1, cl + i, ACS_HLINE);
899 mvaddch(ln + nlines, cl + i, ACS_HLINE);
900 }
6fed9601 901
8a726114
KZ
902 mvaddch(ln - 1, cl + i, ACS_URCORNER);
903 mvaddch(ln + nlines, cl + i, ACS_LRCORNER);
904
6fed9601
KZ
905 /* draw also lines around empty lines on last page */
906 if (m->page_sz &&
907 m->nitems / m->page_sz == m->idx / m->page_sz) {
908 for (i = m->nitems % m->page_sz + 1; i <= m->page_sz; i++) {
909 mvaddch(i, cl - 1, ACS_VLINE);
910 mvaddch(i, cl + cf->menu->width + 4, ACS_VLINE);
911 }
912 }
8a726114
KZ
913 if (m->title) {
914 attron(A_BOLD);
915 mvprintw(ln - 1, cl, " %s ", m->title);
916 attroff(A_BOLD);
917 }
6fed9601
KZ
918 if (curpg != 0)
919 mvaddch(ln - 1, cl + m->width + 3, ACS_UARROW);
920 if (m->page_sz && curpg < m->nitems / m->page_sz)
921 mvaddch(ln + nlines, cl + m->width + 3, ACS_DARROW);
8a726114
KZ
922 }
923
88141067 924 DBG(FRONTEND, ul_debug("ui: menu: draw end."));
6dbe3af9
KZ
925}
926
8c3a5a44
KZ
927static void ui_menu_goto(struct cfdisk *cf, int where)
928{
3b411726 929 struct cfdisk_menuitem *d;
8c3a5a44
KZ
930 size_t old;
931
f019ce1f
KZ
932 /* stop and begin/end for vertical menus */
933 if (cf->menu->vertical) {
934 if (where < 0)
935 where = 0;
936 else if (where > (int) cf->menu->nitems - 1)
937 where = cf->menu->nitems - 1;
938 } else {
939 /* continue from begin/end */
940 if (where < 0)
941 where = cf->menu->nitems - 1;
942 else if ((size_t) where > cf->menu->nitems - 1)
943 where = 0;
944 }
6fed9601 945 if ((size_t) where == cf->menu->idx)
8c3a5a44 946 return;
6dbe3af9 947
1af8003b
KZ
948 ui_clean_info();
949
6fed9601
KZ
950 old = cf->menu->idx;
951 cf->menu->idx = where;
952
953 if (!menuitem_on_page(cf, old)) {
954 ui_draw_menu(cf);
955 return;
956 }
6dbe3af9 957
8c3a5a44
KZ
958 d = menu_get_menuitem(cf, old);
959 ui_draw_menuitem(cf, d, old);
6dbe3af9 960
8c3a5a44
KZ
961 d = menu_get_menuitem(cf, where);
962 ui_draw_menuitem(cf, d, where);
6dbe3af9
KZ
963}
964
ac27ea5c
KZ
965static int ui_menu_move(struct cfdisk *cf, int key)
966{
f019ce1f
KZ
967 struct cfdisk_menu *m;
968
ac27ea5c
KZ
969 assert(cf);
970 assert(cf->menu);
971
f019ce1f
KZ
972 m = cf->menu;
973
88141067 974 DBG(FRONTEND, ul_debug("ui: menu move key >%c<.", key));
f019ce1f
KZ
975
976 if (m->vertical)
ac27ea5c
KZ
977 {
978 switch (key) {
979 case KEY_DOWN:
980 case '\016': /* ^N */
981 case 'j': /* Vi-like alternative */
f019ce1f 982 ui_menu_goto(cf, m->idx + 1);
ac27ea5c
KZ
983 return 0;
984 case KEY_UP:
985 case '\020': /* ^P */
986 case 'k': /* Vi-like alternative */
f019ce1f 987 ui_menu_goto(cf, (int) m->idx - 1);
ac27ea5c 988 return 0;
f019ce1f
KZ
989 case KEY_PPAGE:
990 if (m->page_sz) {
991 ui_menu_goto(cf, (int) m->idx - m->page_sz);
992 return 0;
993 }
ac27ea5c
KZ
994 case KEY_HOME:
995 ui_menu_goto(cf, 0);
996 return 0;
f019ce1f
KZ
997 case KEY_NPAGE:
998 if (m->page_sz) {
999 ui_menu_goto(cf, m->idx + m->page_sz);
1000 return 0;
1001 }
ac27ea5c 1002 case KEY_END:
f019ce1f 1003 ui_menu_goto(cf, m->nitems);
ac27ea5c
KZ
1004 return 0;
1005 }
1006 } else {
1007 switch (key) {
1008 case KEY_RIGHT:
1009 case '\t':
f019ce1f 1010 ui_menu_goto(cf, m->idx + 1);
ac27ea5c
KZ
1011 return 0;
1012 case KEY_LEFT:
1013#ifdef KEY_BTAB
1014 case KEY_BTAB:
1015#endif
f019ce1f 1016 ui_menu_goto(cf, (int) m->idx - 1);
ac27ea5c
KZ
1017 return 0;
1018 }
1019 }
1020
1021 return 1; /* key irrelevant for menu move */
1022}
1023
a6f69126
KZ
1024static int partition_on_page(struct cfdisk *cf, size_t i)
1025{
1026 if (cf->page_sz == 0 ||
1027 cf->lines_idx / cf->page_sz == i / cf->page_sz)
1028 return 1;
1029 return 0;
1030}
1031
8c3a5a44
KZ
1032static void ui_draw_partition(struct cfdisk *cf, size_t i)
1033{
1034 int ln = TABLE_START_LINE + 1 + i; /* skip table header */
1035 int cl = ARROW_CURSOR_WIDTH; /* we need extra space for cursor */
a6f69126
KZ
1036 int cur = cf->lines_idx == i;
1037 size_t curpg = 0;
1038
1039 if (cf->page_sz) {
1040 if (!partition_on_page(cf, i))
1041 return;
1042 ln = TABLE_START_LINE + (i % cf->page_sz) + 1;
1043 curpg = cf->lines_idx / cf->page_sz;
1044 }
6dbe3af9 1045
88141067 1046 DBG(FRONTEND, ul_debug(
a6f69126
KZ
1047 "ui: draw partition %zu [page_sz=%zu, "
1048 "line=%d, idx=%zu]",
1049 i, cf->page_sz, ln, cf->lines_idx));
6dbe3af9 1050
a6f69126
KZ
1051 if (cur) {
1052 attron(A_REVERSE);
8c3a5a44
KZ
1053 mvaddstr(ln, 0, ARROW_CURSOR_STRING);
1054 mvaddstr(ln, cl, cf->lines[i + 1]);
a6f69126 1055 attroff(A_REVERSE);
6dbe3af9 1056 } else {
45333e9d
KZ
1057 int at = 0;
1058
f1512be8 1059 if (colors_wanted() && is_freespace(cf, i)) {
45333e9d
KZ
1060 attron(COLOR_PAIR(CFDISK_CL_FREESPACE));
1061 at = 1;
1062 }
8c3a5a44
KZ
1063 mvaddstr(ln, 0, ARROW_CURSOR_DUMMY);
1064 mvaddstr(ln, cl, cf->lines[i + 1]);
45333e9d
KZ
1065 if (at)
1066 attroff(COLOR_PAIR(CFDISK_CL_FREESPACE));
6dbe3af9
KZ
1067 }
1068
a6f69126
KZ
1069 if ((size_t) ln == MENU_START_LINE - 1 &&
1070 cf->page_sz && curpg < cf->nlines / cf->page_sz) {
1071 if (cur)
1072 attron(A_REVERSE);
1073 mvaddch(ln, COLS - 1, ACS_DARROW);
1074 mvaddch(ln, 0, ACS_DARROW);
1075 if (cur)
1076 attroff(A_REVERSE);
1077 }
6dbe3af9
KZ
1078}
1079
8c3a5a44
KZ
1080static int ui_draw_table(struct cfdisk *cf)
1081{
1082 int cl = ARROW_CURSOR_WIDTH;
1083 size_t i, nparts = fdisk_table_get_nents(cf->table);
a6f69126 1084 size_t curpg = cf->page_sz ? cf->lines_idx / cf->page_sz : 0;
7eda085c 1085
88141067 1086 DBG(FRONTEND, ul_debug("ui: draw table"));
6dbe3af9 1087
a6f69126
KZ
1088 for (i = TABLE_START_LINE; i <= TABLE_START_LINE + cf->page_sz; i++) {
1089 move(i, 0);
1090 clrtoeol();
1091 }
6dbe3af9 1092
b2301179
KZ
1093 if ((size_t) cf->lines_idx > nparts - 1)
1094 cf->lines_idx = nparts ? nparts - 1 : 0;
1095
8c3a5a44
KZ
1096 /* print header */
1097 attron(A_BOLD);
1098 mvaddstr(TABLE_START_LINE, cl, cf->lines[0]);
1099 attroff(A_BOLD);
6dbe3af9 1100
8c3a5a44
KZ
1101 /* print partitions */
1102 for (i = 0; i < nparts; i++)
1103 ui_draw_partition(cf, i);
6dbe3af9 1104
a6f69126
KZ
1105 if (curpg != 0) {
1106 mvaddch(TABLE_START_LINE, COLS - 1, ACS_UARROW);
1107 mvaddch(TABLE_START_LINE, 0, ACS_UARROW);
1108 }
1109 if (cf->page_sz && curpg < cf->nlines / cf->page_sz) {
1110 mvaddch(MENU_START_LINE - 1, COLS - 1, ACS_DARROW);
1111 mvaddch(MENU_START_LINE - 1, 0, ACS_DARROW);
1112 }
8c3a5a44 1113 return 0;
6dbe3af9
KZ
1114}
1115
8c3a5a44
KZ
1116static int ui_table_goto(struct cfdisk *cf, int where)
1117{
1118 size_t old;
1119 size_t nparts = fdisk_table_get_nents(cf->table);
6dbe3af9 1120
88141067 1121 DBG(FRONTEND, ul_debug("ui: goto table %d", where));
6dbe3af9 1122
8c3a5a44
KZ
1123 if (where < 0)
1124 where = 0;
1125 else if ((size_t) where > nparts - 1)
1126 where = nparts - 1;
6dbe3af9 1127
8c3a5a44
KZ
1128 if ((size_t) where == cf->lines_idx)
1129 return 0;
6dbe3af9 1130
8c3a5a44
KZ
1131 old = cf->lines_idx;
1132 cf->lines_idx = where;
6dbe3af9 1133
a6f69126
KZ
1134 if (!partition_on_page(cf, old) ||!partition_on_page(cf, where))
1135 ui_draw_table(cf);
1136 else {
1137 ui_draw_partition(cf, old); /* cleanup old */
1138 ui_draw_partition(cf, where); /* draw new */
1139 }
1af8003b 1140 ui_clean_info();
8c3a5a44
KZ
1141 ui_draw_menu(cf);
1142 refresh();
1143 return 0;
6dbe3af9
KZ
1144}
1145
8c3a5a44
KZ
1146static int ui_refresh(struct cfdisk *cf)
1147{
1148 char *id = NULL;
1149 uint64_t bytes = cf->cxt->total_sectors * cf->cxt->sector_size;
1150 char *strsz = size_to_human_string(SIZE_SUFFIX_SPACE
1151 | SIZE_SUFFIX_3LETTER, bytes);
1152 erase();
1153
83fa0f80 1154 if (!ui_enabled)
8c3a5a44
KZ
1155 return -EINVAL;
1156
1157 /* header */
1158 attron(A_BOLD);
1af8003b 1159 ui_center(0, _("Disk: %s"), cf->cxt->dev_path);
8c3a5a44 1160 attroff(A_BOLD);
1af8003b 1161 ui_center(1, _("Size: %s, %ju bytes, %ju sectors"),
8c3a5a44
KZ
1162 strsz, bytes, (uintmax_t) cf->cxt->total_sectors);
1163 if (fdisk_get_disklabel_id(cf->cxt, &id) == 0 && id)
1af8003b 1164 ui_center(2, _("Label: %s, identifier: %s"),
8c3a5a44 1165 cf->cxt->label->name, id);
7eda085c 1166 else
33867d3b 1167 ui_center(2, _("Label: %s"), cf->cxt->label->name);
8c3a5a44 1168 free(strsz);
6dbe3af9 1169
8c3a5a44
KZ
1170 ui_draw_table(cf);
1171 ui_draw_menu(cf);
6dbe3af9 1172 refresh();
8c3a5a44 1173 return 0;
6dbe3af9
KZ
1174}
1175
b1f58330
KZ
1176static ssize_t ui_get_string(struct cfdisk *cf, const char *prompt,
1177 const char *hint, char *buf, size_t len)
1178{
1179 size_t cells = 0;
1180 ssize_t i = 0, rc = -1;
b1f58330
KZ
1181 int ln = MENU_START_LINE, cl = 1;
1182
1183 assert(cf);
1184 assert(buf);
1185 assert(len);
1186
1187 move(ln, 0);
1188 clrtoeol();
1189
1190 if (prompt) {
f1512be8 1191 mvaddstr(ln, cl, (char *) prompt);
b1f58330
KZ
1192 cl += mbs_safe_width(prompt);
1193 }
1194
1195 /* default value */
1196 if (*buf) {
1197 i = strlen(buf);
1198 cells = mbs_safe_width(buf);
1199 mvaddstr(ln, cl, buf);
1200 }
1201
1202 if (hint)
1203 ui_hint(hint);
1204 else
1205 ui_clean_hint();
1206
1207 move(ln, cl + cells);
1208 curs_set(1);
1209 refresh();
1210
1211 while (1) {
1212#if !defined(HAVE_SLCURSES_H) && !defined(HAVE_SLANG_SLCURSES_H) && \
1213 defined(HAVE_LIBNCURSESW) && defined(HAVE_WIDECHAR)
a08fa9ab 1214 wint_t c;
b1f58330
KZ
1215 if (get_wch(&c) == ERR) {
1216#else
a08fa9ab 1217 int c;
b1f58330
KZ
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}