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