]> git.ipfire.org Git - thirdparty/util-linux.git/blame - fdisks/cfdisk.c
libfdisk: (dos) consolidate partition end-offset code
[thirdparty/util-linux.git] / fdisks / cfdisk.c
CommitLineData
6dbe3af9
KZ
1#include <stdlib.h>
2#include <stdio.h>
6dbe3af9 3#include <errno.h>
8c3a5a44 4#include <signal.h>
00b4f26a 5#include <ctype.h>
541e6934
KZ
6
7#ifdef HAVE_SLANG_H
8#include <slang.h>
9#elif defined(HAVE_SLANG_SLANG_H)
10#include <slang/slang.h>
11#endif
12
48d7b13a
KZ
13#ifdef HAVE_SLCURSES_H
14#include <slcurses.h>
15#elif defined(HAVE_SLANG_SLCURSES_H)
16#include <slang/slcurses.h>
30c97bb8
MF
17#elif defined(HAVE_NCURSESW_NCURSES_H) && defined(HAVE_WIDECHAR)
18#include <ncursesw/ncurses.h>
48d7b13a
KZ
19#elif defined(HAVE_NCURSES_H)
20#include <ncurses.h>
21#elif defined(HAVE_NCURSES_NCURSES_H)
22#include <ncurses/ncurses.h>
2b6fc908 23#endif
541e6934 24
5f94ca33
KZ
25#ifdef HAVE_WIDECHAR
26#include <wctype.h>
27#endif
28
8c3a5a44 29#include "c.h"
b2d28533 30#include "closestream.h"
7eda085c 31#include "nls.h"
8abcf290 32#include "strutils.h"
8c3a5a44 33#include "xalloc.h"
5f94ca33 34#include "mbsalign.h"
6dbe3af9 35
8c3a5a44
KZ
36#include "fdiskP.h"
37
38#define ARROW_CURSOR_STRING ">>> "
39#define ARROW_CURSOR_DUMMY " "
40#define ARROW_CURSOR_WIDTH (sizeof(ARROW_CURSOR_STRING) - 1)
41
42#define MENU_PADDING 2
43#define TABLE_START_LINE 4
44#define MENU_START_LINE (LINES - 5)
1af8003b 45#define INFO_LINE (LINES - 2)
b1f58330
KZ
46#define HINT_LINE (LINES - 1)
47
48#define CFDISK_ERR_ESC 5000
49
50#ifndef KEY_ESC
51# define KEY_ESC '\033'
52#endif
53#ifndef KEY_DELETE
54# define KEY_DELETE '\177'
55#endif
1af8003b
KZ
56
57/* colors */
58enum {
59 CFDISK_CL_NONE = 0,
45333e9d
KZ
60 CFDISK_CL_WARNING,
61 CFDISK_CL_FREESPACE,
1af8003b
KZ
62};
63static const int color_pairs[][2] = {
64 /* color foreground, background */
45333e9d
KZ
65 [CFDISK_CL_WARNING] = { COLOR_RED, -1 },
66 [CFDISK_CL_FREESPACE] = { COLOR_GREEN, -1 }
1af8003b 67};
8c3a5a44 68
8460875d
KZ
69struct cfdisk;
70typedef int (menu_callback_t)(struct cfdisk *, int);
71
72static int menu_cb_main(struct cfdisk *cf, int key);
83fa0f80
KZ
73static struct cfdisk_menudesc *menu_get_menuitem(struct cfdisk *cf, size_t idx);
74static struct cfdisk_menudesc *menu_get_menuitem_by_key(struct cfdisk *cf, int key, size_t *idx);
b1f58330
KZ
75static struct cfdisk_menu *menu_push(struct cfdisk *cf, size_t id, struct cfdisk_menudesc *desc);
76static struct cfdisk_menu *menu_pop(struct cfdisk *cf);
83fa0f80 77
1af8003b 78static int ui_refresh(struct cfdisk *cf);
83fa0f80
KZ
79static void ui_warnx(const char *fmt, ...);
80static void ui_warn(const char *fmt, ...);
81static void ui_info(const char *fmt, ...);
b1f58330
KZ
82static void ui_draw_menu(struct cfdisk *cf);
83static void ui_menu_goto(struct cfdisk *cf, int where);
84static int ui_get_size(struct cfdisk *cf, const char *prompt, uintmax_t *res,
85 uintmax_t low, uintmax_t up);
8460875d 86
83fa0f80 87static int ui_enabled;
8c3a5a44
KZ
88
89struct cfdisk_menudesc {
90 int key; /* keyboard shortcut */
91 const char *name; /* item name */
92 const char *desc; /* item description */
749af4b6
KZ
93};
94
8c3a5a44
KZ
95struct cfdisk_menu {
96 struct cfdisk_menudesc *desc;
97 char *ignore;
98 size_t id;
99 size_t width;
100 size_t nitems;
8460875d
KZ
101
102 menu_callback_t *callback;
103
8c3a5a44 104 struct cfdisk_menu *prev;
749af4b6
KZ
105};
106
8c3a5a44
KZ
107static struct cfdisk_menudesc menu_main[] = {
108 { 'b', N_("Bootable"), N_("Toggle bootable flag of the current partition") },
109 { 'd', N_("Delete"), N_("Delete the current partition") },
110// { 'g', N_("Geometry"), N_("Change disk geometry (experts only)") },
111// { 'h', N_("Help"), N_("Print help screen") },
112// { 'm', N_("Maximize"), N_("Maximize disk usage of the current partition (experts only)") },
113 { 'n', N_("New"), N_("Create new partition from free space") },
114// { 'p', N_("Print"), N_("Print partition table to the screen or to a file") },
115 { 'q', N_("Quit"), N_("Quit program without writing partition table") },
116 { 't', N_("Type"), N_("Change the partition type") },
117// { 'u', N_("Units"), N_("Change units of the partition size display (MB, sect, cyl)") },
118 { 'W', N_("Write"), N_("Write partition table to disk (this might destroy data)") },
119 { 0, NULL, NULL }
120};
6dbe3af9 121
8c3a5a44 122enum {
b1f58330
KZ
123 CFDISK_MENU_GENERATED = -1, /* used in libfdisk callback */
124
125 /* built-in menus */
8c3a5a44 126 CFDISK_MENU_MAIN = 0,
b1f58330 127
5c36a0eb
KZ
128};
129
8c3a5a44
KZ
130static struct cfdisk_menudesc *menus[] = {
131 [CFDISK_MENU_MAIN] = menu_main
132};
7eda085c 133
8460875d
KZ
134static menu_callback_t *menu_callbacks[] = {
135 [CFDISK_MENU_MAIN] = menu_cb_main
136};
137
138
8c3a5a44
KZ
139struct cfdisk {
140 struct fdisk_context *cxt; /* libfdisk context */
141 struct fdisk_table *table; /* partition table */
7eda085c 142
8c3a5a44
KZ
143 struct cfdisk_menu *menu; /* the current menu */
144 size_t menu_idx;
7eda085c 145
8c3a5a44
KZ
146 int *cols; /* output columns */
147 size_t ncols; /* number of columns */
7eda085c 148
8c3a5a44
KZ
149 char *linesbuf; /* table as string */
150 size_t linesbufsz; /* size of the tb_buf */
7eda085c 151
8c3a5a44
KZ
152 char **lines; /* array with lines */
153 size_t nlines; /* number of lines */
154 size_t lines_idx; /* current line <0..N>, exclude header */
8c3a5a44 155};
5c36a0eb 156
8c3a5a44
KZ
157static int cols_init(struct cfdisk *cf)
158{
159 assert(cf);
5c36a0eb 160
8c3a5a44
KZ
161 free(cf->cols);
162 cf->cols = NULL;
163 cf->ncols = 0;
5c36a0eb 164
8c3a5a44 165 return fdisk_get_columns(cf->cxt, 0, &cf->cols, &cf->ncols);
5c36a0eb
KZ
166}
167
8c3a5a44
KZ
168/* It would be possible to use fdisk_table_to_string(), but we want some
169 * extension to the output format, so let's do it without libfdisk
170 */
171static char *table_to_string(struct cfdisk *cf, struct fdisk_table *tb)
172{
8c3a5a44 173 const struct fdisk_column *col;
8903f7df 174 struct fdisk_partition *pa;
8c3a5a44
KZ
175 struct fdisk_label *lb;
176 struct fdisk_iter *itr = NULL;
177 struct tt *tt = NULL;
178 char *res = NULL;
8903f7df 179 size_t i;
45333e9d 180 int tree = 0;
8903f7df 181 struct tt_line *ln_cont = NULL;
8c3a5a44
KZ
182
183 DBG(FRONTEND, dbgprint("table: convert to string"));
184
185 assert(cf);
186 assert(cf->cxt);
187 assert(cf->cols);
188 assert(tb);
189
190 lb = fdisk_context_get_label(cf->cxt, NULL);
191 assert(lb);
192
8c3a5a44
KZ
193 itr = fdisk_new_iter(FDISK_ITER_FORWARD);
194 if (!itr)
195 goto done;
5c36a0eb 196
45333e9d
KZ
197 /* get container (e.g. extended partition) */
198 while (fdisk_table_next_partition(tb, itr, &pa) == 0) {
199 if (fdisk_partition_is_nested(pa)) {
200 DBG(FRONTEND, dbgprint("table: nested detected, using tree"));
45333e9d
KZ
201 tree = TT_FL_TREE;
202 break;
203 }
204 }
45333e9d
KZ
205
206 tt = tt_new_table(TT_FL_FREEDATA | TT_FL_MAX | tree);
207 if (!tt)
208 goto done;
209
8c3a5a44
KZ
210 /* headers */
211 for (i = 0; i < cf->ncols; i++) {
212 col = fdisk_label_get_column(lb, cf->cols[i]);
45333e9d
KZ
213 if (col) {
214 int fl = col->tt_flags;
45333e9d
KZ
215 if (tree && col->id == FDISK_COL_DEVICE)
216 fl |= TT_FL_TREE;
217 tt_define_column(tt, col->name, col->width, fl);
218 }
8c3a5a44
KZ
219 }
220
221 /* data */
8903f7df
KZ
222 fdisk_reset_iter(itr, FDISK_ITER_FORWARD);
223
8c3a5a44 224 while (fdisk_table_next_partition(tb, itr, &pa) == 0) {
8903f7df
KZ
225 struct tt_line *ln;
226 struct tt_line *parent = fdisk_partition_is_nested(pa) ? ln_cont : NULL;
227
228 ln = tt_add_line(tt, parent);
8c3a5a44
KZ
229 if (!ln)
230 goto done;
231 for (i = 0; i < cf->ncols; i++) {
232 char *cdata = NULL;
8c3a5a44
KZ
233 col = fdisk_label_get_column(lb, cf->cols[i]);
234 if (!col)
235 continue;
236 if (fdisk_partition_to_string(pa, cf->cxt, col->id, &cdata))
237 continue;
238 tt_line_set_data(ln, i, cdata);
239 }
8903f7df 240 if (tree && fdisk_partition_is_container(pa))
45333e9d 241 ln_cont = ln;
8c3a5a44 242 }
6dbe3af9 243
8c3a5a44
KZ
244 if (!tt_is_empty(tt)) {
245 tt_set_termreduce(tt, ARROW_CURSOR_WIDTH);
246 tt_print_table_to_string(tt, &res);
247 }
248done:
249 tt_free_table(tt);
250 fdisk_free_iter(itr);
6dbe3af9 251
8c3a5a44 252 return res;
2b6fc908
KZ
253}
254
8460875d 255static int lines_refresh(struct cfdisk *cf)
8c3a5a44
KZ
256{
257 int rc;
258 char *p;
259 size_t i;
7eda085c 260
8c3a5a44 261 assert(cf);
2b6fc908 262
1af8003b 263 DBG(FRONTEND, dbgprint("refreshing buffer"));
c64061c9 264
8c3a5a44
KZ
265 free(cf->linesbuf);
266 free(cf->lines);
267 cf->linesbuf = NULL;
268 cf->linesbufsz = 0;
269 cf->lines = NULL;
270 cf->nlines = 0;
6dbe3af9 271
8c3a5a44 272 fdisk_unref_table(cf->table);
1af8003b 273 cf->table = NULL;
6dbe3af9 274
2cec7949
KZ
275 /* read partitions and free spaces into cf->table */
276 rc = fdisk_get_partitions(cf->cxt, &cf->table);
277 if (!rc)
278 rc = fdisk_get_freespaces(cf->cxt, &cf->table);
8c3a5a44
KZ
279 if (rc)
280 return rc;
0d8589c5 281
8c3a5a44
KZ
282 cf->linesbuf = table_to_string(cf, cf->table);
283 if (!cf->linesbuf)
284 return -ENOMEM;
6dbe3af9 285
8c3a5a44
KZ
286 cf->linesbufsz = strlen(cf->linesbuf);
287 cf->nlines = fdisk_table_get_nents(cf->table) + 1; /* 1 for header line */
6dbe3af9 288
8c3a5a44
KZ
289 cf->lines = calloc(cf->nlines, sizeof(char *));
290 if (!cf->lines)
291 return -ENOMEM;
6dbe3af9 292
8c3a5a44
KZ
293 for (p = cf->linesbuf, i = 0; p && i < cf->nlines; i++) {
294 cf->lines[i] = p;
295 p = strchr(p, '\n');
296 if (p) {
297 *p = '\0';
298 p++;
299 }
300 }
6dbe3af9 301
8c3a5a44 302 return 0;
6dbe3af9
KZ
303}
304
00b4f26a
KZ
305static struct fdisk_partition *get_current_partition(struct cfdisk *cf)
306{
307 assert(cf);
308 assert(cf->table);
309
310 return fdisk_table_get_partition(cf->table, cf->lines_idx);
311}
312
45333e9d
KZ
313static int is_freespace(struct cfdisk *cf, size_t i)
314{
315 struct fdisk_partition *pa;
316
317 assert(cf);
318 assert(cf->table);
319
320 pa = fdisk_table_get_partition(cf->table, i);
321 return fdisk_partition_is_freespace(pa);
322}
323
b1f58330
KZ
324/* converts libfdisk FDISK_ASKTYPE_MENU to cfdisk menu and returns user's
325 * responseback to libfdisk
326 */
327static int ask_menu(struct fdisk_ask *ask, struct cfdisk *cf)
328{
329 struct cfdisk_menudesc *d, *cm;
330 int key;
331 size_t i = 0, nitems;
332 const char *name, *desc;
333
334 assert(ask);
335 assert(cf);
336
337 /* create cfdisk menu according to libfdisk ask-menu, note that the
338 * last cm[] item has to be empty -- so nitems + 1 */
339 nitems = fdisk_ask_menu_get_nitems(ask);
340 cm = calloc(nitems + 1, sizeof(struct cfdisk_menudesc));
341 if (!cm)
342 return -ENOMEM;
343
344 for (i = 0; i < nitems; i++) {
345 if (fdisk_ask_menu_get_item(ask, i, &key, &name, &desc))
346 break;
347 cm[i].key = key;
348 cm[i].desc = desc;
349 cm[i].name = name;
350 }
351
352 /* make the new menu active */
353 menu_push(cf, CFDISK_MENU_GENERATED, cm);
354 ui_draw_menu(cf);
355 refresh();
356
357 /* wait for keys */
358 do {
359 switch (getch()) {
360 case KEY_LEFT:
361#ifdef KEY_BTAB
362 case KEY_BTAB:
363#endif
364 ui_menu_goto(cf, cf->menu_idx - 1);
365 break;
366 case KEY_RIGHT:
367 case '\t':
368 ui_menu_goto(cf, cf->menu_idx + 1);
369 break;
370 case KEY_ENTER:
371 case '\n':
372 case '\r':
373 d = menu_get_menuitem(cf, cf->menu_idx);
374 if (d)
375 fdisk_ask_menu_set_result(ask, d->key);
376 menu_pop(cf);
377 free(cm);
378 return 0;
379 }
380 } while (1);
381
382 menu_pop(cf);
383 free(cm);
384 return -1;
385}
386
387
8c3a5a44
KZ
388static int ask_callback(struct fdisk_context *cxt, struct fdisk_ask *ask,
389 void *data __attribute__((__unused__)))
390{
391 int rc = 0;
6dbe3af9 392
8c3a5a44
KZ
393 assert(cxt);
394 assert(ask);
6dbe3af9 395
8c3a5a44
KZ
396 switch(fdisk_ask_get_type(ask)) {
397 case FDISK_ASKTYPE_INFO:
83fa0f80 398 ui_info(fdisk_ask_print_get_mesg(ask));
8c3a5a44
KZ
399 break;
400 case FDISK_ASKTYPE_WARNX:
83fa0f80 401 ui_warnx(fdisk_ask_print_get_mesg(ask));
8c3a5a44
KZ
402 break;
403 case FDISK_ASKTYPE_WARN:
83fa0f80 404 ui_warn(fdisk_ask_print_get_mesg(ask));
8c3a5a44 405 break;
b1f58330
KZ
406 case FDISK_ASKTYPE_MENU:
407 ask_menu(ask, (struct cfdisk *) data);
408 break;
8c3a5a44 409 default:
83fa0f80
KZ
410 ui_warnx(_("internal error: unsupported dialog type %d"),
411 fdisk_ask_get_type(ask));
8c3a5a44
KZ
412 return -EINVAL;
413 }
414 return rc;
fd6b7a7f 415}
6dbe3af9 416
6dbe3af9 417
8c3a5a44
KZ
418static int ui_end(struct cfdisk *cf)
419{
83fa0f80 420 if (cf && !ui_enabled)
8c3a5a44
KZ
421 return -EINVAL;
422
48d7b13a 423#if defined(HAVE_SLCURSES_H) || defined(HAVE_SLANG_SLCURSES_H)
8c3a5a44
KZ
424 SLsmg_gotorc(LINES - 1, 0);
425 SLsmg_refresh();
2b6fc908 426#else
8c3a5a44 427 mvcur(0, COLS - 1, LINES-1, 0);
2b6fc908 428#endif
8c3a5a44
KZ
429 nl();
430 endwin();
431 printf("\n");
432 return 0;
6dbe3af9
KZ
433}
434
1af8003b 435static void ui_vprint_center(int line, int attrs, const char *fmt, va_list ap)
f609e92e 436{
8c3a5a44 437 size_t width;
8c3a5a44 438 char *buf = NULL;
f609e92e 439
8c3a5a44
KZ
440 move(line, 0);
441 clrtoeol();
f609e92e 442
8c3a5a44 443 xvasprintf(&buf, fmt, ap);
fd6b7a7f 444
b1f58330 445 width = mbs_safe_width(buf);
91ba41ca
KZ
446 if (width > (size_t) COLS) {
447 char *p = strrchr(buf + COLS, ' ');
448 if (!p)
449 p = buf + COLS;
450 *p = '\0';
451 if (line + 1 >= LINES)
452 line--;
453 attron(attrs);
454 mvaddstr(line, 0, buf);
455 mvaddstr(line + 1, 0, p+1);
456 attroff(attrs);
457 } else {
458 attron(attrs);
459 mvaddstr(line, (COLS - width) / 2, buf);
460 attroff(attrs);
461 }
8c3a5a44 462 free(buf);
6dbe3af9
KZ
463}
464
1af8003b
KZ
465static void ui_center(int line, const char *fmt, ...)
466{
467 va_list ap;
468 va_start(ap, fmt);
469 ui_vprint_center(line, 0, fmt, ap);
470 va_end(ap);
471}
472
83fa0f80
KZ
473static void ui_warnx(const char *fmt, ...)
474{
475 va_list ap;
476 va_start(ap, fmt);
477 if (ui_enabled)
478 ui_vprint_center(INFO_LINE, COLOR_PAIR(CFDISK_CL_WARNING), fmt, ap);
479 else
480 vfprintf(stderr, fmt, ap);
481 va_end(ap);
482}
483
484static void ui_warn(const char *fmt, ...)
1af8003b 485{
83fa0f80 486 char *fmt_m;
1af8003b 487 va_list ap;
83fa0f80
KZ
488
489 xasprintf(&fmt_m, "%s: %m", fmt);
490
1af8003b 491 va_start(ap, fmt);
83fa0f80
KZ
492 if (ui_enabled)
493 ui_vprint_center(INFO_LINE, COLOR_PAIR(CFDISK_CL_WARNING), fmt_m, ap);
494 else
495 vfprintf(stderr, fmt_m, ap);
1af8003b 496 va_end(ap);
83fa0f80 497 free(fmt_m);
1af8003b
KZ
498}
499
500static void ui_info(const char *fmt, ...)
501{
502 va_list ap;
503 va_start(ap, fmt);
83fa0f80
KZ
504 if (ui_enabled)
505 ui_vprint_center(INFO_LINE, A_BOLD, fmt, ap);
506 else
507 vfprintf(stdout, fmt, ap);
1af8003b
KZ
508 va_end(ap);
509}
510
511static void ui_clean_info(void)
512{
513 move(INFO_LINE, 0);
514 clrtoeol();
515}
6dbe3af9 516
b1f58330
KZ
517static void ui_hint(const char *fmt, ...)
518{
519 va_list ap;
520 va_start(ap, fmt);
521 if (ui_enabled)
522 ui_vprint_center(HINT_LINE, A_BOLD, fmt, ap);
523 else
524 vfprintf(stdout, fmt, ap);
525 va_end(ap);
526}
527
528static void ui_clean_hint(void)
529{
530 move(HINT_LINE, 0);
531 clrtoeol();
532}
533
8c3a5a44
KZ
534static void die_on_signal(int dummy __attribute__((__unused__)))
535{
536 ui_end(NULL);
537 exit(EXIT_FAILURE);
6dbe3af9
KZ
538}
539
8c3a5a44
KZ
540static void menu_update_ignore(struct cfdisk *cf)
541{
00b4f26a
KZ
542 char ignore[128] = { 0 };
543 int i = 0;
544 struct fdisk_partition *pa;
8c3a5a44 545 struct cfdisk_menu *m;
83fa0f80
KZ
546 struct cfdisk_menudesc *d, *org;
547 size_t idx;
6dbe3af9 548
8c3a5a44 549 assert(cf);
6dbe3af9 550
8c3a5a44 551 m = cf->menu;
83fa0f80
KZ
552 org = menu_get_menuitem(cf, cf->menu_idx);
553
8c3a5a44 554 DBG(FRONTEND, dbgprint("menu: update menu ignored keys"));
6dbe3af9 555
8c3a5a44
KZ
556 switch (m->id) {
557 case CFDISK_MENU_MAIN:
00b4f26a
KZ
558 pa = get_current_partition(cf);
559 if (!pa)
560 break;
561 if (fdisk_partition_is_freespace(pa)) {
562 ignore[i++] = 'd'; /* delete */
563 ignore[i++] = 't'; /* set type */
564 ignore[i++] = 'b'; /* set bootable */
83fa0f80 565 } else {
00b4f26a 566 ignore[i++] = 'n';
83fa0f80
KZ
567 if (!fdisk_is_disklabel(cf->cxt, DOS) &&
568 !fdisk_is_disklabel(cf->cxt, SGI))
569 ignore[i++] = 'b';
570 }
00b4f26a 571
8c3a5a44 572 break;
fd6b7a7f 573 }
6dbe3af9 574
00b4f26a
KZ
575 ignore[i] = '\0';
576
8c3a5a44 577 /* return if no change */
00b4f26a
KZ
578 if ( (!m->ignore && !*ignore)
579 || (m->ignore && *ignore && strcmp(m->ignore, ignore) == 0)) {
8c3a5a44 580 return;
fd6b7a7f 581 }
6dbe3af9 582
8c3a5a44 583 free(m->ignore);
8460875d 584 m->ignore = xstrdup(ignore);
8c3a5a44 585 m->nitems = 0;
6dbe3af9 586
8c3a5a44
KZ
587 for (d = m->desc; d->name; d++) {
588 if (m->ignore && strchr(m->ignore, d->key))
8460875d
KZ
589 continue;
590 m->nitems++;
8c3a5a44 591 }
83fa0f80
KZ
592
593 /* refresh menu index to be at the same menuitem or go to the first */
594 if (org && menu_get_menuitem_by_key(cf, org->key, &idx))
595 cf->menu_idx = idx;
596 else
597 cf->menu_idx = 0;
6dbe3af9
KZ
598}
599
b1f58330
KZ
600static struct cfdisk_menu *menu_push(
601 struct cfdisk *cf,
602 size_t id,
603 struct cfdisk_menudesc *desc)
8c3a5a44
KZ
604{
605 struct cfdisk_menu *m = xcalloc(1, sizeof(*m));
606 struct cfdisk_menudesc *d;
6dbe3af9 607
8c3a5a44 608 assert(cf);
6dbe3af9 609
8c3a5a44 610 DBG(FRONTEND, dbgprint("menu: new menu"));
6dbe3af9 611
8c3a5a44
KZ
612 m->prev = cf->menu;
613 m->id = id;
b1f58330 614 m->desc = desc ? desc : menus[id];
8460875d 615 m->callback = menu_callbacks[id];
6dbe3af9 616
8c3a5a44
KZ
617 for (d = m->desc; d->name; d++) {
618 const char *name = _(d->name);
b1f58330 619 size_t len = mbs_safe_width(name);
8c3a5a44
KZ
620 if (len > m->width)
621 m->width = len;
622 m->nitems++;
623 }
6dbe3af9 624
8c3a5a44
KZ
625 cf->menu = m;
626 return m;
6dbe3af9
KZ
627}
628
8c3a5a44 629static struct cfdisk_menu *menu_pop(struct cfdisk *cf)
6dbe3af9 630{
8c3a5a44 631 struct cfdisk_menu *m = NULL;
6dbe3af9 632
8c3a5a44 633 assert(cf);
7eda085c 634
8c3a5a44 635 DBG(FRONTEND, dbgprint("menu: rem menu"));
7eda085c 636
8c3a5a44
KZ
637 if (cf->menu) {
638 m = cf->menu->prev;
639 free(cf->menu->ignore);
640 free(cf->menu);
c07ebfa1 641 }
8c3a5a44
KZ
642 cf->menu = m;
643 return cf->menu;
6dbe3af9
KZ
644}
645
8460875d
KZ
646/* returns: error: < 0, success: 0, quit: 1 */
647static int menu_cb_main(struct cfdisk *cf, int key)
648{
83fa0f80 649 size_t n;
b1f58330 650 int ref = 0, rc;
83fa0f80 651 const char *info = NULL, *warn = NULL;
b1f58330 652 struct fdisk_partition *pa;
1af8003b
KZ
653
654 assert(cf);
655 assert(cf->cxt);
656 assert(key);
657
b1f58330 658 pa = get_current_partition(cf);
d80921ac 659 n = fdisk_partition_get_partno(pa);
83fa0f80 660
8460875d 661 switch (key) {
83fa0f80
KZ
662 case 'b': /* Bootable flag */
663 {
664 int fl = fdisk_is_disklabel(cf->cxt, DOS) ? DOS_FLAG_ACTIVE :
665 fdisk_is_disklabel(cf->cxt, SGI) ? SGI_FLAG_BOOT : 0;
666
667 if (fl && fdisk_partition_toggle_flag(cf->cxt, n, fl))
668 warn = _("Could not toggle the flag.");
669 else if (fl)
670 ref = 1;
671 break;
672 }
8460875d 673 case 'd': /* Delete */
83fa0f80
KZ
674 if (fdisk_delete_partition(cf->cxt, n) != 0)
675 warn = _("Could not delete partition %zu.");
1af8003b 676 else
83fa0f80
KZ
677 info = _("Partition %zu has been deleted.");
678 ref = 1;
8460875d
KZ
679 break;
680 case 'n': /* New */
b1f58330 681 {
872d2389 682 uint64_t start, size, dflt_size;
b1f58330
KZ
683 struct fdisk_partition *npa; /* the new partition */
684
685 if (!pa || !fdisk_partition_is_freespace(pa))
686 return -EINVAL;
687 npa = fdisk_new_partition();
688 if (!npa)
689 return -ENOMEM;
690 /* free space range */
691 start = fdisk_partition_get_start(pa);
872d2389 692 size = dflt_size = fdisk_partition_get_size(pa) * cf->cxt->sector_size;
b1f58330
KZ
693
694 if (ui_get_size(cf, _("Partition size: "), &size, 1, size)
695 == -CFDISK_ERR_ESC)
696 break;
872d2389
KZ
697
698 if (dflt_size == size) /* default is to fillin all free space */
699 fdisk_partition_end_follow_default(npa, 1);
700 else /* set relative size of the partition */
701 fdisk_partition_set_size(npa, size / cf->cxt->sector_size);
702
b1f58330 703 fdisk_partition_set_start(npa, start);
872d2389 704 fdisk_partition_partno_follow_default(npa, 1);
b1f58330
KZ
705 /* add to disk label -- libfdisk will ask for missing details */
706 rc = fdisk_add_partition(cf->cxt, npa);
707 fdisk_unref_partition(npa);
708 if (rc == 0)
709 ref = 1;
8460875d 710 break;
b1f58330 711 }
8460875d
KZ
712 case 'q': /* Quit */
713 return 1;
714 case 't': /* Type */
715 break;
716 case 'W': /* Write */
717 break;
8460875d 718 }
83fa0f80
KZ
719
720 if (ref) {
721 lines_refresh(cf);
722 ui_refresh(cf);
723 }
724 if (warn)
725 ui_warnx(warn, n);
726 else if (info)
727 ui_info(info, n);
728
8460875d
KZ
729 return 0;
730}
7eda085c 731
b1f58330 732static int ui_init(struct cfdisk *cf __attribute__((__unused__)))
8c3a5a44
KZ
733{
734 struct sigaction sa;
6dbe3af9 735
8c3a5a44 736 DBG(FRONTEND, dbgprint("ui: init"));
6dbe3af9 737
8c3a5a44
KZ
738 /* setup SIGCHLD handler */
739 sigemptyset(&sa.sa_mask);
740 sa.sa_flags = 0;
741 sa.sa_handler = die_on_signal;
742 sigaction(SIGINT, &sa, NULL);
743 sigaction(SIGTERM, &sa, NULL);
6dbe3af9 744
83fa0f80 745 ui_enabled = 1;
8c3a5a44 746 initscr();
6dbe3af9 747
1af8003b
KZ
748 if (has_colors()) {
749 size_t i;
750
751 start_color();
752 use_default_colors();
753
754 for (i = 1; i < ARRAY_SIZE(color_pairs); i++) /* yeah, start from 1! */
755 init_pair(i, color_pairs[i][0], color_pairs[i][1]);
756 }
757
8c3a5a44
KZ
758 cbreak();
759 noecho();
760 nonl();
761 curs_set(0);
762 keypad(stdscr, TRUE);
6dbe3af9 763
8c3a5a44 764 return 0;
7eda085c
KZ
765}
766
8c3a5a44
KZ
767static size_t menuitem_get_line(struct cfdisk *cf, size_t idx)
768{
769 size_t len = cf->menu->width + 4 + MENU_PADDING; /* item width */
770 size_t items = COLS / len; /* items per line */
7eda085c 771
8c3a5a44 772 return MENU_START_LINE + ((idx / items));
7eda085c
KZ
773}
774
8c3a5a44
KZ
775static int menuitem_get_column(struct cfdisk *cf, size_t idx)
776{
777 size_t len = cf->menu->width + 4 + MENU_PADDING; /* item width */
778 size_t items = COLS / len; /* items per line */
779 size_t extra = items < cf->menu->nitems ? /* extra space on line */
780 COLS % len : /* - multi-line menu */
781 COLS - (cf->menu->nitems * len); /* - one line menu */
df1dddf9 782
8c3a5a44 783 extra += MENU_PADDING; /* add padding after last item to extra */
e66ac5d3 784
8c3a5a44
KZ
785 if (idx < items)
786 return (idx * len) + (extra / 2);
787 return ((idx % items) * len) + (extra / 2);
df1dddf9
KZ
788}
789
8c3a5a44
KZ
790static struct cfdisk_menudesc *menu_get_menuitem(struct cfdisk *cf, size_t idx)
791{
792 struct cfdisk_menudesc *d;
793 size_t i;
7eda085c 794
8c3a5a44
KZ
795 for (i = 0, d = cf->menu->desc; d->name; d++) {
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
83fa0f80
KZ
805static struct cfdisk_menudesc *menu_get_menuitem_by_key(struct cfdisk *cf,
806 int key, size_t *idx)
807{
808 struct cfdisk_menudesc *d;
809
810 for (*idx = 0, d = cf->menu->desc; d->name; d++) {
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
KZ
821static void ui_draw_menuitem(struct cfdisk *cf,
822 struct cfdisk_menudesc *d,
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 */
828 int ln, cl;
829
830 name = _(d->name);
831 mbsalign(name, buf, sizeof(buf), &width, MBS_ALIGN_CENTER, 0);
832
833 ln = menuitem_get_line(cf, idx);
834 cl = menuitem_get_column(cf, idx);
835
836 DBG(FRONTEND, dbgprint("ui: menuitem: cl=%d, ln=%d, item='%s'",
837 cl, ln, buf));
838
839 if (cf->menu_idx == idx) {
840 standout();
841 mvprintw(ln, cl, "[%s]", buf);
842 standend();
843 if (d->desc)
b1f58330 844 ui_hint(d->desc);
8c3a5a44
KZ
845 } else
846 mvprintw(ln, cl, "[%s]", buf);
6dbe3af9
KZ
847}
848
8c3a5a44
KZ
849static void ui_draw_menu(struct cfdisk *cf)
850{
851 struct cfdisk_menudesc *d;
852 size_t i = 0;
7eda085c 853
8c3a5a44
KZ
854 assert(cf);
855 assert(cf->menu);
fd6b7a7f 856
8c3a5a44 857 DBG(FRONTEND, dbgprint("ui: menu: draw start"));
6dbe3af9 858
00b4f26a
KZ
859 for (i = MENU_START_LINE; i < (size_t) LINES - 1; i++) {
860 move(i, 0);
861 clrtoeol();
862 }
863
8c3a5a44 864 menu_update_ignore(cf);
6dbe3af9 865
00b4f26a 866 i = 0;
8c3a5a44
KZ
867 while ((d = menu_get_menuitem(cf, i)))
868 ui_draw_menuitem(cf, d, i++);
6dbe3af9 869
8c3a5a44 870 DBG(FRONTEND, dbgprint("ui: menu: draw end."));
6dbe3af9
KZ
871}
872
8c3a5a44
KZ
873static void ui_menu_goto(struct cfdisk *cf, int where)
874{
875 struct cfdisk_menudesc *d;
876 size_t old;
877
878 if (where < 0)
879 where = cf->menu->nitems - 1;
880 else if ((size_t) where > cf->menu->nitems - 1)
881 where = 0;
882 if ((size_t) where == cf->menu_idx)
883 return;
6dbe3af9 884
1af8003b
KZ
885 ui_clean_info();
886
8c3a5a44
KZ
887 old = cf->menu_idx;
888 cf->menu_idx = where;
6dbe3af9 889
8c3a5a44
KZ
890 d = menu_get_menuitem(cf, old);
891 ui_draw_menuitem(cf, d, old);
6dbe3af9 892
8c3a5a44
KZ
893 d = menu_get_menuitem(cf, where);
894 ui_draw_menuitem(cf, d, where);
6dbe3af9
KZ
895}
896
8460875d 897/* returns: error: < 0, success: 0, quit: 1 */
8c3a5a44
KZ
898static int ui_menu_action(struct cfdisk *cf, int key)
899{
8460875d
KZ
900 assert(cf);
901 assert(cf->menu);
902 assert(cf->menu->callback);
903
904 if (key == 0) {
905 struct cfdisk_menudesc *d = menu_get_menuitem(cf, cf->menu_idx);
906 if (!d)
907 return 0;
908 key = d->key;
00b4f26a
KZ
909
910 } else if (key != 'w' && key != 'W')
911 key = tolower(key); /* case insensitive except 'W'rite */
8460875d
KZ
912
913 DBG(FRONTEND, dbgprint("ui: menu action: key=%c", key));
914
915 if (cf->menu->ignore && strchr(cf->menu->ignore, key)) {
916 DBG(FRONTEND, dbgprint(" ignore '%c'", key));
917 return 0;
918 }
919
920 return cf->menu->callback(cf, key);
6dbe3af9
KZ
921}
922
8c3a5a44
KZ
923static void ui_draw_partition(struct cfdisk *cf, size_t i)
924{
925 int ln = TABLE_START_LINE + 1 + i; /* skip table header */
926 int cl = ARROW_CURSOR_WIDTH; /* we need extra space for cursor */
6dbe3af9 927
8c3a5a44 928 DBG(FRONTEND, dbgprint("ui: draw partition %zu", i));
6dbe3af9 929
8c3a5a44
KZ
930 if (cf->lines_idx == i) {
931 standout();
932 mvaddstr(ln, 0, ARROW_CURSOR_STRING);
933 mvaddstr(ln, cl, cf->lines[i + 1]);
934 standend();
6dbe3af9 935 } else {
45333e9d
KZ
936 int at = 0;
937
938 if (is_freespace(cf, i)) {
939 attron(COLOR_PAIR(CFDISK_CL_FREESPACE));
940 at = 1;
941 }
8c3a5a44
KZ
942 mvaddstr(ln, 0, ARROW_CURSOR_DUMMY);
943 mvaddstr(ln, cl, cf->lines[i + 1]);
45333e9d
KZ
944 if (at)
945 attroff(COLOR_PAIR(CFDISK_CL_FREESPACE));
6dbe3af9
KZ
946 }
947
6dbe3af9
KZ
948}
949
8c3a5a44
KZ
950static int ui_draw_table(struct cfdisk *cf)
951{
952 int cl = ARROW_CURSOR_WIDTH;
953 size_t i, nparts = fdisk_table_get_nents(cf->table);
7eda085c 954
8c3a5a44 955 DBG(FRONTEND, dbgprint("ui: draw table"));
6dbe3af9 956
8c3a5a44
KZ
957 if (cf->nlines - 2 < cf->lines_idx)
958 cf->lines_idx = cf->nlines - 2; /* don't count header */
6dbe3af9 959
8c3a5a44
KZ
960 /* print header */
961 attron(A_BOLD);
962 mvaddstr(TABLE_START_LINE, cl, cf->lines[0]);
963 attroff(A_BOLD);
6dbe3af9 964
8c3a5a44
KZ
965 /* print partitions */
966 for (i = 0; i < nparts; i++)
967 ui_draw_partition(cf, i);
6dbe3af9 968
8c3a5a44 969 return 0;
6dbe3af9
KZ
970}
971
8c3a5a44
KZ
972static int ui_table_goto(struct cfdisk *cf, int where)
973{
974 size_t old;
975 size_t nparts = fdisk_table_get_nents(cf->table);
6dbe3af9 976
8c3a5a44 977 DBG(FRONTEND, dbgprint("ui: goto table %d", where));
6dbe3af9 978
8c3a5a44
KZ
979 if (where < 0)
980 where = 0;
981 else if ((size_t) where > nparts - 1)
982 where = nparts - 1;
6dbe3af9 983
8c3a5a44
KZ
984 if ((size_t) where == cf->lines_idx)
985 return 0;
6dbe3af9 986
8c3a5a44
KZ
987 old = cf->lines_idx;
988 cf->lines_idx = where;
6dbe3af9 989
8c3a5a44
KZ
990 ui_draw_partition(cf, old); /* cleanup old */
991 ui_draw_partition(cf, where); /* draw new */
1af8003b 992 ui_clean_info();
8c3a5a44
KZ
993 ui_draw_menu(cf);
994 refresh();
995 return 0;
6dbe3af9
KZ
996}
997
8c3a5a44
KZ
998static int ui_refresh(struct cfdisk *cf)
999{
1000 char *id = NULL;
1001 uint64_t bytes = cf->cxt->total_sectors * cf->cxt->sector_size;
1002 char *strsz = size_to_human_string(SIZE_SUFFIX_SPACE
1003 | SIZE_SUFFIX_3LETTER, bytes);
1004 erase();
1005
83fa0f80 1006 if (!ui_enabled)
8c3a5a44
KZ
1007 return -EINVAL;
1008
1009 /* header */
1010 attron(A_BOLD);
1af8003b 1011 ui_center(0, _("Disk: %s"), cf->cxt->dev_path);
8c3a5a44 1012 attroff(A_BOLD);
1af8003b 1013 ui_center(1, _("Size: %s, %ju bytes, %ju sectors"),
8c3a5a44
KZ
1014 strsz, bytes, (uintmax_t) cf->cxt->total_sectors);
1015 if (fdisk_get_disklabel_id(cf->cxt, &id) == 0 && id)
1af8003b 1016 ui_center(2, _("Label: %s, identifier: %s"),
8c3a5a44 1017 cf->cxt->label->name, id);
7eda085c 1018 else
1af8003b 1019 ui_center(2, _("Label: %s"));
8c3a5a44 1020 free(strsz);
6dbe3af9 1021
8c3a5a44
KZ
1022 ui_draw_table(cf);
1023 ui_draw_menu(cf);
6dbe3af9 1024 refresh();
8c3a5a44 1025 return 0;
6dbe3af9
KZ
1026}
1027
b1f58330
KZ
1028static ssize_t ui_get_string(struct cfdisk *cf, const char *prompt,
1029 const char *hint, char *buf, size_t len)
1030{
1031 size_t cells = 0;
1032 ssize_t i = 0, rc = -1;
1033 wint_t c;
1034 int ln = MENU_START_LINE, cl = 1;
1035
1036 assert(cf);
1037 assert(buf);
1038 assert(len);
1039
1040 move(ln, 0);
1041 clrtoeol();
1042
1043 if (prompt) {
1044 mvaddstr(ln, cl, prompt);
1045 cl += mbs_safe_width(prompt);
1046 }
1047
1048 /* default value */
1049 if (*buf) {
1050 i = strlen(buf);
1051 cells = mbs_safe_width(buf);
1052 mvaddstr(ln, cl, buf);
1053 }
1054
1055 if (hint)
1056 ui_hint(hint);
1057 else
1058 ui_clean_hint();
1059
1060 move(ln, cl + cells);
1061 curs_set(1);
1062 refresh();
1063
1064 while (1) {
1065#if !defined(HAVE_SLCURSES_H) && !defined(HAVE_SLANG_SLCURSES_H) && \
1066 defined(HAVE_LIBNCURSESW) && defined(HAVE_WIDECHAR)
1067 if (get_wch(&c) == ERR) {
1068#else
1069 if ((c = getch()) == ERR) {
1070#endif
1071 if (!isatty(STDIN_FILENO))
1072 exit(2);
1073 else
1074 goto done;
1075 }
1076 if (c == '\r' || c == '\n' || c == KEY_ENTER)
1077 break;
1078
1079 switch (c) {
1080 case KEY_ESC:
1081 rc = -CFDISK_ERR_ESC;
1082 goto done;
1083 case KEY_DELETE:
1084 case '\b':
1085 case KEY_BACKSPACE:
1086 if (i > 0) {
1087 cells--;
1088 i = mbs_truncate(buf, &cells);
1089 if (i < 0)
1090 goto done;
1091 mvaddch(ln, cl + cells, ' ');
1092 move(ln, cl + cells);
1093 } else
1094 beep();
1095 break;
1096 default:
1097#if defined(HAVE_LIBNCURSESW) && defined(HAVE_WIDECHAR)
1098 if (i + 1 < (ssize_t) len && iswprint(c)) {
1099 wchar_t wc = (wchar_t) c;
1100 char s[MB_CUR_MAX + 1];
1101 int sz = wctomb(s, wc);
1102
1103 if (sz > 0 && sz + i < (ssize_t) len) {
1104 s[sz] = '\0';
1105 mvaddnstr(ln, cl + cells, s, sz);
1106 memcpy(buf + i, s, sz);
1107 i += sz;
1108 buf[i] = '\0';
1109 cells += wcwidth(wc);
1110 } else
1111 beep();
1112 }
1113#else
1114 if (i + 1 < (ssize_t) len && isprint(c)) {
1115 mvaddch(ln, cl + cells, c);
1116 str[i++] = c;
1117 str[i] = '\0';
1118 cells++;
1119 }
1120#endif
1121 else
1122 beep();
1123 }
1124 refresh();
1125 }
1126
1127 rc = i; /* success */
1128done:
1129 move(ln, 0);
1130 clrtoeol();
1131 curs_set(0);
1132 refresh();
1133
1134 return rc;
1135}
1136
1137/* @res is default value as well as result in bytes */
1138static int ui_get_size(struct cfdisk *cf, const char *prompt, uintmax_t *res,
1139 uintmax_t low, uintmax_t up)
1140{
1141 char buf[128];
1142 uintmax_t user = 0;
1143 ssize_t rc;
1144 char *dflt = size_to_human_string(0, *res);
1145
1146 DBG(FRONTEND, dbgprint("ui: get_size (default=%ju)", *res));
1147
1148 ui_clean_info();
1149
1150 do {
91ba41ca 1151 int pwr = 0, insec = 0;
b1f58330
KZ
1152
1153 snprintf(buf, sizeof(buf), "%s", dflt);
1154 rc = ui_get_string(cf, prompt,
91ba41ca
KZ
1155 _("The size may be followed by {M,B,G,T}iB "
1156 "(the \"iB\" is optional) or S for sectors."),
b1f58330
KZ
1157 buf, sizeof(buf));
1158 if (rc == 0) {
1159 ui_warnx(_("Please, specify size."));
1160 continue; /* nothing specified */
1161 } else if (rc == -CFDISK_ERR_ESC)
1162 break; /* cancel dialog */
1163
91ba41ca
KZ
1164 if (strcmp(buf, dflt) == 0)
1165 user = *res, rc = 0; /* no change, use default */
1166 else {
1167 size_t len = strlen(buf);
1168 if (buf[len - 1] == 'S') {
1169 insec = 1;
1170 buf[len - 1] = '\0';
1171 }
1172 rc = parse_size(buf, &user, &pwr); /* parse */
1173 }
1174
b1f58330 1175 if (rc == 0) {
91ba41ca
KZ
1176 DBG(FRONTEND, dbgprint("ui: get_size user=%ju, power=%d, sectors=%s",
1177 user, pwr, insec ? "yes" : "no"));
1178 if (insec)
1179 user *= cf->cxt->sector_size;
b1f58330
KZ
1180 if (user < low) {
1181 ui_warnx(_("Minimal size is %ju"), low);
1182 rc = -ERANGE;
1183 }
1184 if (user > up && pwr && user < up + (1ULL << pwr * 10))
1185 /* ignore when the user specified size overflow
1186 * with in range specified by suffix (e.g. MiB) */
1187 user = up;
1188
1189 if (user > up) {
1190 ui_warnx(_("Maximal size is %ju bytes."), up);
1191 rc = -ERANGE;
1192 }
2cec7949
KZ
1193 } else
1194 ui_warnx(_("Failed to parse size."));
b1f58330
KZ
1195 } while (rc != 0);
1196
1197 if (rc == 0)
1198 *res = user;
1199 free(dflt);
1200
1201 DBG(FRONTEND, dbgprint("ui: get_size (result=%ju, rc=%zd)", *res, rc));
1202 return rc;
1203}
1204
1205
8c3a5a44
KZ
1206static int ui_run(struct cfdisk *cf)
1207{
1208 int rc;
6dbe3af9 1209
8c3a5a44 1210 DBG(FRONTEND, dbgprint("ui: start COLS=%d, LINES=%d", COLS, LINES));
6dbe3af9 1211
b1f58330 1212 menu_push(cf, CFDISK_MENU_MAIN, NULL);
6dbe3af9 1213
8c3a5a44
KZ
1214 rc = ui_refresh(cf);
1215 if (rc)
1216 return rc;
6dbe3af9 1217
8c3a5a44 1218 do {
8460875d 1219 int rc = 0, key = getch();
6dbe3af9 1220
8c3a5a44
KZ
1221 switch (key) {
1222 case KEY_DOWN:
1223 case '\016': /* ^N */
1224 case 'j': /* Vi-like alternative */
1225 ui_table_goto(cf, cf->lines_idx + 1);
1226 break;
1227 case KEY_UP:
1228 case '\020': /* ^P */
1229 case 'k': /* Vi-like alternative */
1230 ui_table_goto(cf, cf->lines_idx - 1);
1231 break;
1232 case KEY_HOME:
1233 ui_table_goto(cf, 0);
1234 break;
1235 case KEY_END:
1236 ui_table_goto(cf, cf->nlines - 1);
1237 break;
1238 ui_menu_action(cf, 0);
1239 break;
1240 case KEY_LEFT:
1241#ifdef KEY_BTAB
1242 case KEY_BTAB:
6dbe3af9 1243#endif
8c3a5a44
KZ
1244 ui_menu_goto(cf, cf->menu_idx - 1);
1245 break;
1246 case KEY_RIGHT:
1247 case '\t':
1248 ui_menu_goto(cf, cf->menu_idx + 1);
1249 break;
1250 case KEY_ENTER:
1251 case '\n':
1252 case '\r':
8460875d 1253 rc = ui_menu_action(cf, 0);
8c3a5a44
KZ
1254 break;
1255 default:
8460875d
KZ
1256 rc = ui_menu_action(cf, key);
1257 if (rc < 0)
8c3a5a44
KZ
1258 beep();
1259 break;
1260 }
8460875d
KZ
1261
1262 if (rc == 1)
1263 break; /* quit */
8c3a5a44 1264 } while (1);
6dbe3af9 1265
8c3a5a44 1266 menu_pop(cf);
6dbe3af9 1267
8c3a5a44
KZ
1268 DBG(FRONTEND, dbgprint("ui: end"));
1269
1270 return 0;
1271}
6dbe3af9 1272
8c3a5a44
KZ
1273int main(int argc, char *argv[])
1274{
1275 struct cfdisk _cf = { .lines_idx = 0 },
1276 *cf = &_cf;
6dbe3af9 1277
8c3a5a44
KZ
1278 setlocale(LC_ALL, "");
1279 bindtextdomain(PACKAGE, LOCALEDIR);
1280 textdomain(PACKAGE);
1281 atexit(close_stdout);
6dbe3af9 1282
8c3a5a44
KZ
1283 fdisk_init_debug(0);
1284 cf->cxt = fdisk_new_context();
1285 if (!cf->cxt)
1286 err(EXIT_FAILURE, _("failed to allocate libfdisk context"));
6dbe3af9 1287
8c3a5a44 1288 fdisk_context_set_ask(cf->cxt, ask_callback, (void *) cf);
6dbe3af9 1289
8c3a5a44
KZ
1290 if (argc != 2)
1291 err(EXIT_FAILURE, "usage: %s <device>", argv[0]);
6dbe3af9 1292
8c3a5a44
KZ
1293 if (fdisk_context_assign_device(cf->cxt, argv[optind], 0) != 0)
1294 err(EXIT_FAILURE, _("cannot open %s"), argv[optind]);
6dbe3af9 1295
8c3a5a44 1296 cols_init(cf);
fd6b7a7f 1297
8460875d 1298 if (lines_refresh(cf))
8c3a5a44 1299 errx(EXIT_FAILURE, _("failed to read partitions"));
6dbe3af9 1300
8c3a5a44
KZ
1301 /* Don't use err(), warn() from this point */
1302 ui_init(cf);
1303 ui_run(cf);
1304 ui_end(cf);
6dbe3af9 1305
8c3a5a44
KZ
1306 free(cf->lines);
1307 free(cf->linesbuf);
1308 fdisk_unref_table(cf->table);
1309 fdisk_free_context(cf->cxt);
1310 return EXIT_SUCCESS;
6dbe3af9 1311}