]> git.ipfire.org Git - thirdparty/util-linux.git/blame - disk-utils/cfdisk.c
hexdump: check blocksize when display data
[thirdparty/util-linux.git] / disk-utils / cfdisk.c
CommitLineData
2ddfd9e4 1/*
9e95aa12
KZ
2 * SPDX-License-Identifier: GPL-2.0-or-later
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
2ddfd9e4
BS
9 * cfdisk.c - Display or manipulate a disk partition table.
10 *
793e8d2a 11 * Copyright (C) 2014-2023 Karel Zak <kzak@redhat.com>
2ddfd9e4
BS
12 * Copyright (C) 1994 Kevin E. Martin (martin@cs.unc.edu)
13 *
14 * The original cfdisk was inspired by the fdisk program
15 * by A. V. Le Blanc (leblanc@mcc.ac.uk.
2ddfd9e4 16 */
6dbe3af9
KZ
17#include <stdlib.h>
18#include <stdio.h>
6dbe3af9 19#include <errno.h>
8c3a5a44 20#include <signal.h>
00b4f26a 21#include <ctype.h>
04915c3f 22#include <getopt.h>
57c83d63 23#include <assert.h>
baa3b270 24#include <libsmartcols.h>
7556c944 25#include <sys/ioctl.h>
ad6d9fd5 26#include <rpmatch.h>
57c83d63 27#include <libfdisk.h>
541e6934 28
dda7fe12
OO
29#ifdef HAVE_LIBMOUNT
30# include <libmount.h> /* keep it optional for non-linux systems */
31#endif
32
541e6934 33#ifdef HAVE_SLANG_H
3b411726 34# include <slang.h>
541e6934 35#elif defined(HAVE_SLANG_SLANG_H)
3b411726 36# include <slang/slang.h>
541e6934
KZ
37#endif
38
cc6ab5ef
PS
39#ifndef _XOPEN_SOURCE
40# define _XOPEN_SOURCE 500 /* for inclusion of get_wch */
41#endif
42
48d7b13a 43#ifdef HAVE_SLCURSES_H
3b411726 44# include <slcurses.h>
48d7b13a 45#elif defined(HAVE_SLANG_SLCURSES_H)
3b411726 46# include <slang/slcurses.h>
30c97bb8 47#elif defined(HAVE_NCURSESW_NCURSES_H) && defined(HAVE_WIDECHAR)
3b411726 48# include <ncursesw/ncurses.h>
48d7b13a 49#elif defined(HAVE_NCURSES_H)
3b411726 50# include <ncurses.h>
48d7b13a 51#elif defined(HAVE_NCURSES_NCURSES_H)
3b411726 52# include <ncurses/ncurses.h>
2b6fc908 53#endif
541e6934 54
5f94ca33 55#ifdef HAVE_WIDECHAR
3b411726 56# include <wctype.h>
f1512be8 57# include <wchar.h>
5f94ca33
KZ
58#endif
59
8c3a5a44 60#include "c.h"
b2d28533 61#include "closestream.h"
7eda085c 62#include "nls.h"
8abcf290 63#include "strutils.h"
8c3a5a44 64#include "xalloc.h"
5f94ca33 65#include "mbsalign.h"
1b6d02fe 66#include "mbsedit.h"
04915c3f 67#include "colors.h"
57c83d63 68#include "debug.h"
dda7fe12 69#include "list.h"
ec8f7121 70#include "blkdev.h"
8c3a5a44 71
6e51ab0c 72static const char *default_disks[] = {
a4f0a42d 73#ifdef __GNU__
6e51ab0c
KZ
74 "/dev/hd0",
75 "/dev/sd0",
a4f0a42d 76#elif defined(__FreeBSD__)
6e51ab0c
KZ
77 "/dev/ad0",
78 "/dev/da0",
a4f0a42d 79#else
6e51ab0c
KZ
80 "/dev/sda",
81 "/dev/vda",
82 "/dev/hda",
a4f0a42d 83#endif
6e51ab0c 84};
a4f0a42d 85
c743bf74 86#define ARROW_CURSOR_STRING ">> "
8c3a5a44
KZ
87#define ARROW_CURSOR_DUMMY " "
88#define ARROW_CURSOR_WIDTH (sizeof(ARROW_CURSOR_STRING) - 1)
89
5c04b408
KZ
90/* vertical menu */
91#define MENU_V_SPADDING 1 /* space around menu item string */
92
93/* horizontal menu */
94#define MENU_H_SPADDING 0 /* space around menu item string */
95#define MENU_H_BETWEEN 2 /* space between menu items */
96#define MENU_H_PRESTR "["
97#define MENU_H_POSTSTR "]"
98
99#define MENU_TITLE_PADDING 3
100
101#define MENU_H_PRESTR_SZ (sizeof(MENU_H_PRESTR) - 1)
102#define MENU_H_POSTSTR_SZ (sizeof(MENU_H_POSTSTR) - 1)
103
8c3a5a44 104#define TABLE_START_LINE 4
6e07b904 105#define MENU_START_LINE (ui_lines - 4) /* The menu maybe use two lines */
eef63970 106#define INFO_LINE (ui_lines - 2)
702d0e1c 107#define WARN_LINE INFO_LINE
eef63970 108#define HINT_LINE (ui_lines - 1)
b1f58330
KZ
109
110#define CFDISK_ERR_ESC 5000
111
112#ifndef KEY_ESC
113# define KEY_ESC '\033'
114#endif
115#ifndef KEY_DELETE
116# define KEY_DELETE '\177'
117#endif
1b6d02fe
KZ
118#ifndef KEY_DC
119# define KEY_DC 0423
120#endif
121
1af8003b
KZ
122
123/* colors */
124enum {
125 CFDISK_CL_NONE = 0,
45333e9d
KZ
126 CFDISK_CL_WARNING,
127 CFDISK_CL_FREESPACE,
f9fb8290 128 CFDISK_CL_INFO
1af8003b 129};
061282b2 130#ifdef HAVE_USE_DEFAULT_COLORS
1af8003b
KZ
131static const int color_pairs[][2] = {
132 /* color foreground, background */
45333e9d 133 [CFDISK_CL_WARNING] = { COLOR_RED, -1 },
f9fb8290
KZ
134 [CFDISK_CL_FREESPACE] = { COLOR_GREEN, -1 },
135 [CFDISK_CL_INFO] = { COLOR_BLUE, -1 }
1af8003b 136};
061282b2 137#endif
8c3a5a44 138
8460875d 139struct cfdisk;
8460875d 140
3b411726
KZ
141static struct cfdisk_menuitem *menu_get_menuitem(struct cfdisk *cf, size_t idx);
142static struct cfdisk_menuitem *menu_get_menuitem_by_key(struct cfdisk *cf, int key, size_t *idx);
143static struct cfdisk_menu *menu_push(struct cfdisk *cf, struct cfdisk_menuitem *item);
b1f58330 144static struct cfdisk_menu *menu_pop(struct cfdisk *cf);
7556c944 145static void menu_refresh_size(struct cfdisk *cf);
83fa0f80 146
502c5186 147static int ui_end(void);
1af8003b 148static int ui_refresh(struct cfdisk *cf);
fbae1442
KZ
149
150static void ui_warnx(const char *fmt, ...)
151 __attribute__((__format__ (__printf__, 1, 2)));
152static void ui_warn(const char *fmt, ...)
153 __attribute__((__format__ (__printf__, 1, 2)));
154static void ui_info(const char *fmt, ...)
155 __attribute__((__format__ (__printf__, 1, 2)));
156
b1f58330 157static void ui_draw_menu(struct cfdisk *cf);
ac27ea5c 158static int ui_menu_move(struct cfdisk *cf, int key);
7556c944 159static void ui_menu_resize(struct cfdisk *cf);
ac27ea5c 160
7085f1e4
KZ
161static int ui_get_size(struct cfdisk *cf, const char *prompt, uint64_t *res,
162 uint64_t low, uint64_t up, int *expsize);
8460875d 163
83fa0f80 164static int ui_enabled;
502c5186
KZ
165static volatile sig_atomic_t sig_resize;
166static volatile sig_atomic_t sig_die;
8c3a5a44 167
eef63970
KZ
168/* ncurses LINES and COLS may be actual variables or *macros*, but we need
169 * something portable and writable */
2ba641e5
SK
170static size_t ui_lines;
171static size_t ui_cols;
eef63970 172
88942179 173/* menu item */
3b411726 174struct cfdisk_menuitem {
8c3a5a44
KZ
175 int key; /* keyboard shortcut */
176 const char *name; /* item name */
88942179 177 const char *desc; /* item description (hint) */
6fed9601 178 void *userdata;
749af4b6
KZ
179};
180
88942179 181/* menu */
8c3a5a44 182struct cfdisk_menu {
88942179
KZ
183 char *title; /* optional menu title */
184 struct cfdisk_menuitem *items; /* array with menu items */
185 char *ignore;/* string with keys to ignore */
186 size_t width; /* maximal width of the menu item */
187 size_t nitems; /* number of the active menu items */
188 size_t page_sz;/* when menu longer than screen */
189 size_t idx; /* the current menu item */
b5ef65a9 190 int prefkey;/* preferred menu item */
8c3a5a44 191 struct cfdisk_menu *prev;
88942179
KZ
192
193 /* @ignore keys generator */
63128bbf 194 int (*ignore_cb) (struct cfdisk *, char *, size_t);
8a726114 195
88942179 196 unsigned int vertical : 1; /* enable vertical mode */
749af4b6
KZ
197};
198
88942179 199/* main menu */
3b411726 200static struct cfdisk_menuitem main_menuitems[] = {
8c3a5a44
KZ
201 { 'b', N_("Bootable"), N_("Toggle bootable flag of the current partition") },
202 { 'd', N_("Delete"), N_("Delete the current partition") },
a351f2e5 203 { 'r', N_("Resize"), N_("Reduce or enlarge the current partition") },
8c3a5a44 204 { 'n', N_("New"), N_("Create new partition from free space") },
3d6db3fd 205 { 'q', N_("Quit"), N_("Quit program without writing changes") },
8c3a5a44 206 { 't', N_("Type"), N_("Change the partition type") },
314a0dd8 207 { 'h', N_("Help"), N_("Print help screen") },
d5314bf5 208 { 's', N_("Sort"), N_("Fix partitions order") },
8c3a5a44 209 { 'W', N_("Write"), N_("Write partition table to disk (this might destroy data)") },
a89eafed 210 { 'u', N_("Dump"), N_("Dump partition table to sfdisk compatible script file") },
8c3a5a44
KZ
211 { 0, NULL, NULL }
212};
6dbe3af9 213
dda7fe12
OO
214/* extra partinfo in name:value pairs */
215struct cfdisk_extra {
216 char *name;
217 char *data;
218
219 struct list_head exs;
220};
221
222/* line and extra partinfo list_head */
223struct cfdisk_line {
224 char *data; /* line data */
225 struct libscols_table *extra; /* extra info ('X') */
226 WINDOW *w; /* window with extra info */
227};
228
88942179 229/* top level control struct */
8c3a5a44
KZ
230struct cfdisk {
231 struct fdisk_context *cxt; /* libfdisk context */
232 struct fdisk_table *table; /* partition table */
044ebc0c 233 struct fdisk_table *original_layout; /* original on-disk PT */
dda7fe12 234
a6f69126 235 struct cfdisk_menu *menu; /* the current menu */
7eda085c 236
bd85d11f
KZ
237 int *fields; /* output columns IDs */
238 size_t nfields; /* number of columns IDs */
7eda085c 239
8c3a5a44
KZ
240 char *linesbuf; /* table as string */
241 size_t linesbufsz; /* size of the tb_buf */
7eda085c 242
dda7fe12
OO
243 struct cfdisk_line *lines; /* list of lines */
244
8c3a5a44 245 size_t nlines; /* number of lines */
a6f69126
KZ
246 size_t lines_idx; /* current line <0..N>, exclude header */
247 size_t page_sz;
d5314bf5 248
bc787727
KZ
249 unsigned int nwrites; /* fdisk_write_disklabel() counter */
250
dda7fe12
OO
251 WINDOW *act_win; /* the window currently on the screen */
252
253#ifdef HAVE_LIBMOUNT
254 struct libmnt_table *mtab;
255 struct libmnt_table *fstab;
256 struct libmnt_cache *mntcache;
257#endif
d121efdb 258 unsigned int wrong_order :1, /* PT not in right order */
dda7fe12 259 zero_start :1, /* ignore existing partition table */
044ebc0c 260 device_is_used : 1, /* don't use re-read ioctl */
dda7fe12 261 show_extra :1; /* show extra partinfo */
8c3a5a44 262};
5c36a0eb 263
14620822
KZ
264
265/*
266 * let's use include/debug.h stuff for cfdisk too
267 */
2ba641e5 268static UL_DEBUG_DEFINE_MASK(cfdisk);
819d9a29 269UL_DEBUG_DEFINE_MASKNAMES(cfdisk) = UL_DEBUG_EMPTY_MASKNAMES;
14620822
KZ
270
271#define CFDISK_DEBUG_INIT (1 << 1)
272#define CFDISK_DEBUG_UI (1 << 2)
273#define CFDISK_DEBUG_MENU (1 << 3)
274#define CFDISK_DEBUG_MISC (1 << 4)
275#define CFDISK_DEBUG_TABLE (1 << 5)
276#define CFDISK_DEBUG_ALL 0xFFFF
277
14620822
KZ
278#define DBG(m, x) __UL_DBG(cfdisk, CFDISK_DEBUG_, m, x)
279
280static void cfdisk_init_debug(void)
281{
a15dca2f 282 __UL_INIT_DEBUG_FROM_ENV(cfdisk, CFDISK_DEBUG_, 0, CFDISK_DEBUG);
14620822
KZ
283}
284
bd85d11f 285/* Initialize output columns -- we follow libfdisk fields (usually specific
88942179
KZ
286 * to the label type.
287 */
8c3a5a44
KZ
288static int cols_init(struct cfdisk *cf)
289{
290 assert(cf);
5c36a0eb 291
bd85d11f
KZ
292 free(cf->fields);
293 cf->fields = NULL;
294 cf->nfields = 0;
5c36a0eb 295
11ee1177 296 return fdisk_label_get_fields_ids(NULL, cf->cxt, &cf->fields, &cf->nfields);
5c36a0eb
KZ
297}
298
502c5186
KZ
299static void die_on_signal(void)
300{
301 DBG(MISC, ul_debug("die on signal."));
302 ui_end();
303 exit(EXIT_FAILURE);
304}
305
7556c944
KZ
306static void resize(void)
307{
308 struct winsize ws;
309
310 if (ioctl(fileno(stdout), TIOCGWINSZ, &ws) != -1
311 && ws.ws_row && ws.ws_col) {
eef63970
KZ
312 ui_lines = ws.ws_row;
313 ui_cols = ws.ws_col;
7556c944
KZ
314#if HAVE_RESIZETERM
315 resizeterm(ws.ws_row, ws.ws_col);
316#endif
317 clearok(stdscr, TRUE);
318 }
319 touchwin(stdscr);
320
eef63970
KZ
321 DBG(UI, ul_debug("ui: resize refresh ui_cols=%zu, ui_lines=%zu",
322 ui_cols, ui_lines));
c431d901 323 sig_resize = 0;
7556c944
KZ
324}
325
c743bf74
KZ
326/* Reads partition in tree-like order from scols
327 */
328static int partition_from_scols(struct fdisk_table *tb,
329 struct libscols_line *ln)
330{
331 struct fdisk_partition *pa = scols_line_get_userdata(ln);
332
333 fdisk_table_add_partition(tb, pa);
334 fdisk_unref_partition(pa);
335
336 if (scols_line_has_children(ln)) {
337 struct libscols_line *chln;
338 struct libscols_iter *itr = scols_new_iter(SCOLS_ITER_FORWARD);
339
340 if (!itr)
341 return -EINVAL;
342 while (scols_line_next_child(ln, itr, &chln) == 0)
343 partition_from_scols(tb, chln);
a9408274 344 scols_free_iter(itr);
c743bf74
KZ
345 }
346 return 0;
347}
348
8c3a5a44
KZ
349static char *table_to_string(struct cfdisk *cf, struct fdisk_table *tb)
350{
8903f7df 351 struct fdisk_partition *pa;
8c3a5a44 352 struct fdisk_label *lb;
1b504263 353 struct fdisk_iter *itr;
baa3b270
OO
354 struct libscols_table *table = NULL;
355 struct libscols_iter *s_itr = NULL;
8c3a5a44 356 char *res = NULL;
8903f7df 357 size_t i;
45333e9d 358 int tree = 0;
baa3b270 359 struct libscols_line *ln, *ln_cont = NULL;
8c3a5a44 360
14620822 361 DBG(TABLE, ul_debug("convert to string"));
8c3a5a44
KZ
362
363 assert(cf);
364 assert(cf->cxt);
bd85d11f 365 assert(cf->fields);
8c3a5a44
KZ
366 assert(tb);
367
6a632136 368 lb = fdisk_get_label(cf->cxt, NULL);
8c3a5a44
KZ
369 assert(lb);
370
8c3a5a44
KZ
371 itr = fdisk_new_iter(FDISK_ITER_FORWARD);
372 if (!itr)
373 goto done;
5c36a0eb 374
45333e9d
KZ
375 /* get container (e.g. extended partition) */
376 while (fdisk_table_next_partition(tb, itr, &pa) == 0) {
377 if (fdisk_partition_is_nested(pa)) {
14620822 378 DBG(TABLE, ul_debug("nested detected, using tree"));
baa3b270 379 tree = SCOLS_FL_TREE;
45333e9d
KZ
380 break;
381 }
382 }
45333e9d 383
0925a9dd 384 table = scols_new_table();
baa3b270 385 if (!table)
45333e9d 386 goto done;
0925a9dd 387 scols_table_enable_maxout(table, 1);
717fff86 388 scols_table_enable_nowrap(table, 1);
45333e9d 389
9907a95a
KZ
390#if !defined(HAVE_LIBNCURSESW) || !defined(HAVE_WIDECHAR)
391 scols_table_enable_ascii(table, 1);
392#endif
393
8c3a5a44 394 /* headers */
bd85d11f
KZ
395 for (i = 0; i < cf->nfields; i++) {
396 int fl = 0;
397 const struct fdisk_field *field =
398 fdisk_label_get_field(lb, cf->fields[i]);
399 if (!field)
400 continue;
401
402 if (fdisk_field_is_number(field))
403 fl |= SCOLS_FL_RIGHT;
404 if (fdisk_field_get_id(field) == FDISK_FIELD_TYPE)
405 fl |= SCOLS_FL_TRUNC;
406 if (tree && fdisk_field_get_id(field) == FDISK_FIELD_DEVICE)
407 fl |= SCOLS_FL_TREE;
408
409 if (!scols_table_new_column(table,
b6e3c614 410 _(fdisk_field_get_name(field)),
bd85d11f
KZ
411 fdisk_field_get_width(field), fl))
412 goto done;
8c3a5a44
KZ
413 }
414
415 /* data */
8903f7df
KZ
416 fdisk_reset_iter(itr, FDISK_ITER_FORWARD);
417
8c3a5a44 418 while (fdisk_table_next_partition(tb, itr, &pa) == 0) {
baa3b270 419 struct libscols_line *parent = fdisk_partition_is_nested(pa) ? ln_cont : NULL;
8903f7df 420
baa3b270 421 ln = scols_table_new_line(table, parent);
8c3a5a44
KZ
422 if (!ln)
423 goto done;
bd85d11f 424 for (i = 0; i < cf->nfields; i++) {
8c3a5a44 425 char *cdata = NULL;
bd85d11f 426
d44115f3 427 if (fdisk_partition_to_string(pa, cf->cxt,
bd85d11f 428 cf->fields[i], &cdata))
8c3a5a44 429 continue;
c743bf74 430 scols_line_refer_data(ln, i, cdata);
8c3a5a44 431 }
8903f7df 432 if (tree && fdisk_partition_is_container(pa))
45333e9d 433 ln_cont = ln;
d051ea93 434
baa3b270 435 scols_line_set_userdata(ln, (void *) pa);
d051ea93 436 fdisk_ref_partition(pa);
8c3a5a44 437 }
6dbe3af9 438
baa3b270 439 if (scols_table_is_empty(table))
d051ea93
KZ
440 goto done;
441
baa3b270
OO
442 scols_table_reduce_termwidth(table, ARROW_CURSOR_WIDTH);
443 scols_print_table_to_string(table, &res);
d051ea93 444
baa3b270 445 /* scols_* code might reorder lines, let's reorder @tb according to the
d051ea93
KZ
446 * final output (it's no problem because partitions are addressed by
447 * parno stored within struct fdisk_partition) */
448
449 /* remove all */
49e1a333 450 fdisk_reset_table(tb);
d051ea93 451
baa3b270
OO
452 s_itr = scols_new_iter(SCOLS_ITER_FORWARD);
453 if (!s_itr)
454 goto done;
455
c743bf74 456 /* add all in the right order (don't forget the output is tree) */
baa3b270 457 while (scols_table_next_line(table, s_itr, &ln) == 0) {
c743bf74
KZ
458 if (scols_line_get_parent(ln))
459 continue;
460 if (partition_from_scols(tb, ln))
461 break;
8c3a5a44
KZ
462 }
463done:
baa3b270
OO
464 scols_unref_table(table);
465 scols_free_iter(s_itr);
8c3a5a44 466 fdisk_free_iter(itr);
6dbe3af9 467
8c3a5a44 468 return res;
2b6fc908
KZ
469}
470
dda7fe12
OO
471static void cfdisk_free_lines(struct cfdisk *cf)
472{
473 size_t i = 0;
474 while(i < cf->nlines) {
475 scols_unref_table(cf->lines[i].extra);
476
477 DBG(UI, ul_debug("delete window: %p",
478 cf->lines[i].w));
479
a2d0dbb4
KZ
480 if (cf->lines[i].w)
481 delwin(cf->lines[i].w);
482 cf->lines[i].w = NULL;
dda7fe12
OO
483 ++i;
484 }
485 cf->act_win = NULL;
486 free(cf->lines);
a2d0dbb4 487 cf->lines = NULL;
dda7fe12 488}
88942179
KZ
489/*
490 * Read data about partitions from libfdisk and prepare output lines.
491 */
8460875d 492static int lines_refresh(struct cfdisk *cf)
8c3a5a44
KZ
493{
494 int rc;
495 char *p;
496 size_t i;
7eda085c 497
8c3a5a44 498 assert(cf);
2b6fc908 499
14620822 500 DBG(TABLE, ul_debug("refreshing buffer"));
c64061c9 501
8c3a5a44 502 free(cf->linesbuf);
dda7fe12 503 cfdisk_free_lines(cf);
8c3a5a44
KZ
504 cf->linesbuf = NULL;
505 cf->linesbufsz = 0;
506 cf->lines = NULL;
507 cf->nlines = 0;
6dbe3af9 508
8c3a5a44 509 fdisk_unref_table(cf->table);
1af8003b 510 cf->table = NULL;
6dbe3af9 511
2cec7949
KZ
512 /* read partitions and free spaces into cf->table */
513 rc = fdisk_get_partitions(cf->cxt, &cf->table);
514 if (!rc)
515 rc = fdisk_get_freespaces(cf->cxt, &cf->table);
8c3a5a44
KZ
516 if (rc)
517 return rc;
0d8589c5 518
8c3a5a44
KZ
519 cf->linesbuf = table_to_string(cf, cf->table);
520 if (!cf->linesbuf)
521 return -ENOMEM;
6dbe3af9 522
8c3a5a44
KZ
523 cf->linesbufsz = strlen(cf->linesbuf);
524 cf->nlines = fdisk_table_get_nents(cf->table) + 1; /* 1 for header line */
a6f69126 525 cf->page_sz = 0;
d5314bf5 526 cf->wrong_order = fdisk_table_wrong_order(cf->table) ? 1 : 0;
a6f69126
KZ
527
528 if (MENU_START_LINE - TABLE_START_LINE < cf->nlines)
529 cf->page_sz = MENU_START_LINE - TABLE_START_LINE - 1;
6dbe3af9 530
dda7fe12 531 cf->lines = xcalloc(cf->nlines, sizeof(struct cfdisk_line));
6dbe3af9 532
8c3a5a44 533 for (p = cf->linesbuf, i = 0; p && i < cf->nlines; i++) {
86688c37
KZ
534 cf->lines[i].data = p;
535 p = strchr(p, '\n');
8c3a5a44
KZ
536 if (p) {
537 *p = '\0';
538 p++;
539 }
dda7fe12
OO
540 cf->lines[i].extra = scols_new_table();
541 scols_table_enable_noheadings(cf->lines[i].extra, 1);
542 scols_table_new_column(cf->lines[i].extra, NULL, 0, SCOLS_FL_RIGHT);
543 scols_table_new_column(cf->lines[i].extra, NULL, 0, SCOLS_FL_TRUNC);
8c3a5a44 544 }
6dbe3af9 545
8c3a5a44 546 return 0;
6dbe3af9
KZ
547}
548
00b4f26a
KZ
549static struct fdisk_partition *get_current_partition(struct cfdisk *cf)
550{
551 assert(cf);
552 assert(cf->table);
553
554 return fdisk_table_get_partition(cf->table, cf->lines_idx);
555}
556
45333e9d
KZ
557static int is_freespace(struct cfdisk *cf, size_t i)
558{
559 struct fdisk_partition *pa;
560
561 assert(cf);
562 assert(cf->table);
563
564 pa = fdisk_table_get_partition(cf->table, i);
565 return fdisk_partition_is_freespace(pa);
566}
567
b1f58330 568/* converts libfdisk FDISK_ASKTYPE_MENU to cfdisk menu and returns user's
9e930041 569 * response back to libfdisk
b1f58330
KZ
570 */
571static int ask_menu(struct fdisk_ask *ask, struct cfdisk *cf)
572{
3b411726 573 struct cfdisk_menuitem *d, *cm;
b1f58330
KZ
574 int key;
575 size_t i = 0, nitems;
576 const char *name, *desc;
577
578 assert(ask);
579 assert(cf);
580
581 /* create cfdisk menu according to libfdisk ask-menu, note that the
582 * last cm[] item has to be empty -- so nitems + 1 */
583 nitems = fdisk_ask_menu_get_nitems(ask);
3b411726 584 cm = xcalloc(nitems + 1, sizeof(struct cfdisk_menuitem));
b1f58330
KZ
585
586 for (i = 0; i < nitems; i++) {
587 if (fdisk_ask_menu_get_item(ask, i, &key, &name, &desc))
588 break;
589 cm[i].key = key;
590 cm[i].desc = desc;
591 cm[i].name = name;
592 }
593
594 /* make the new menu active */
63128bbf 595 menu_push(cf, cm);
b1f58330
KZ
596 ui_draw_menu(cf);
597 refresh();
598
599 /* wait for keys */
502c5186 600 while (!sig_die) {
7ee26cbf 601 key = getch();
ac27ea5c 602
502c5186
KZ
603 if (sig_die)
604 break;
c431d901 605 if (sig_resize)
7556c944 606 ui_menu_resize(cf);
ac27ea5c
KZ
607 if (ui_menu_move(cf, key) == 0)
608 continue;
609
610 switch (key) {
b1f58330
KZ
611 case KEY_ENTER:
612 case '\n':
613 case '\r':
6fed9601 614 d = menu_get_menuitem(cf, cf->menu->idx);
b1f58330
KZ
615 if (d)
616 fdisk_ask_menu_set_result(ask, d->key);
617 menu_pop(cf);
618 free(cm);
619 return 0;
620 }
502c5186
KZ
621 }
622
623 if (sig_die)
624 die_on_signal();
b1f58330
KZ
625
626 menu_pop(cf);
627 free(cm);
628 return -1;
629}
630
88942179
KZ
631/* libfdisk callback
632 */
ffab025d
KZ
633static int ask_callback(struct fdisk_context *cxt __attribute__((__unused__)),
634 struct fdisk_ask *ask,
635 void *data __attribute__((__unused__)))
8c3a5a44
KZ
636{
637 int rc = 0;
6dbe3af9 638
8c3a5a44 639 assert(ask);
6dbe3af9 640
8c3a5a44
KZ
641 switch(fdisk_ask_get_type(ask)) {
642 case FDISK_ASKTYPE_INFO:
fbae1442 643 ui_info("%s", fdisk_ask_print_get_mesg(ask));
8c3a5a44
KZ
644 break;
645 case FDISK_ASKTYPE_WARNX:
fbae1442 646 ui_warnx("%s", fdisk_ask_print_get_mesg(ask));
8c3a5a44
KZ
647 break;
648 case FDISK_ASKTYPE_WARN:
fbae1442 649 ui_warn("%s", fdisk_ask_print_get_mesg(ask));
8c3a5a44 650 break;
b1f58330
KZ
651 case FDISK_ASKTYPE_MENU:
652 ask_menu(ask, (struct cfdisk *) data);
653 break;
8c3a5a44 654 default:
83fa0f80
KZ
655 ui_warnx(_("internal error: unsupported dialog type %d"),
656 fdisk_ask_get_type(ask));
8c3a5a44
KZ
657 return -EINVAL;
658 }
659 return rc;
fd6b7a7f 660}
6dbe3af9 661
7aa0d529 662static int ui_end(void)
8c3a5a44 663{
7aa0d529 664 if (!ui_enabled)
8c3a5a44
KZ
665 return -EINVAL;
666
48d7b13a 667#if defined(HAVE_SLCURSES_H) || defined(HAVE_SLANG_SLCURSES_H)
eef63970 668 SLsmg_gotorc(ui_lines - 1, 0);
8c3a5a44 669 SLsmg_refresh();
2b6fc908 670#else
eef63970 671 mvcur(0, ui_cols - 1, ui_lines-1, 0);
2b6fc908 672#endif
cd8414f7 673 curs_set(1);
8c3a5a44
KZ
674 nl();
675 endwin();
676 printf("\n");
7aa0d529 677 ui_enabled = 0;
8c3a5a44 678 return 0;
6dbe3af9
KZ
679}
680
fbae1442
KZ
681static void __attribute__((__format__ (__printf__, 3, 0)))
682 ui_vprint_center(size_t line, int attrs, const char *fmt, va_list ap)
f609e92e 683{
8c3a5a44 684 size_t width;
8c3a5a44 685 char *buf = NULL;
f609e92e 686
8c3a5a44
KZ
687 move(line, 0);
688 clrtoeol();
f609e92e 689
8c3a5a44 690 xvasprintf(&buf, fmt, ap);
fd6b7a7f 691
b1f58330 692 width = mbs_safe_width(buf);
eef63970
KZ
693 if (width > (size_t) ui_cols) {
694 char *p = strrchr(buf + ui_cols, ' ');
91ba41ca 695 if (!p)
eef63970 696 p = buf + ui_cols;
91ba41ca 697 *p = '\0';
eef63970 698 if (line + 1 >= ui_lines)
91ba41ca
KZ
699 line--;
700 attron(attrs);
701 mvaddstr(line, 0, buf);
702 mvaddstr(line + 1, 0, p+1);
703 attroff(attrs);
704 } else {
705 attron(attrs);
eef63970 706 mvaddstr(line, (ui_cols - width) / 2, buf);
91ba41ca
KZ
707 attroff(attrs);
708 }
8c3a5a44 709 free(buf);
6dbe3af9
KZ
710}
711
fbae1442
KZ
712static void __attribute__((__format__ (__printf__, 2, 3)))
713 ui_center(size_t line, const char *fmt, ...)
1af8003b
KZ
714{
715 va_list ap;
716 va_start(ap, fmt);
717 ui_vprint_center(line, 0, fmt, ap);
718 va_end(ap);
719}
720
fbae1442
KZ
721static void __attribute__((__format__ (__printf__, 1, 2)))
722 ui_warnx(const char *fmt, ...)
83fa0f80
KZ
723{
724 va_list ap;
725 va_start(ap, fmt);
726 if (ui_enabled)
702d0e1c 727 ui_vprint_center(WARN_LINE,
f1512be8
KZ
728 colors_wanted() ? COLOR_PAIR(CFDISK_CL_WARNING) : 0,
729 fmt, ap);
8fc37981 730 else {
83fa0f80 731 vfprintf(stderr, fmt, ap);
8fc37981
KZ
732 fputc('\n', stderr);
733 }
83fa0f80
KZ
734 va_end(ap);
735}
736
fbae1442
KZ
737static void __attribute__((__format__ (__printf__, 1, 2)))
738 ui_warn(const char *fmt, ...)
1af8003b 739{
83fa0f80 740 char *fmt_m;
1af8003b 741 va_list ap;
83fa0f80
KZ
742
743 xasprintf(&fmt_m, "%s: %m", fmt);
744
1af8003b 745 va_start(ap, fmt);
83fa0f80 746 if (ui_enabled)
702d0e1c 747 ui_vprint_center(WARN_LINE,
f1512be8
KZ
748 colors_wanted() ? COLOR_PAIR(CFDISK_CL_WARNING) : 0,
749 fmt_m, ap);
8fc37981 750 else {
83fa0f80 751 vfprintf(stderr, fmt_m, ap);
8fc37981
KZ
752 fputc('\n', stderr);
753 }
1af8003b 754 va_end(ap);
83fa0f80 755 free(fmt_m);
1af8003b
KZ
756}
757
29e9b787
KZ
758static void ui_clean_warn(void)
759{
760 move(WARN_LINE, 0);
761 clrtoeol();
762}
763
fbae1442
KZ
764static int __attribute__((__noreturn__))
765 __attribute__((__format__ (__printf__, 2, 3)))
766 ui_err(int rc, const char *fmt, ...)
767{
134b6296
KZ
768 va_list ap;
769 ui_end();
770
771 va_start(ap, fmt);
772 fprintf(stderr, "%s: ", program_invocation_short_name);
773 vfprintf(stderr, fmt, ap);
774 fprintf(stderr, ": %s\n", strerror(errno));
775 va_end(ap);
776
777 exit(rc);
778}
779
fbae1442
KZ
780static int __attribute__((__noreturn__))
781 __attribute__((__format__ (__printf__, 2, 3)))
782 ui_errx(int rc, const char *fmt, ...)
7aa0d529
KZ
783 {
784 va_list ap;
785 ui_end();
786
787 va_start(ap, fmt);
788 fprintf(stderr, "%s: ", program_invocation_short_name);
789 vfprintf(stderr, fmt, ap);
8fc37981 790 fputc('\n', stderr);
7aa0d529
KZ
791 va_end(ap);
792
793 exit(rc);
794}
795
fbae1442
KZ
796static void __attribute__((__format__ (__printf__, 1, 2)))
797 ui_info(const char *fmt, ...)
1af8003b
KZ
798{
799 va_list ap;
800 va_start(ap, fmt);
83fa0f80 801 if (ui_enabled)
f9fb8290
KZ
802 ui_vprint_center(INFO_LINE,
803 colors_wanted() ? COLOR_PAIR(CFDISK_CL_INFO) : 0,
804 fmt, ap);
8fc37981 805 else {
83fa0f80 806 vfprintf(stdout, fmt, ap);
8fc37981
KZ
807 fputc('\n', stdout);
808 }
1af8003b
KZ
809 va_end(ap);
810}
811
812static void ui_clean_info(void)
813{
814 move(INFO_LINE, 0);
815 clrtoeol();
816}
6dbe3af9 817
fbae1442
KZ
818static void __attribute__((__format__ (__printf__, 1, 2)))
819 ui_hint(const char *fmt, ...)
b1f58330
KZ
820{
821 va_list ap;
822 va_start(ap, fmt);
823 if (ui_enabled)
824 ui_vprint_center(HINT_LINE, A_BOLD, fmt, ap);
8fc37981 825 else {
b1f58330 826 vfprintf(stdout, fmt, ap);
8fc37981
KZ
827 fputc('\n', stdout);
828 }
b1f58330
KZ
829 va_end(ap);
830}
831
832static void ui_clean_hint(void)
833{
834 move(HINT_LINE, 0);
835 clrtoeol();
836}
837
502c5186
KZ
838
839static void sig_handler_die(int dummy __attribute__((__unused__)))
8c3a5a44 840{
502c5186 841 sig_die = 1;
6dbe3af9
KZ
842}
843
c431d901 844static void sig_handler_resize(int dummy __attribute__((__unused__)))
7556c944 845{
c431d901 846 sig_resize = 1;
7556c944
KZ
847}
848
849static void menu_refresh_size(struct cfdisk *cf)
850{
851 if (cf->menu && cf->menu->nitems)
eef63970 852 cf->menu->page_sz = (cf->menu->nitems / (ui_lines - 4)) ? ui_lines - 4 : 0;
7556c944
KZ
853}
854
8c3a5a44
KZ
855static void menu_update_ignore(struct cfdisk *cf)
856{
00b4f26a
KZ
857 char ignore[128] = { 0 };
858 int i = 0;
8c3a5a44 859 struct cfdisk_menu *m;
b5ef65a9 860 struct cfdisk_menuitem *d, *org = NULL;
83fa0f80 861 size_t idx;
6dbe3af9 862
8c3a5a44 863 assert(cf);
63128bbf
KZ
864 assert(cf->menu);
865 assert(cf->menu->ignore_cb);
6dbe3af9 866
8c3a5a44 867 m = cf->menu;
14620822 868 DBG(MENU, ul_debug("update menu ignored keys"));
6dbe3af9 869
63128bbf 870 i = m->ignore_cb(cf, ignore, sizeof(ignore));
00b4f26a
KZ
871 ignore[i] = '\0';
872
8c3a5a44 873 /* return if no change */
b5ef65a9 874 if ((!m->ignore && !*ignore)
00b4f26a 875 || (m->ignore && *ignore && strcmp(m->ignore, ignore) == 0)) {
8c3a5a44 876 return;
fd6b7a7f 877 }
6dbe3af9 878
b5ef65a9
KZ
879 if (!m->prefkey)
880 org = menu_get_menuitem(cf, m->idx);
881
8c3a5a44 882 free(m->ignore);
8460875d 883 m->ignore = xstrdup(ignore);
8c3a5a44 884 m->nitems = 0;
6dbe3af9 885
3b411726 886 for (d = m->items; d->name; d++) {
8c3a5a44 887 if (m->ignore && strchr(m->ignore, d->key))
8460875d
KZ
888 continue;
889 m->nitems++;
8c3a5a44 890 }
83fa0f80 891
b5ef65a9
KZ
892 DBG(MENU, ul_debug("update menu preferred keys"));
893
83fa0f80
KZ
894 /* refresh menu index to be at the same menuitem or go to the first */
895 if (org && menu_get_menuitem_by_key(cf, org->key, &idx))
6fed9601 896 m->idx = idx;
b5ef65a9
KZ
897 else if (m->prefkey && menu_get_menuitem_by_key(cf, m->prefkey, &idx))
898 m->idx = idx;
83fa0f80 899 else
6fed9601
KZ
900 m->idx = 0;
901
7556c944 902 menu_refresh_size(cf);
6dbe3af9
KZ
903}
904
b1f58330
KZ
905static struct cfdisk_menu *menu_push(
906 struct cfdisk *cf,
3b411726 907 struct cfdisk_menuitem *items)
8c3a5a44
KZ
908{
909 struct cfdisk_menu *m = xcalloc(1, sizeof(*m));
3b411726 910 struct cfdisk_menuitem *d;
6dbe3af9 911
8c3a5a44 912 assert(cf);
6dbe3af9 913
14620822 914 DBG(MENU, ul_debug("new menu"));
6dbe3af9 915
8c3a5a44 916 m->prev = cf->menu;
3b411726 917 m->items = items;
6dbe3af9 918
3b411726 919 for (d = m->items; d->name; d++) {
8c3a5a44 920 const char *name = _(d->name);
b1f58330 921 size_t len = mbs_safe_width(name);
8c3a5a44
KZ
922 if (len > m->width)
923 m->width = len;
924 m->nitems++;
925 }
6dbe3af9 926
8c3a5a44 927 cf->menu = m;
b5ef65a9 928
7556c944 929 menu_refresh_size(cf);
8c3a5a44 930 return m;
6dbe3af9
KZ
931}
932
8c3a5a44 933static struct cfdisk_menu *menu_pop(struct cfdisk *cf)
6dbe3af9 934{
8c3a5a44 935 struct cfdisk_menu *m = NULL;
6dbe3af9 936
8c3a5a44 937 assert(cf);
7eda085c 938
14620822 939 DBG(MENU, ul_debug("pop menu"));
7eda085c 940
8c3a5a44
KZ
941 if (cf->menu) {
942 m = cf->menu->prev;
943 free(cf->menu->ignore);
8a726114 944 free(cf->menu->title);
8c3a5a44 945 free(cf->menu);
c07ebfa1 946 }
8c3a5a44
KZ
947 cf->menu = m;
948 return cf->menu;
6dbe3af9
KZ
949}
950
8a726114
KZ
951static void menu_set_title(struct cfdisk_menu *m, const char *title)
952{
953 char *str = NULL;
954
955 if (title) {
956 size_t len = mbs_safe_width(title);
5c04b408
KZ
957 if (len + MENU_TITLE_PADDING > m->width)
958 m->width = len + MENU_TITLE_PADDING;
8a726114
KZ
959 str = xstrdup(title);
960 }
961 m->title = str;
962}
963
964
b1f58330 965static int ui_init(struct cfdisk *cf __attribute__((__unused__)))
8c3a5a44
KZ
966{
967 struct sigaction sa;
6dbe3af9 968
14620822 969 DBG(UI, ul_debug("init"));
6dbe3af9 970
8c3a5a44
KZ
971 /* setup SIGCHLD handler */
972 sigemptyset(&sa.sa_mask);
973 sa.sa_flags = 0;
502c5186 974 sa.sa_handler = sig_handler_die;
8c3a5a44
KZ
975 sigaction(SIGINT, &sa, NULL);
976 sigaction(SIGTERM, &sa, NULL);
6dbe3af9 977
c431d901 978 sa.sa_handler = sig_handler_resize;
7556c944
KZ
979 sigaction(SIGWINCH, &sa, NULL);
980
83fa0f80 981 ui_enabled = 1;
8c3a5a44 982 initscr();
6dbe3af9 983
f1512be8 984#ifdef HAVE_USE_DEFAULT_COLORS
04915c3f 985 if (colors_wanted() && has_colors()) {
1af8003b
KZ
986 size_t i;
987
988 start_color();
989 use_default_colors();
1af8003b
KZ
990 for (i = 1; i < ARRAY_SIZE(color_pairs); i++) /* yeah, start from 1! */
991 init_pair(i, color_pairs[i][0], color_pairs[i][1]);
992 }
f1512be8 993#else
e66a6627 994 colors_off();
f1512be8 995#endif
1af8003b 996
8c3a5a44
KZ
997 cbreak();
998 noecho();
999 nonl();
1000 curs_set(0);
1001 keypad(stdscr, TRUE);
6dbe3af9 1002
8c3a5a44 1003 return 0;
7eda085c
KZ
1004}
1005
5c04b408
KZ
1006/* "[ string ]" */
1007#define MENU_H_ITEMWIDTH(m) ( MENU_H_PRESTR_SZ \
1008 + MENU_H_SPADDING \
1009 + (m)->width \
1010 + MENU_H_SPADDING \
1011 + MENU_H_POSTSTR_SZ)
1012
1013#define MENU_V_ITEMWIDTH(m) (MENU_V_SPADDING + (m)->width + MENU_V_SPADDING)
1014
1015
8c3a5a44
KZ
1016static size_t menuitem_get_line(struct cfdisk *cf, size_t idx)
1017{
6fed9601
KZ
1018 struct cfdisk_menu *m = cf->menu;
1019
1020 if (m->vertical) {
1021 if (!m->page_sz) /* small menu */
eef63970 1022 return (ui_lines - (cf->menu->nitems + 1)) / 2 + idx;
6fed9601 1023 return (idx % m->page_sz) + 1;
042f62df
RP
1024 }
1025
1026 {
5c04b408 1027 size_t len = MENU_H_ITEMWIDTH(m) + MENU_H_BETWEEN; /** item width */
eef63970 1028 size_t items = ui_cols / len; /* items per line */
8a726114 1029
a1da27a8
KZ
1030 if (items == 0)
1031 return 0;
8a726114
KZ
1032 return MENU_START_LINE + ((idx / items));
1033 }
7eda085c
KZ
1034}
1035
8c3a5a44
KZ
1036static int menuitem_get_column(struct cfdisk *cf, size_t idx)
1037{
8a726114 1038 if (cf->menu->vertical) {
5c04b408 1039 size_t nc = MENU_V_ITEMWIDTH(cf->menu);
eef63970 1040 if ((size_t) ui_cols <= nc)
7aa0d529 1041 return 0;
eef63970 1042 return (ui_cols - nc) / 2;
042f62df
RP
1043 }
1044
1045 {
5c04b408 1046 size_t len = MENU_H_ITEMWIDTH(cf->menu) + MENU_H_BETWEEN; /* item width */
eef63970 1047 size_t items = ui_cols / len; /* items per line */
8a726114 1048 size_t extra = items < cf->menu->nitems ? /* extra space on line */
eef63970
KZ
1049 ui_cols % len : /* - multi-line menu */
1050 ui_cols - (cf->menu->nitems * len); /* - one line menu */
8a726114 1051
a1da27a8
KZ
1052 if (items == 0)
1053 return 0; /* hmm... no space */
1054
5c04b408 1055 extra += MENU_H_BETWEEN; /* add padding after last item to extra */
e66ac5d3 1056
8a726114
KZ
1057 if (idx < items)
1058 return (idx * len) + (extra / 2);
1059 return ((idx % items) * len) + (extra / 2);
1060 }
df1dddf9
KZ
1061}
1062
6fed9601
KZ
1063static int menuitem_on_page(struct cfdisk *cf, size_t idx)
1064{
1065 struct cfdisk_menu *m = cf->menu;
1066
1067 if (m->page_sz == 0 ||
1068 m->idx / m->page_sz == idx / m->page_sz)
1069 return 1;
1070 return 0;
1071}
1072
3b411726 1073static struct cfdisk_menuitem *menu_get_menuitem(struct cfdisk *cf, size_t idx)
8c3a5a44 1074{
3b411726 1075 struct cfdisk_menuitem *d;
8c3a5a44 1076 size_t i;
7eda085c 1077
3b411726 1078 for (i = 0, d = cf->menu->items; d->name; d++) {
8c3a5a44
KZ
1079 if (cf->menu->ignore && strchr(cf->menu->ignore, d->key))
1080 continue;
1081 if (i++ == idx)
1082 return d;
d26aa358 1083 }
7eda085c 1084
8c3a5a44 1085 return NULL;
6dbe3af9
KZ
1086}
1087
3b411726 1088static struct cfdisk_menuitem *menu_get_menuitem_by_key(struct cfdisk *cf,
83fa0f80
KZ
1089 int key, size_t *idx)
1090{
3b411726 1091 struct cfdisk_menuitem *d;
83fa0f80 1092
3b411726 1093 for (*idx = 0, d = cf->menu->items; d->name; d++) {
83fa0f80
KZ
1094 if (cf->menu->ignore && strchr(cf->menu->ignore, d->key))
1095 continue;
1096 if (key == d->key)
1097 return d;
1098 (*idx)++;
1099 }
1100
1101 return NULL;
1102}
1103
8c3a5a44 1104static void ui_draw_menuitem(struct cfdisk *cf,
3b411726 1105 struct cfdisk_menuitem *d,
8c3a5a44
KZ
1106 size_t idx)
1107{
e948f4b6 1108 char *buf, *ptr;
8c3a5a44 1109 const char *name;
5c04b408 1110 size_t width;
e948f4b6 1111 const size_t buf_sz = 80 * MB_CUR_MAX;
8a726114 1112 int ln, cl, vert = cf->menu->vertical;
8c3a5a44 1113
6fed9601
KZ
1114 if (!menuitem_on_page(cf, idx))
1115 return; /* no visible item */
1116 ln = menuitem_get_line(cf, idx);
1117 cl = menuitem_get_column(cf, idx);
1118
e948f4b6 1119 ptr = buf = xmalloc(buf_sz);
5c04b408
KZ
1120 /* string width */
1121 if (vert) {
1122 width = cf->menu->width + MENU_V_SPADDING;
1123 memset(ptr, ' ', MENU_V_SPADDING);
1124 ptr += MENU_V_SPADDING;
1125 } else
1126 width = MENU_H_SPADDING + cf->menu->width + MENU_H_SPADDING;
1127
8c3a5a44 1128 name = _(d->name);
e948f4b6 1129 mbsalign(name, ptr, buf_sz, &width,
8a726114
KZ
1130 vert ? MBS_ALIGN_LEFT : MBS_ALIGN_CENTER,
1131 0);
8c3a5a44 1132
14620822 1133 DBG(MENU, ul_debug("menuitem: cl=%d, ln=%d, item='%s'",
8c3a5a44
KZ
1134 cl, ln, buf));
1135
8a726114
KZ
1136 if (vert) {
1137 mvaddch(ln, cl - 1, ACS_VLINE);
5c04b408 1138 mvaddch(ln, cl + MENU_V_ITEMWIDTH(cf->menu), ACS_VLINE);
8a726114
KZ
1139 }
1140
5c04b408 1141 if (cf->menu->idx == idx)
8c3a5a44 1142 standout();
5c04b408
KZ
1143
1144 if (vert)
1145 mvprintw(ln, cl, "%s", buf);
1146 else
1147 mvprintw(ln, cl, "%s%s%s", MENU_H_PRESTR, buf, MENU_H_POSTSTR);
e948f4b6 1148 free(buf);
5c04b408
KZ
1149
1150 if (cf->menu->idx == idx) {
8c3a5a44
KZ
1151 standend();
1152 if (d->desc)
fbae1442 1153 ui_hint("%s", _(d->desc));
5c04b408 1154 }
6dbe3af9
KZ
1155}
1156
7556c944
KZ
1157static void ui_clean_menu(struct cfdisk *cf)
1158{
1159 size_t i;
702d0e1c 1160 size_t lastline;
7556c944
KZ
1161 struct cfdisk_menu *m = cf->menu;
1162 size_t ln = menuitem_get_line(cf, 0);
1163
1164 if (m->vertical)
702d0e1c 1165 lastline = ln + (m->page_sz ? m->page_sz : m->nitems);
7556c944 1166 else
702d0e1c 1167 lastline = menuitem_get_line(cf, m->nitems);
7556c944 1168
702d0e1c 1169 for (i = ln; i <= lastline; i++) {
7556c944
KZ
1170 move(i, 0);
1171 clrtoeol();
702d0e1c 1172 DBG(MENU, ul_debug("clean_menu: line %zu", i));
7556c944
KZ
1173 }
1174 if (m->vertical) {
1175 move(ln - 1, 0);
1176 clrtoeol();
1177 }
1178 ui_clean_hint();
1179}
1180
8c3a5a44
KZ
1181static void ui_draw_menu(struct cfdisk *cf)
1182{
3b411726 1183 struct cfdisk_menuitem *d;
8a726114 1184 struct cfdisk_menu *m;
6fed9601
KZ
1185 size_t i = 0;
1186 size_t ln = menuitem_get_line(cf, 0);
1187 size_t nlines;
7eda085c 1188
8c3a5a44
KZ
1189 assert(cf);
1190 assert(cf->menu);
fd6b7a7f 1191
14620822 1192 DBG(MENU, ul_debug("draw start"));
6dbe3af9 1193
7556c944 1194 ui_clean_menu(cf);
8a726114
KZ
1195 m = cf->menu;
1196
6fed9601
KZ
1197 if (m->vertical)
1198 nlines = m->page_sz ? m->page_sz : m->nitems;
1199 else
1200 nlines = menuitem_get_line(cf, m->nitems);
1201
63128bbf
KZ
1202 if (m->ignore_cb)
1203 menu_update_ignore(cf);
00b4f26a 1204 i = 0;
8c3a5a44
KZ
1205 while ((d = menu_get_menuitem(cf, i)))
1206 ui_draw_menuitem(cf, d, i++);
6dbe3af9 1207
8a726114 1208 if (m->vertical) {
8a726114 1209 size_t cl = menuitem_get_column(cf, 0);
6fed9601 1210 size_t curpg = m->page_sz ? m->idx / m->page_sz : 0;
8a726114 1211
6fed9601 1212 /* corners and horizontal lines */
8a726114
KZ
1213 mvaddch(ln - 1, cl - 1, ACS_ULCORNER);
1214 mvaddch(ln + nlines, cl - 1, ACS_LLCORNER);
1215
5c04b408 1216 for (i = 0; i < MENU_V_ITEMWIDTH(m); i++) {
8a726114
KZ
1217 mvaddch(ln - 1, cl + i, ACS_HLINE);
1218 mvaddch(ln + nlines, cl + i, ACS_HLINE);
1219 }
6fed9601 1220
8a726114
KZ
1221 mvaddch(ln - 1, cl + i, ACS_URCORNER);
1222 mvaddch(ln + nlines, cl + i, ACS_LRCORNER);
1223
6fed9601
KZ
1224 /* draw also lines around empty lines on last page */
1225 if (m->page_sz &&
1226 m->nitems / m->page_sz == m->idx / m->page_sz) {
1227 for (i = m->nitems % m->page_sz + 1; i <= m->page_sz; i++) {
1228 mvaddch(i, cl - 1, ACS_VLINE);
5c04b408 1229 mvaddch(i, cl + MENU_V_ITEMWIDTH(m), ACS_VLINE);
6fed9601
KZ
1230 }
1231 }
8a726114
KZ
1232 if (m->title) {
1233 attron(A_BOLD);
1234 mvprintw(ln - 1, cl, " %s ", m->title);
1235 attroff(A_BOLD);
1236 }
6fed9601 1237 if (curpg != 0)
5c04b408 1238 mvaddch(ln - 1, cl + MENU_V_ITEMWIDTH(m) - 2, ACS_UARROW);
6fed9601 1239 if (m->page_sz && curpg < m->nitems / m->page_sz)
5c04b408 1240 mvaddch(ln + nlines, cl + MENU_V_ITEMWIDTH(m) - 2, ACS_DARROW);
8a726114
KZ
1241 }
1242
14620822 1243 DBG(MENU, ul_debug("draw end."));
6dbe3af9
KZ
1244}
1245
dda7fe12
OO
1246inline static int extra_insert_pair(struct cfdisk_line *l, const char *name, const char *data)
1247{
1248 struct libscols_line *lsl;
4c166c22 1249 int rc;
dda7fe12
OO
1250
1251 assert(l);
a2d0dbb4 1252 assert(l->extra);
dda7fe12 1253
13c551f2 1254 if (!data || !*data)
dda7fe12
OO
1255 return 0;
1256
1257 lsl = scols_table_new_line(l->extra, NULL);
1258 if (!lsl)
1259 return -ENOMEM;
1260
4c166c22
KZ
1261 rc = scols_line_set_data(lsl, 0, name);
1262 if (!rc)
1263 rc = scols_line_set_data(lsl, 1, data);
dda7fe12 1264
4c166c22 1265 return rc;
dda7fe12
OO
1266}
1267
cf9b302d
KZ
1268#ifndef HAVE_LIBMOUNT
1269static char *get_mountpoint( struct cfdisk *cf __attribute__((unused)),
1270 const char *tagname __attribute__((unused)),
1271 const char *tagdata __attribute__((unused)))
1272{
1273 return NULL;
1274}
1275#else
1276static char *get_mountpoint(struct cfdisk *cf, const char *tagname, const char *tagdata)
dda7fe12
OO
1277{
1278 struct libmnt_fs *fs = NULL;
1279 char *target = NULL;
1280 int mounted = 0;
1281
cf9b302d
KZ
1282 assert(tagname);
1283 assert(tagdata);
dda7fe12 1284
cf9b302d 1285 DBG(UI, ul_debug("asking for mountpoint [%s=%s]", tagname, tagdata));
dda7fe12
OO
1286
1287 if (!cf->mntcache)
1288 cf->mntcache = mnt_new_cache();
1289
1290 /* 1st try between mounted filesystems */
1291 if (!cf->mtab) {
1292 cf->mtab = mnt_new_table();
1293 if (cf->mtab) {
1294 mnt_table_set_cache(cf->mtab, cf->mntcache);
1295 mnt_table_parse_mtab(cf->mtab, NULL);
1296 }
1297 }
1298
1299 if (cf->mtab)
cf9b302d 1300 fs = mnt_table_find_tag(cf->mtab, tagname, tagdata, MNT_ITER_FORWARD);
dda7fe12
OO
1301
1302 /* 2nd try fstab */
1303 if (!fs) {
1304 if (!cf->fstab) {
1305 cf->fstab = mnt_new_table();
1306 if (cf->fstab) {
1307 mnt_table_set_cache(cf->fstab, cf->mntcache);
a8955bf0
KZ
1308 if (mnt_table_parse_fstab(cf->fstab, NULL) != 0) {
1309 mnt_unref_table(cf->fstab);
1310 cf->fstab = NULL;
1311 }
dda7fe12
OO
1312 }
1313 }
1314 if (cf->fstab)
cf9b302d 1315 fs = mnt_table_find_tag(cf->fstab, tagname, tagdata, MNT_ITER_FORWARD);
dda7fe12
OO
1316 } else
1317 mounted = 1;
1318
1319 if (fs) {
1320 if (mounted)
1321 xasprintf(&target, _("%s (mounted)"), mnt_fs_get_target(fs));
1322 else
1323 target = xstrdup(mnt_fs_get_target(fs));
1324 }
1325
1326 return target;
1327}
1328#endif /* HAVE_LIBMOUNT */
1329
94a5b2e8
KZ
1330static inline int iszero(const char *str)
1331{
1332 const char *p;
1333
1334 for (p = str; p && *p == '0'; p++);
1335
1336 return !p || *p == '\0';
1337}
1338
5efc31f9
KZ
1339static int has_uuid(struct fdisk_table *tb, const char *uuid)
1340{
1341 struct fdisk_partition *pa;
1342 struct fdisk_iter *itr;
1343 int rc = 0;
1344
1345 if (!tb || !uuid || fdisk_table_is_empty(tb))
1346 return 0;
1347
1348 itr = fdisk_new_iter(FDISK_ITER_FORWARD);
1349 while (rc == 0 && fdisk_table_next_partition(tb, itr, &pa) == 0) {
1350 const char *x = fdisk_partition_get_uuid(pa);
1351 if (x)
1352 rc = strcmp(x, uuid) == 0;
1353 }
1354 fdisk_free_iter(itr);
1355 return rc;
1356}
1357
dda7fe12
OO
1358static void extra_prepare_data(struct cfdisk *cf)
1359{
1360 struct fdisk_partition *pa = get_current_partition(cf);
1361 struct cfdisk_line *l = &cf->lines[cf->lines_idx];
1362 char *data = NULL;
cf9b302d 1363 char *mountpoint = NULL;
dda7fe12
OO
1364
1365 DBG(UI, ul_debug("preparing extra data"));
1366
1367 /* string data should not equal an empty string */
1368 if (!fdisk_partition_to_string(pa, cf->cxt, FDISK_FIELD_NAME, &data) && data) {
1369 extra_insert_pair(l, _("Partition name:"), data);
cf9b302d
KZ
1370 if (!mountpoint)
1371 mountpoint = get_mountpoint(cf, "PARTLABEL", data);
dda7fe12
OO
1372 free(data);
1373 }
1374
1375 if (!fdisk_partition_to_string(pa, cf->cxt, FDISK_FIELD_UUID, &data) && data) {
1376 extra_insert_pair(l, _("Partition UUID:"), data);
5efc31f9
KZ
1377
1378 /* Search for mountpoint by PARTUUID= means that we need to
1379 * check fstab and convert PARTUUID to the device name. This is
1380 * unnecessary and overkill for newly created partitions. Let's
1381 * check if the UUID already exist in the old layout, otherwise
1382 * ignore it.
1383 */
1384 if (!mountpoint && has_uuid(cf->original_layout, data))
cf9b302d 1385 mountpoint = get_mountpoint(cf, "PARTUUID", data);
dda7fe12
OO
1386 free(data);
1387 }
1388
1389 if (!fdisk_partition_to_string(pa, cf->cxt, FDISK_FIELD_TYPE, &data) && data) {
1390 char *code = NULL, *type = NULL;
1391
1392 fdisk_partition_to_string(pa, cf->cxt, FDISK_FIELD_TYPEID, &code);
1393 xasprintf(&type, "%s (%s)", data, code);
1394
1395 extra_insert_pair(l, _("Partition type:"), type);
1396 free(data);
1397 free(code);
1398 free(type);
1399 }
1400
1401 if (!fdisk_partition_to_string(pa, cf->cxt, FDISK_FIELD_ATTR, &data) && data) {
1402 extra_insert_pair(l, _("Attributes:"), data);
1403 free(data);
1404 }
1405
1406 /* for numeric data, only show non-zero rows */
1407 if (!fdisk_partition_to_string(pa, cf->cxt, FDISK_FIELD_BSIZE, &data) && data) {
94a5b2e8 1408 if (!iszero(data))
dda7fe12
OO
1409 extra_insert_pair(l, "BSIZE:", data);
1410 free(data);
1411 }
1412
1413 if (!fdisk_partition_to_string(pa, cf->cxt, FDISK_FIELD_CPG, &data) && data) {
94a5b2e8 1414 if (!iszero(data))
dda7fe12
OO
1415 extra_insert_pair(l, "CPG:", data);
1416 free(data);
1417 }
1418
1419 if (!fdisk_partition_to_string(pa, cf->cxt, FDISK_FIELD_FSIZE, &data) && data) {
94a5b2e8 1420 if (!iszero(data))
dda7fe12
OO
1421 extra_insert_pair(l, "FSIZE:", data);
1422 free(data);
1423 }
1424
3d6db3fd
KZ
1425 if (!fdisk_partition_to_string(pa, cf->cxt, FDISK_FIELD_FSUUID, &data) && data) {
1426 extra_insert_pair(l, _("Filesystem UUID:"), data);
cf9b302d
KZ
1427 if (!mountpoint)
1428 mountpoint = get_mountpoint(cf, "UUID", data);
3d6db3fd
KZ
1429 free(data);
1430 }
dda7fe12 1431
3d6db3fd
KZ
1432 if (!fdisk_partition_to_string(pa, cf->cxt, FDISK_FIELD_FSLABEL, &data) && data) {
1433 extra_insert_pair(l, _("Filesystem LABEL:"), data);
cf9b302d
KZ
1434 if (!mountpoint)
1435 mountpoint = get_mountpoint(cf, "LABEL", data);
3d6db3fd
KZ
1436 free(data);
1437 }
1438 if (!fdisk_partition_to_string(pa, cf->cxt, FDISK_FIELD_FSTYPE, &data) && data) {
1439 extra_insert_pair(l, _("Filesystem:"), data);
1440 free(data);
dda7fe12 1441 }
dda7fe12 1442
cf9b302d
KZ
1443 if (mountpoint) {
1444 extra_insert_pair(l, _("Mountpoint:"), mountpoint);
1445 free(mountpoint);
dda7fe12 1446 }
dda7fe12
OO
1447}
1448
dda7fe12
OO
1449static int ui_draw_extra(struct cfdisk *cf)
1450{
1451 WINDOW *win_ex;
1452 int wline = 1;
1453 struct cfdisk_line *ln = &cf->lines[cf->lines_idx];
1454 char *tbstr = NULL, *end;
1455 int win_ex_start_line, win_height, tblen;
1456 int ndatalines;
1457
3542fc51
KZ
1458 if (!cf->show_extra)
1459 return 0;
1460
1461 DBG(UI, ul_debug("draw extra"));
1462
a2d0dbb4
KZ
1463 assert(ln->extra);
1464
cbcafba2 1465 if (cf->act_win) {
3542fc51 1466 wclear(cf->act_win);
cbcafba2
KZ
1467 touchwin(stdscr);
1468 }
3542fc51 1469
a2d0dbb4 1470 if (scols_table_is_empty(ln->extra)) {
dda7fe12 1471 extra_prepare_data(cf);
a2d0dbb4
KZ
1472 if (scols_table_is_empty(ln->extra))
1473 return 0;
1474 }
dda7fe12
OO
1475
1476 ndatalines = fdisk_table_get_nents(cf->table) + 1;
1477
1478 /* nents + header + one free line */
1479 win_ex_start_line = TABLE_START_LINE + ndatalines;
1480 win_height = MENU_START_LINE - win_ex_start_line;
1481 tblen = scols_table_get_nlines(ln->extra);
1482
1483 /* we can't get a single line of data under the partlist*/
1484 if (win_height < 3)
1485 return 1;
1486
1487 /* number of data lines + 2 for top/bottom lines */
1488 win_height = win_height < tblen + 2 ? win_height : tblen + 2;
1489
1490 if ((size_t) win_ex_start_line + win_height + 1 < MENU_START_LINE)
1491 win_ex_start_line = MENU_START_LINE - win_height;
1492
3542fc51 1493 win_ex = subwin(stdscr, win_height, ui_cols - 2, win_ex_start_line, 1);
dda7fe12
OO
1494
1495 scols_table_reduce_termwidth(ln->extra, 4);
1496 scols_print_table_to_string(ln->extra, &tbstr);
1497
1498 end = tbstr;
1499 while ((end = strchr(end, '\n')))
1500 *end++ = '\0';
1501
1502 box(win_ex, 0, 0);
1503
1504 end = tbstr;
1505 while (--win_height > 1) {
1506 mvwaddstr(win_ex, wline++, 1 /* window column*/, tbstr);
1507 tbstr += strlen(tbstr) + 1;
1508 }
1509 free(end);
1510
a2d0dbb4
KZ
1511 if (ln->w)
1512 delwin(ln->w);
dda7fe12
OO
1513
1514 DBG(UI, ul_debug("draw window: %p", win_ex));
3542fc51 1515 touchwin(stdscr);
dda7fe12
OO
1516 wrefresh(win_ex);
1517
1518 cf->act_win = ln->w = win_ex;
1519 return 0;
1520}
1521
8c3a5a44
KZ
1522static void ui_menu_goto(struct cfdisk *cf, int where)
1523{
3b411726 1524 struct cfdisk_menuitem *d;
8c3a5a44
KZ
1525 size_t old;
1526
f019ce1f
KZ
1527 /* stop and begin/end for vertical menus */
1528 if (cf->menu->vertical) {
1529 if (where < 0)
1530 where = 0;
1531 else if (where > (int) cf->menu->nitems - 1)
1532 where = cf->menu->nitems - 1;
1533 } else {
1534 /* continue from begin/end */
1535 if (where < 0)
1536 where = cf->menu->nitems - 1;
1537 else if ((size_t) where > cf->menu->nitems - 1)
1538 where = 0;
1539 }
6fed9601 1540 if ((size_t) where == cf->menu->idx)
8c3a5a44 1541 return;
6dbe3af9 1542
1af8003b
KZ
1543 ui_clean_info();
1544
6fed9601
KZ
1545 old = cf->menu->idx;
1546 cf->menu->idx = where;
1547
1548 if (!menuitem_on_page(cf, old)) {
1549 ui_draw_menu(cf);
1550 return;
1551 }
6dbe3af9 1552
8c3a5a44
KZ
1553 d = menu_get_menuitem(cf, old);
1554 ui_draw_menuitem(cf, d, old);
6dbe3af9 1555
8c3a5a44
KZ
1556 d = menu_get_menuitem(cf, where);
1557 ui_draw_menuitem(cf, d, where);
dda7fe12 1558
6dbe3af9
KZ
1559}
1560
ac27ea5c
KZ
1561static int ui_menu_move(struct cfdisk *cf, int key)
1562{
f019ce1f
KZ
1563 struct cfdisk_menu *m;
1564
ac27ea5c
KZ
1565 assert(cf);
1566 assert(cf->menu);
1567
c71f5a56 1568 if (key == (int) ERR)
7556c944
KZ
1569 return 0; /* ignore errors */
1570
f019ce1f
KZ
1571 m = cf->menu;
1572
14620822 1573 DBG(MENU, ul_debug("menu move key >%c<.", key));
f019ce1f
KZ
1574
1575 if (m->vertical)
ac27ea5c
KZ
1576 {
1577 switch (key) {
1578 case KEY_DOWN:
1579 case '\016': /* ^N */
1580 case 'j': /* Vi-like alternative */
f019ce1f 1581 ui_menu_goto(cf, m->idx + 1);
ac27ea5c
KZ
1582 return 0;
1583 case KEY_UP:
1584 case '\020': /* ^P */
1585 case 'k': /* Vi-like alternative */
f019ce1f 1586 ui_menu_goto(cf, (int) m->idx - 1);
ac27ea5c 1587 return 0;
f019ce1f
KZ
1588 case KEY_PPAGE:
1589 if (m->page_sz) {
1590 ui_menu_goto(cf, (int) m->idx - m->page_sz);
1591 return 0;
1592 }
d02c2035 1593 /* fallthrough */
ac27ea5c
KZ
1594 case KEY_HOME:
1595 ui_menu_goto(cf, 0);
1596 return 0;
f019ce1f
KZ
1597 case KEY_NPAGE:
1598 if (m->page_sz) {
1599 ui_menu_goto(cf, m->idx + m->page_sz);
1600 return 0;
1601 }
d02c2035 1602 /* fallthrough */
ac27ea5c 1603 case KEY_END:
f019ce1f 1604 ui_menu_goto(cf, m->nitems);
ac27ea5c
KZ
1605 return 0;
1606 }
1607 } else {
1608 switch (key) {
1609 case KEY_RIGHT:
1610 case '\t':
f019ce1f 1611 ui_menu_goto(cf, m->idx + 1);
ac27ea5c
KZ
1612 return 0;
1613 case KEY_LEFT:
1614#ifdef KEY_BTAB
1615 case KEY_BTAB:
1616#endif
f019ce1f 1617 ui_menu_goto(cf, (int) m->idx - 1);
ac27ea5c
KZ
1618 return 0;
1619 }
1620 }
1621
2f4eb047
KZ
1622 if (key == '\014') { /* ^L refresh */
1623 ui_menu_resize(cf);
1624 return 0;
1625 }
1626
b607e5fa 1627 DBG(MENU, ul_debug(" no menu move key"));
2f4eb047 1628 return 1;
ac27ea5c
KZ
1629}
1630
7556c944
KZ
1631/* but don't call me from ui_run(), this is for pop-up menus only */
1632static void ui_menu_resize(struct cfdisk *cf)
1633{
b607e5fa 1634 DBG(MENU, ul_debug("menu resize/refresh"));
7556c944
KZ
1635 resize();
1636 ui_clean_menu(cf);
1637 menu_refresh_size(cf);
1638 ui_draw_menu(cf);
1639 refresh();
1640}
1641
a6f69126
KZ
1642static int partition_on_page(struct cfdisk *cf, size_t i)
1643{
1644 if (cf->page_sz == 0 ||
1645 cf->lines_idx / cf->page_sz == i / cf->page_sz)
1646 return 1;
1647 return 0;
1648}
1649
8c3a5a44
KZ
1650static void ui_draw_partition(struct cfdisk *cf, size_t i)
1651{
1652 int ln = TABLE_START_LINE + 1 + i; /* skip table header */
1653 int cl = ARROW_CURSOR_WIDTH; /* we need extra space for cursor */
a6f69126
KZ
1654 int cur = cf->lines_idx == i;
1655 size_t curpg = 0;
1656
1657 if (cf->page_sz) {
1658 if (!partition_on_page(cf, i))
1659 return;
1660 ln = TABLE_START_LINE + (i % cf->page_sz) + 1;
1661 curpg = cf->lines_idx / cf->page_sz;
1662 }
6dbe3af9 1663
14620822
KZ
1664 DBG(UI, ul_debug(
1665 "draw partition %zu [page_sz=%zu, "
a6f69126
KZ
1666 "line=%d, idx=%zu]",
1667 i, cf->page_sz, ln, cf->lines_idx));
6dbe3af9 1668
a6f69126
KZ
1669 if (cur) {
1670 attron(A_REVERSE);
8c3a5a44 1671 mvaddstr(ln, 0, ARROW_CURSOR_STRING);
dda7fe12 1672 mvaddstr(ln, cl, cf->lines[i + 1].data);
a6f69126 1673 attroff(A_REVERSE);
6dbe3af9 1674 } else {
45333e9d
KZ
1675 int at = 0;
1676
f1512be8 1677 if (colors_wanted() && is_freespace(cf, i)) {
45333e9d
KZ
1678 attron(COLOR_PAIR(CFDISK_CL_FREESPACE));
1679 at = 1;
1680 }
8c3a5a44 1681 mvaddstr(ln, 0, ARROW_CURSOR_DUMMY);
dda7fe12 1682 mvaddstr(ln, cl, cf->lines[i + 1].data);
45333e9d 1683 if (at)
dda7fe12 1684 attroff(COLOR_PAIR(CFDISK_CL_FREESPACE));
6dbe3af9
KZ
1685 }
1686
a6f69126
KZ
1687 if ((size_t) ln == MENU_START_LINE - 1 &&
1688 cf->page_sz && curpg < cf->nlines / cf->page_sz) {
1689 if (cur)
1690 attron(A_REVERSE);
eef63970 1691 mvaddch(ln, ui_cols - 1, ACS_DARROW);
a6f69126
KZ
1692 mvaddch(ln, 0, ACS_DARROW);
1693 if (cur)
1694 attroff(A_REVERSE);
1695 }
dda7fe12 1696
6dbe3af9
KZ
1697}
1698
8c3a5a44
KZ
1699static int ui_draw_table(struct cfdisk *cf)
1700{
1701 int cl = ARROW_CURSOR_WIDTH;
1702 size_t i, nparts = fdisk_table_get_nents(cf->table);
a6f69126 1703 size_t curpg = cf->page_sz ? cf->lines_idx / cf->page_sz : 0;
7eda085c 1704
14620822 1705 DBG(UI, ul_debug("draw table"));
6dbe3af9 1706
a6f69126
KZ
1707 for (i = TABLE_START_LINE; i <= TABLE_START_LINE + cf->page_sz; i++) {
1708 move(i, 0);
1709 clrtoeol();
1710 }
6dbe3af9 1711
a2d0dbb4 1712 if (nparts == 0 || (size_t) cf->lines_idx > nparts - 1)
b2301179
KZ
1713 cf->lines_idx = nparts ? nparts - 1 : 0;
1714
8c3a5a44
KZ
1715 /* print header */
1716 attron(A_BOLD);
dda7fe12 1717 mvaddstr(TABLE_START_LINE, cl, cf->lines[0].data);
8c3a5a44 1718 attroff(A_BOLD);
6dbe3af9 1719
8c3a5a44
KZ
1720 /* print partitions */
1721 for (i = 0; i < nparts; i++)
1722 ui_draw_partition(cf, i);
6dbe3af9 1723
a6f69126 1724 if (curpg != 0) {
eef63970 1725 mvaddch(TABLE_START_LINE, ui_cols - 1, ACS_UARROW);
a6f69126
KZ
1726 mvaddch(TABLE_START_LINE, 0, ACS_UARROW);
1727 }
1728 if (cf->page_sz && curpg < cf->nlines / cf->page_sz) {
eef63970 1729 mvaddch(MENU_START_LINE - 1, ui_cols - 1, ACS_DARROW);
a6f69126
KZ
1730 mvaddch(MENU_START_LINE - 1, 0, ACS_DARROW);
1731 }
8c3a5a44 1732 return 0;
6dbe3af9
KZ
1733}
1734
8c3a5a44
KZ
1735static int ui_table_goto(struct cfdisk *cf, int where)
1736{
1737 size_t old;
1738 size_t nparts = fdisk_table_get_nents(cf->table);
6dbe3af9 1739
14620822 1740 DBG(UI, ul_debug("goto table %d", where));
6dbe3af9 1741
8c3a5a44
KZ
1742 if (where < 0)
1743 where = 0;
1744 else if ((size_t) where > nparts - 1)
1745 where = nparts - 1;
6dbe3af9 1746
8c3a5a44
KZ
1747 if ((size_t) where == cf->lines_idx)
1748 return 0;
6dbe3af9 1749
8c3a5a44
KZ
1750 old = cf->lines_idx;
1751 cf->lines_idx = where;
6dbe3af9 1752
a6f69126
KZ
1753 if (!partition_on_page(cf, old) ||!partition_on_page(cf, where))
1754 ui_draw_table(cf);
1755 else {
1756 ui_draw_partition(cf, old); /* cleanup old */
1757 ui_draw_partition(cf, where); /* draw new */
1758 }
1af8003b 1759 ui_clean_info();
8c3a5a44 1760 ui_draw_menu(cf);
3542fc51 1761 ui_draw_extra(cf);
8c3a5a44 1762 refresh();
dda7fe12 1763
8c3a5a44 1764 return 0;
6dbe3af9
KZ
1765}
1766
8c3a5a44
KZ
1767static int ui_refresh(struct cfdisk *cf)
1768{
57c83d63 1769 struct fdisk_label *lb;
8c3a5a44 1770 char *id = NULL;
57c83d63 1771 uint64_t bytes = fdisk_get_nsectors(cf->cxt) * fdisk_get_sector_size(cf->cxt);
ec8a728a 1772 char *strsz;
8c3a5a44 1773
83fa0f80 1774 if (!ui_enabled)
8c3a5a44
KZ
1775 return -EINVAL;
1776
39f37044
KZ
1777 strsz = size_to_human_string(SIZE_DECIMAL_2DIGITS
1778 | SIZE_SUFFIX_SPACE
ec8a728a
KZ
1779 | SIZE_SUFFIX_3LETTER, bytes);
1780
57c83d63
KZ
1781 lb = fdisk_get_label(cf->cxt, NULL);
1782 assert(lb);
1783
a2d0dbb4
KZ
1784 clear();
1785
8c3a5a44
KZ
1786 /* header */
1787 attron(A_BOLD);
57c83d63 1788 ui_center(0, _("Disk: %s"), fdisk_get_devname(cf->cxt));
8c3a5a44 1789 attroff(A_BOLD);
7085f1e4 1790 ui_center(1, _("Size: %s, %"PRIu64" bytes, %ju sectors"),
57c83d63 1791 strsz, bytes, (uintmax_t) fdisk_get_nsectors(cf->cxt));
8c3a5a44 1792 if (fdisk_get_disklabel_id(cf->cxt, &id) == 0 && id)
1af8003b 1793 ui_center(2, _("Label: %s, identifier: %s"),
57c83d63 1794 fdisk_label_get_name(lb), id);
7eda085c 1795 else
57c83d63 1796 ui_center(2, _("Label: %s"), fdisk_label_get_name(lb));
8c3a5a44 1797 free(strsz);
ec8f7121 1798 free(id);
6dbe3af9 1799
8c3a5a44
KZ
1800 ui_draw_table(cf);
1801 ui_draw_menu(cf);
6dbe3af9 1802 refresh();
8c3a5a44 1803 return 0;
6dbe3af9
KZ
1804}
1805
ffab025d 1806static ssize_t ui_get_string(const char *prompt,
b1f58330
KZ
1807 const char *hint, char *buf, size_t len)
1808{
b1f58330 1809 int ln = MENU_START_LINE, cl = 1;
1b6d02fe
KZ
1810 ssize_t rc = -1;
1811 struct mbs_editor *edit;
1812
1813 DBG(UI, ul_debug("ui get string"));
b1f58330 1814
b1f58330
KZ
1815 assert(buf);
1816 assert(len);
1817
1818 move(ln, 0);
1819 clrtoeol();
1820
a89eafed
KZ
1821 move(ln + 1, 0);
1822 clrtoeol();
1823
b1f58330 1824 if (prompt) {
f2cfb235 1825 mvaddstr(ln, cl, prompt);
b1f58330
KZ
1826 cl += mbs_safe_width(prompt);
1827 }
1828
1b6d02fe
KZ
1829 edit = mbs_new_edit(buf, len, ui_cols - cl);
1830 if (!edit)
1831 goto done;
1832
1833 mbs_edit_goto(edit, MBS_EDIT_END);
b1f58330
KZ
1834
1835 if (hint)
fbae1442 1836 ui_hint("%s", hint);
b1f58330
KZ
1837 else
1838 ui_clean_hint();
1839
b1f58330 1840 curs_set(1);
b1f58330 1841
502c5186 1842 while (!sig_die) {
1b6d02fe
KZ
1843 wint_t c; /* we have fallback in widechar.h */
1844
1845 move(ln, cl);
1846 clrtoeol();
1847 mvaddstr(ln, cl, edit->buf);
1848 move(ln, cl + edit->cursor_cells);
1849 refresh();
1850
b1f58330
KZ
1851#if !defined(HAVE_SLCURSES_H) && !defined(HAVE_SLANG_SLCURSES_H) && \
1852 defined(HAVE_LIBNCURSESW) && defined(HAVE_WIDECHAR)
1853 if (get_wch(&c) == ERR) {
1854#else
c71f5a56 1855 if ((c = getch()) == (wint_t) ERR) {
b1f58330 1856#endif
502c5186
KZ
1857 if (sig_die)
1858 break;
c431d901 1859 if (sig_resize) {
7556c944
KZ
1860 resize();
1861 continue;
1862 }
b1f58330
KZ
1863 if (!isatty(STDIN_FILENO))
1864 exit(2);
1865 else
1866 goto done;
1867 }
1b6d02fe
KZ
1868
1869 DBG(UI, ul_debug("ui get string: key=%lc", c));
1870
b1f58330
KZ
1871 if (c == '\r' || c == '\n' || c == KEY_ENTER)
1872 break;
1873
1b6d02fe
KZ
1874 rc = 1;
1875
b1f58330
KZ
1876 switch (c) {
1877 case KEY_ESC:
1878 rc = -CFDISK_ERR_ESC;
1879 goto done;
1b6d02fe
KZ
1880 case KEY_LEFT:
1881 rc = mbs_edit_goto(edit, MBS_EDIT_LEFT);
1882 break;
635a8151 1883 case KEY_RIGHT:
1b6d02fe
KZ
1884 rc = mbs_edit_goto(edit, MBS_EDIT_RIGHT);
1885 break;
635a8151 1886 case KEY_END:
1b6d02fe
KZ
1887 rc = mbs_edit_goto(edit, MBS_EDIT_END);
1888 break;
635a8151 1889 case KEY_HOME:
1b6d02fe
KZ
1890 rc = mbs_edit_goto(edit, MBS_EDIT_HOME);
1891 break;
635a8151
KZ
1892 case KEY_UP:
1893 case KEY_DOWN:
635a8151 1894 break;
1b6d02fe
KZ
1895 case KEY_DC:
1896 rc = mbs_edit_delete(edit);
1897 break;
b1f58330 1898 case '\b':
6b1e439a 1899 case KEY_DELETE:
b1f58330 1900 case KEY_BACKSPACE:
1b6d02fe 1901 rc = mbs_edit_backspace(edit);
b1f58330
KZ
1902 break;
1903 default:
1b6d02fe
KZ
1904 rc = mbs_edit_insert(edit, c);
1905 break;
b1f58330 1906 }
1b6d02fe
KZ
1907 if (rc == 1)
1908 beep();
b1f58330
KZ
1909 }
1910
502c5186
KZ
1911 if (sig_die)
1912 die_on_signal();
1913
1b6d02fe 1914 rc = strlen(edit->buf); /* success */
b1f58330
KZ
1915done:
1916 move(ln, 0);
1917 clrtoeol();
1918 curs_set(0);
1919 refresh();
1b6d02fe 1920 mbs_free_edit(edit);
b1f58330
KZ
1921
1922 return rc;
1923}
1924
a351f2e5
KZ
1925static int ui_get_size(struct cfdisk *cf, /* context */
1926 const char *prompt, /* UI dialog string */
7085f1e4
KZ
1927 uint64_t *res, /* result in bytes */
1928 uint64_t low, /* minimal size */
1929 uint64_t up, /* maximal size */
a351f2e5 1930 int *expsize) /* explicitly specified size */
b1f58330
KZ
1931{
1932 char buf[128];
7085f1e4 1933 uint64_t user = 0;
b1f58330
KZ
1934 ssize_t rc;
1935 char *dflt = size_to_human_string(0, *res);
1936
33342316 1937 DBG(UI, ul_debug("get_size (default=%"PRIu64")", *res));
b1f58330
KZ
1938
1939 ui_clean_info();
1940
29e9b787
KZ
1941 snprintf(buf, sizeof(buf), "%s", dflt);
1942
b1f58330 1943 do {
91ba41ca 1944 int pwr = 0, insec = 0;
b1f58330 1945
ffab025d 1946 rc = ui_get_string(prompt,
a4fbbbd4
BS
1947 _("May be followed by M for MiB, G for GiB, "
1948 "T for TiB, or S for sectors."),
b1f58330 1949 buf, sizeof(buf));
29e9b787
KZ
1950 ui_clean_warn();
1951
b1f58330
KZ
1952 if (rc == 0) {
1953 ui_warnx(_("Please, specify size."));
1954 continue; /* nothing specified */
042f62df 1955 } if (rc == -CFDISK_ERR_ESC)
b1f58330
KZ
1956 break; /* cancel dialog */
1957
91ba41ca
KZ
1958 if (strcmp(buf, dflt) == 0)
1959 user = *res, rc = 0; /* no change, use default */
1960 else {
1961 size_t len = strlen(buf);
bfdb3244 1962 if (buf[len - 1] == 'S' || buf[len - 1] == 's') {
91ba41ca
KZ
1963 insec = 1;
1964 buf[len - 1] = '\0';
1965 }
33342316 1966 rc = parse_size(buf, (uintmax_t *)&user, &pwr); /* parse */
91ba41ca
KZ
1967 }
1968
b1f58330 1969 if (rc == 0) {
7085f1e4 1970 DBG(UI, ul_debug("get_size user=%"PRIu64", power=%d, in-sectors=%s",
91ba41ca
KZ
1971 user, pwr, insec ? "yes" : "no"));
1972 if (insec)
57c83d63 1973 user *= fdisk_get_sector_size(cf->cxt);
b1f58330 1974 if (user < low) {
7085f1e4 1975 ui_warnx(_("Minimum size is %"PRIu64" bytes."), low);
b1f58330
KZ
1976 rc = -ERANGE;
1977 }
1978 if (user > up && pwr && user < up + (1ULL << pwr * 10))
1979 /* ignore when the user specified size overflow
1980 * with in range specified by suffix (e.g. MiB) */
1981 user = up;
1982
1983 if (user > up) {
7085f1e4 1984 ui_warnx(_("Maximum size is %"PRIu64" bytes."), up);
b1f58330
KZ
1985 rc = -ERANGE;
1986 }
9b0b9fb1
KZ
1987 if (rc == 0 && insec && expsize)
1988 *expsize = 1;
1989
2cec7949
KZ
1990 } else
1991 ui_warnx(_("Failed to parse size."));
b1f58330
KZ
1992 } while (rc != 0);
1993
1994 if (rc == 0)
1995 *res = user;
1996 free(dflt);
1997
7085f1e4 1998 DBG(UI, ul_debug("get_size (result=%"PRIu64", rc=%zd)", *res, rc));
b1f58330
KZ
1999 return rc;
2000}
2001
6d6d9c1a
KZ
2002static struct fdisk_parttype *ui_get_parttype(struct cfdisk *cf,
2003 struct fdisk_parttype *cur)
6fed9601 2004{
3b411726 2005 struct cfdisk_menuitem *d, *cm;
6d6d9c1a 2006 size_t i = 0, nitems, idx = 0;
a745611d 2007 struct fdisk_parttype *t = NULL;
5ab37600 2008 struct fdisk_label *lb;
a745611d 2009 int codetypes = 0;
6fed9601 2010
14620822 2011 DBG(UI, ul_debug("asking for parttype."));
6fed9601 2012
5ab37600
KZ
2013 lb = fdisk_get_label(cf->cxt, NULL);
2014
6fed9601
KZ
2015 /* create cfdisk menu according to label types, note that the
2016 * last cm[] item has to be empty -- so nitems + 1 */
a745611d
KZ
2017 nitems = fdisk_label_get_nparttypes(lb);
2018 if (!nitems)
6d6d9c1a 2019 return NULL;
5ab37600 2020
3b411726 2021 cm = xcalloc(nitems + 1, sizeof(struct cfdisk_menuitem));
6fed9601
KZ
2022 if (!cm)
2023 return NULL;
2024
a745611d 2025 codetypes = fdisk_label_has_code_parttypes(lb);
6d6d9c1a 2026
6fed9601 2027 for (i = 0; i < nitems; i++) {
a745611d 2028 const struct fdisk_parttype *x = fdisk_label_get_parttype(lb, i);
6d6d9c1a 2029 char *name;
6fed9601 2030
a745611d
KZ
2031 cm[i].userdata = (void *) x;
2032 if (codetypes)
2033 xasprintf(&name, "%2x %s",
2034 fdisk_parttype_get_code(x),
2035 _(fdisk_parttype_get_name(x)));
6d6d9c1a 2036 else {
a745611d
KZ
2037 name = (char *) _(fdisk_parttype_get_name(x));
2038 cm[i].desc = fdisk_parttype_get_string(x);
6d6d9c1a
KZ
2039 }
2040 cm[i].name = name;
2041 if (x == cur)
2042 idx = i;
6fed9601
KZ
2043 }
2044
2045 /* make the new menu active */
2046 menu_push(cf, cm);
2047 cf->menu->vertical = 1;
6d6d9c1a 2048 cf->menu->idx = idx;
6fed9601
KZ
2049 menu_set_title(cf->menu, _("Select partition type"));
2050 ui_draw_menu(cf);
2051 refresh();
2052
502c5186 2053 while (!sig_die) {
6fed9601 2054 int key = getch();
f019ce1f 2055
502c5186
KZ
2056 if (sig_die)
2057 break;
c431d901 2058 if (sig_resize)
7556c944 2059 ui_menu_resize(cf);
6fed9601
KZ
2060 if (ui_menu_move(cf, key) == 0)
2061 continue;
f019ce1f 2062
6fed9601
KZ
2063 switch (key) {
2064 case KEY_ENTER:
2065 case '\n':
2066 case '\r':
2067 d = menu_get_menuitem(cf, cf->menu->idx);
2068 if (d)
2069 t = (struct fdisk_parttype *) d->userdata;
2070 goto done;
ad5d45c0 2071 case KEY_ESC:
6fed9601
KZ
2072 case 'q':
2073 case 'Q':
2074 goto done;
2075 }
502c5186 2076 }
6fed9601 2077
502c5186
KZ
2078 if (sig_die)
2079 die_on_signal();
6fed9601
KZ
2080done:
2081 menu_pop(cf);
a745611d 2082 if (codetypes) {
6d6d9c1a
KZ
2083 for (i = 0; i < nitems; i++)
2084 free((char *) cm[i].name);
2085 }
6fed9601 2086 free(cm);
57c83d63 2087 DBG(UI, ul_debug("get parrtype done [type=%s] ", t ?
30cc5f57 2088 fdisk_parttype_get_name(t) : ""));
6fed9601
KZ
2089 return t;
2090}
2091
a89eafed
KZ
2092static int ui_script_read(struct cfdisk *cf)
2093{
2094 struct fdisk_script *sc = NULL;
2095 char buf[PATH_MAX] = { 0 };
2096 int rc;
2097
941409c0 2098 erase();
ffab025d 2099 rc = ui_get_string( _("Enter script file name: "),
a89eafed
KZ
2100 _("The script file will be applied to in-memory partition table."),
2101 buf, sizeof(buf));
2102 if (rc <= 0)
2103 return rc;
2104
2105 rc = -1;
2106 errno = 0;
2107 sc = fdisk_new_script_from_file(cf->cxt, buf);
2108 if (!sc && errno)
54fefa07 2109 ui_warn(_("Cannot open %s"), buf);
a89eafed
KZ
2110 else if (!sc)
2111 ui_warnx(_("Failed to parse script file %s"), buf);
2112 else if (fdisk_apply_script(cf->cxt, sc) != 0)
2113 ui_warnx(_("Failed to apply script %s"), buf);
2114 else
2115 rc = 0;
2116
941409c0 2117 ui_clean_hint();
a89eafed
KZ
2118 fdisk_unref_script(sc);
2119 return rc;
2120}
2121
2122static int ui_script_write(struct cfdisk *cf)
2123{
2124 struct fdisk_script *sc = NULL;
2125 char buf[PATH_MAX] = { 0 };
2126 FILE *f = NULL;
2127 int rc;
2128
ffab025d 2129 rc = ui_get_string( _("Enter script file name: "),
a89eafed
KZ
2130 _("The current in-memory partition table will be dumped to the file."),
2131 buf, sizeof(buf));
2132 if (rc <= 0)
2133 return rc;
2134
2135 rc = 0;
2136 sc = fdisk_new_script(cf->cxt);
2137 if (!sc) {
2138 ui_warn(_("Failed to allocate script handler"));
2139 goto done;
2140 }
2141
2142 rc = fdisk_script_read_context(sc, NULL);
2143 if (rc) {
2144 ui_warnx(_("Failed to read disk layout into script."));
2145 goto done;
2146 }
2147
8c9615a9 2148 DBG(UI, ul_debug("writing dump into: '%s'", buf));
a89eafed
KZ
2149 f = fopen(buf, "w");
2150 if (!f) {
54fefa07 2151 ui_warn(_("Cannot open %s"), buf);
8c9615a9 2152 rc = -errno;
a89eafed
KZ
2153 goto done;
2154 }
2155
2156 rc = fdisk_script_write_file(sc, f);
8c9615a9
KZ
2157 if (!rc)
2158 ui_info(_("Disk layout successfully dumped."));
2159done:
a89eafed
KZ
2160 if (rc)
2161 ui_warn(_("Failed to write script %s"), buf);
a89eafed
KZ
2162 if (f)
2163 fclose(f);
2164 fdisk_unref_script(sc);
2165 return rc;
2166}
2167
7aa0d529
KZ
2168/* prints menu with libfdisk labels and waits for users response */
2169static int ui_create_label(struct cfdisk *cf)
2170{
3b411726 2171 struct cfdisk_menuitem *d, *cm;
941409c0 2172 int rc = 1, refresh_menu = 1;
7aa0d529
KZ
2173 size_t i = 0, nitems;
2174 struct fdisk_label *lb = NULL;
2175
2176 assert(cf);
2177
14620822 2178 DBG(UI, ul_debug("asking for new disklabe."));
7aa0d529
KZ
2179
2180 /* create cfdisk menu according to libfdisk labels, note that the
2181 * last cm[] item has to be empty -- so nitems + 1 */
6a632136 2182 nitems = fdisk_get_nlabels(cf->cxt);
3b411726 2183 cm = xcalloc(nitems + 1, sizeof(struct cfdisk_menuitem));
7aa0d529 2184
6a632136 2185 while (fdisk_next_label(cf->cxt, &lb) == 0) {
57c83d63 2186 if (fdisk_label_is_disabled(lb) ||
8eccde20 2187 fdisk_label_get_type(lb) == FDISK_DISKLABEL_BSD)
dd626abd 2188 continue;
57c83d63 2189 cm[i++].name = fdisk_label_get_name(lb);
7aa0d529
KZ
2190 }
2191
2192 erase();
7aa0d529
KZ
2193
2194 /* make the new menu active */
63128bbf 2195 menu_push(cf, cm);
7aa0d529
KZ
2196 cf->menu->vertical = 1;
2197 menu_set_title(cf->menu, _("Select label type"));
941409c0
KZ
2198
2199 if (!cf->zero_start)
2200 ui_info(_("Device does not contain a recognized partition table."));
2201
7aa0d529 2202
502c5186 2203 while (!sig_die) {
c308e205
SK
2204 int key;
2205
941409c0
KZ
2206 if (refresh_menu) {
2207 ui_draw_menu(cf);
45be288c 2208 ui_hint(_("Select a type to create a new label, press 'L' to load script file, 'Q' quits."));
941409c0
KZ
2209 refresh();
2210 refresh_menu = 0;
2211 }
2212
c308e205 2213 key = getch();
7556c944 2214
502c5186
KZ
2215 if (sig_die)
2216 break;
c431d901 2217 if (sig_resize)
7556c944 2218 ui_menu_resize(cf);
7aa0d529
KZ
2219 if (ui_menu_move(cf, key) == 0)
2220 continue;
2221 switch (key) {
2222 case KEY_ENTER:
2223 case '\n':
2224 case '\r':
6fed9601 2225 d = menu_get_menuitem(cf, cf->menu->idx);
7aa0d529
KZ
2226 if (d)
2227 rc = fdisk_create_disklabel(cf->cxt, d->name);
2228 goto done;
ad5d45c0 2229 case KEY_ESC:
7aa0d529
KZ
2230 case 'q':
2231 case 'Q':
2232 goto done;
f16c37f4 2233 case 'l':
a89eafed 2234 case 'L':
a89eafed
KZ
2235 rc = ui_script_read(cf);
2236 if (rc == 0)
2237 goto done;
941409c0 2238 refresh_menu = 1;
a89eafed 2239 break;
7aa0d529 2240 }
502c5186 2241 }
7aa0d529 2242
502c5186
KZ
2243 if (sig_die)
2244 die_on_signal();
7aa0d529
KZ
2245done:
2246 menu_pop(cf);
2247 free(cm);
14620822 2248 DBG(UI, ul_debug("create label done [rc=%d] ", rc));
7aa0d529
KZ
2249 return rc;
2250}
2251
a89eafed 2252
314a0dd8
KZ
2253static int ui_help(void)
2254{
2255 size_t i;
314a0dd8 2256 static const char *help[] = {
e993b9c8
BS
2257 N_("This is cfdisk, a curses-based disk partitioning program."),
2258 N_("It lets you create, delete, and modify partitions on a block device."),
fd4484a7 2259 " ",
314a0dd8
KZ
2260 N_("Command Meaning"),
2261 N_("------- -------"),
793e8d2a
KZ
2262 N_(" b Toggle bootable flag of the current partition;"),
2263 N_(" implemented for DOS (MBR) and SGI labels only"),
314a0dd8
KZ
2264 N_(" d Delete the current partition"),
2265 N_(" h Print this screen"),
2266 N_(" n Create new partition from free space"),
2267 N_(" q Quit program without writing partition table"),
c186e148 2268 N_(" r Reduce or enlarge the current partition"),
33f7c502 2269 N_(" s Fix partitions order (only when in disarray)"),
e993b9c8 2270 N_(" t Change the partition type"),
a89eafed 2271 N_(" u Dump disk layout to sfdisk compatible script file"),
e993b9c8
BS
2272 N_(" W Write partition table to disk (you must enter uppercase W);"),
2273 N_(" since this might destroy data on the disk, you must either"),
2274 N_(" confirm or deny the write by entering 'yes' or 'no'"),
dda7fe12 2275 N_(" x Display/hide extra information about a partition"),
314a0dd8
KZ
2276 N_("Up Arrow Move cursor to the previous partition"),
2277 N_("Down Arrow Move cursor to the next partition"),
2278 N_("Left Arrow Move cursor to the previous menu item"),
2279 N_("Right Arrow Move cursor to the next menu item"),
fd4484a7 2280 " ",
314a0dd8 2281 N_("Note: All of the commands can be entered with either upper or lower"),
e993b9c8 2282 N_("case letters (except for Write)."),
fd4484a7 2283 " ",
e7e76976
KZ
2284 N_("Use lsblk(8) or partx(8) to see more details about the device."),
2285 " ",
2286 " ",
793e8d2a 2287 "Copyright (C) 2014-2023 Karel Zak <kzak@redhat.com>"
314a0dd8
KZ
2288 };
2289
2290 erase();
314a0dd8
KZ
2291 for (i = 0; i < ARRAY_SIZE(help); i++)
2292 mvaddstr(i, 1, _(help[i]));
2293
2294 ui_info(_("Press a key to continue."));
7556c944 2295
314a0dd8 2296 getch();
502c5186
KZ
2297
2298 if (sig_die)
2299 die_on_signal();
314a0dd8
KZ
2300 return 0;
2301}
2302
63128bbf
KZ
2303/* TODO: use @sz, now 128bytes */
2304static int main_menu_ignore_keys(struct cfdisk *cf, char *ignore,
2305 size_t sz __attribute__((__unused__)))
2306{
2307 struct fdisk_partition *pa = get_current_partition(cf);
2308 size_t i = 0;
2309
2310 if (!pa)
2311 return 0;
2312 if (fdisk_partition_is_freespace(pa)) {
2313 ignore[i++] = 'd'; /* delete */
2314 ignore[i++] = 't'; /* set type */
2315 ignore[i++] = 'b'; /* set bootable */
a351f2e5 2316 ignore[i++] = 'r'; /* resize */
b5ef65a9 2317 cf->menu->prefkey = 'n';
63128bbf 2318 } else {
b5ef65a9 2319 cf->menu->prefkey = 'q';
63128bbf 2320 ignore[i++] = 'n';
aa36c2cf
KZ
2321 if (!fdisk_is_label(cf->cxt, DOS) &&
2322 !fdisk_is_label(cf->cxt, SGI))
63128bbf
KZ
2323 ignore[i++] = 'b';
2324 }
e146ae4e 2325
d5314bf5
KZ
2326 if (!cf->wrong_order)
2327 ignore[i++] = 's';
f9fb8290 2328
6a632136 2329 if (fdisk_is_readonly(cf->cxt))
e146ae4e 2330 ignore[i++] = 'W';
dda7fe12 2331
63128bbf
KZ
2332 return i;
2333}
2334
2335
ed8a13e6
KZ
2336/* returns: error: < 0, success: 0, quit: 1 */
2337static int main_menu_action(struct cfdisk *cf, int key)
2338{
2339 size_t n;
d5314bf5 2340 int ref = 0, rc, org_order = cf->wrong_order;
ed8a13e6
KZ
2341 const char *info = NULL, *warn = NULL;
2342 struct fdisk_partition *pa;
2343
2344 assert(cf);
2345 assert(cf->cxt);
2346 assert(cf->menu);
2347
2348 if (key == 0) {
3b411726 2349 struct cfdisk_menuitem *d = menu_get_menuitem(cf, cf->menu->idx);
ed8a13e6
KZ
2350 if (!d)
2351 return 0;
2352 key = d->key;
2353
2354 } else if (key != 'w' && key != 'W')
2355 key = tolower(key); /* case insensitive except 'W'rite */
2356
14620822 2357 DBG(MENU, ul_debug("main menu action: key=%c", key));
ed8a13e6
KZ
2358
2359 if (cf->menu->ignore && strchr(cf->menu->ignore, key)) {
14620822 2360 DBG(MENU, ul_debug(" ignore '%c'", key));
ed8a13e6
KZ
2361 return 0;
2362 }
2363
2364 pa = get_current_partition(cf);
ec8a728a
KZ
2365 if (!pa)
2366 return -EINVAL;
ed8a13e6
KZ
2367 n = fdisk_partition_get_partno(pa);
2368
14620822 2369 DBG(MENU, ul_debug("menu action on %p", pa));
7b1ffbc4
KZ
2370 ui_clean_hint();
2371 ui_clean_info();
ed8a13e6
KZ
2372
2373 switch (key) {
2374 case 'b': /* Bootable flag */
2375 {
aa36c2cf
KZ
2376 int fl = fdisk_is_label(cf->cxt, DOS) ? DOS_FLAG_ACTIVE :
2377 fdisk_is_label(cf->cxt, SGI) ? SGI_FLAG_BOOT : 0;
ed8a13e6 2378
a1ef792f 2379 if (fl && fdisk_toggle_partition_flag(cf->cxt, n, fl))
ed8a13e6
KZ
2380 warn = _("Could not toggle the flag.");
2381 else if (fl)
2382 ref = 1;
2383 break;
2384 }
f1512be8 2385#ifdef KEY_DC
f019ce1f 2386 case KEY_DC:
f1512be8 2387#endif
ed8a13e6
KZ
2388 case 'd': /* Delete */
2389 if (fdisk_delete_partition(cf->cxt, n) != 0)
2390 warn = _("Could not delete partition %zu.");
2391 else
2392 info = _("Partition %zu has been deleted.");
2393 ref = 1;
2394 break;
d4640320 2395 case 'h': /* Help */
2a0ffa31 2396 case '?':
314a0dd8
KZ
2397 ui_help();
2398 ref = 1;
2399 break;
ed8a13e6
KZ
2400 case 'n': /* New */
2401 {
a351f2e5 2402 uint64_t start, size, dflt_size, secs, max_size;
ed8a13e6 2403 struct fdisk_partition *npa; /* the new partition */
9b0b9fb1 2404 int expsize = 0; /* size specified explicitly in sectors */
ed8a13e6 2405
ec8a728a 2406 if (!fdisk_partition_is_freespace(pa) || !fdisk_partition_has_start(pa))
ed8a13e6 2407 return -EINVAL;
75090201 2408
ed8a13e6
KZ
2409 /* free space range */
2410 start = fdisk_partition_get_start(pa);
a351f2e5 2411 size = max_size = dflt_size = fdisk_partition_get_size(pa) * fdisk_get_sector_size(cf->cxt);
ed8a13e6 2412
1bb387bd
KZ
2413 if (ui_get_size(cf, _("Partition size: "), &size,
2414 fdisk_get_sector_size(cf->cxt),
a351f2e5 2415 max_size, &expsize) == -CFDISK_ERR_ESC)
ed8a13e6
KZ
2416 break;
2417
75090201 2418 secs = size / fdisk_get_sector_size(cf->cxt);
75090201
KZ
2419
2420 npa = fdisk_new_partition();
2421 if (!npa)
2422 return -ENOMEM;
2423
ed8a13e6
KZ
2424 if (dflt_size == size) /* default is to fillin all free space */
2425 fdisk_partition_end_follow_default(npa, 1);
75090201
KZ
2426 else
2427 fdisk_partition_set_size(npa, secs);
ed8a13e6 2428
9b0b9fb1
KZ
2429 if (expsize)
2430 fdisk_partition_size_explicit(pa, 1);
2431
ed8a13e6 2432 fdisk_partition_set_start(npa, start);
9b0b9fb1 2433 fdisk_partition_partno_follow_default(npa, 1);
ed8a13e6 2434 /* add to disk label -- libfdisk will ask for missing details */
c3bc7483 2435 rc = fdisk_add_partition(cf->cxt, npa, NULL);
ed8a13e6
KZ
2436 fdisk_unref_partition(npa);
2437 if (rc == 0)
2438 ref = 1;
2439 break;
2440 }
2441 case 'q': /* Quit */
2442 return 1;
2443 case 't': /* Type */
6fed9601 2444 {
6fed9601
KZ
2445 struct fdisk_parttype *t;
2446
ec8a728a 2447 if (fdisk_partition_is_freespace(pa))
6fed9601
KZ
2448 return -EINVAL;
2449 t = (struct fdisk_parttype *) fdisk_partition_get_type(pa);
6d6d9c1a 2450 t = ui_get_parttype(cf, t);
6fed9601
KZ
2451 ref = 1;
2452
2453 if (t && fdisk_set_partition_type(cf->cxt, n, t) == 0)
09af3db4 2454 info = _("Changed type of partition %zu.");
6fed9601 2455 else
09af3db4 2456 info = _("The type of partition %zu is unchanged.");
ed8a13e6 2457 break;
6fed9601 2458 }
a351f2e5
KZ
2459 case 'r': /* resize */
2460 {
a351f2e5 2461 uint64_t size, max_size, secs;
78fd7300 2462 struct fdisk_partition *npa;
a351f2e5
KZ
2463
2464 if (fdisk_partition_is_freespace(pa) || !fdisk_partition_has_start(pa))
2465 return -EINVAL;
2466
78fd7300
TW
2467 rc = fdisk_partition_get_max_size(cf->cxt,
2468 fdisk_partition_get_partno(pa),
2469 &size);
2470 if (rc)
2471 return rc;
a351f2e5
KZ
2472
2473 size *= fdisk_get_sector_size(cf->cxt);
2474 max_size = size;
2475
2476 if (ui_get_size(cf, _("New size: "), &size,
2477 fdisk_get_sector_size(cf->cxt),
2478 max_size, NULL) == -CFDISK_ERR_ESC)
2479 break;
2480 secs = size / fdisk_get_sector_size(cf->cxt);
2481 npa = fdisk_new_partition();
2482 if (!npa)
2483 return -ENOMEM;
2484
2485 fdisk_partition_set_size(npa, secs);
2486
2487 rc = fdisk_set_partition(cf->cxt, n, npa);
2488 fdisk_unref_partition(npa);
2489 if (rc == 0) {
2490 ref = 1;
2491 info = _("Partition %zu resized.");
2492 }
2493 break;
2494 }
d4640320 2495 case 's': /* Sort */
d5314bf5
KZ
2496 if (cf->wrong_order) {
2497 fdisk_reorder_partitions(cf->cxt);
2498 ref = 1;
2499 }
2500 break;
d4640320 2501 case 'u': /* dUmp */
8c9615a9 2502 ui_script_write(cf);
a89eafed 2503 break;
ed8a13e6 2504 case 'W': /* Write */
7b1ffbc4
KZ
2505 {
2506 char buf[64] = { 0 };
e146ae4e 2507
6a632136 2508 if (fdisk_is_readonly(cf->cxt)) {
d4640320 2509 warn = _("Device is open in read-only mode.");
e146ae4e
KZ
2510 break;
2511 }
2512
ffab025d 2513 rc = ui_get_string(
7b1ffbc4
KZ
2514 _("Are you sure you want to write the partition "
2515 "table to disk? "),
09af3db4 2516 _("Type \"yes\" or \"no\", or press ESC to leave this dialog."),
7b1ffbc4
KZ
2517 buf, sizeof(buf));
2518
2519 ref = 1;
59af21c3
KZ
2520 if (rc <= 0 || (strcasecmp(buf, "yes") != 0 &&
2521 strcasecmp(buf, _("yes")) != 0)) {
d4640320 2522 info = _("Did not write partition table to disk.");
7b1ffbc4
KZ
2523 break;
2524 }
ed8a13e6
KZ
2525 rc = fdisk_write_disklabel(cf->cxt);
2526 if (rc)
d4640320 2527 warn = _("Failed to write disklabel.");
7b1ffbc4 2528 else {
b0d4d093
KZ
2529 size_t q_idx = 0;
2530
044ebc0c
KZ
2531 if (cf->device_is_used)
2532 fdisk_reread_changes(cf->cxt, cf->original_layout);
2533 else
2534 fdisk_reread_partition_table(cf->cxt);
7b1ffbc4 2535 info = _("The partition table has been altered.");
b0d4d093
KZ
2536 if (menu_get_menuitem_by_key(cf, 'q', &q_idx))
2537 ui_menu_goto(cf, q_idx);
7b1ffbc4 2538 }
bc787727 2539 cf->nwrites++;
7b1ffbc4
KZ
2540 break;
2541 }
2542 default:
ed8a13e6
KZ
2543 break;
2544 }
2545
2546 if (ref) {
2547 lines_refresh(cf);
2548 ui_refresh(cf);
3542fc51 2549 ui_draw_extra(cf);
a89eafed
KZ
2550 } else
2551 ui_draw_menu(cf);
7b1ffbc4
KZ
2552
2553 ui_clean_hint();
75090201 2554
ed8a13e6 2555 if (warn)
7b1ffbc4 2556 ui_warnx(warn, n + 1);
ed8a13e6 2557 else if (info)
7b1ffbc4 2558 ui_info(info, n + 1);
d5314bf5
KZ
2559 else if (key == 'n' && cf->wrong_order && org_order == 0)
2560 ui_info(_("Note that partition table entries are not in disk order now."));
ed8a13e6
KZ
2561
2562 return 0;
2563}
2564
7556c944
KZ
2565static void ui_resize_refresh(struct cfdisk *cf)
2566{
2f4eb047 2567 DBG(UI, ul_debug("ui resize/refresh"));
7556c944
KZ
2568 resize();
2569 menu_refresh_size(cf);
2570 lines_refresh(cf);
2571 ui_refresh(cf);
3542fc51 2572 ui_draw_extra(cf);
7556c944
KZ
2573}
2574
a2d0dbb4
KZ
2575static void toggle_show_extra(struct cfdisk *cf)
2576{
2577 if (cf->show_extra && cf->act_win) {
2578 wclear(cf->act_win);
2579 touchwin(stdscr);
2580 }
2581 cf->show_extra = cf->show_extra ? 0 : 1;
2582
2583 if (cf->show_extra)
2584 ui_draw_extra(cf);
2585 DBG(MENU, ul_debug("extra: %s", cf->show_extra ? "ENABLED" : "DISABLED" ));
2586}
2587
8c3a5a44
KZ
2588static int ui_run(struct cfdisk *cf)
2589{
7aa0d529 2590 int rc = 0;
6dbe3af9 2591
eef63970
KZ
2592 ui_lines = LINES;
2593 ui_cols = COLS;
2594 DBG(UI, ul_debug("start cols=%zu, lines=%zu", ui_cols, ui_lines));
6dbe3af9 2595
97ffbd43 2596 if (fdisk_get_collision(cf->cxt)) {
ad6d9fd5
KZ
2597 ui_warnx(_("Device already contains a %s signature."), fdisk_get_collision(cf->cxt));
2598 if (fdisk_is_readonly(cf->cxt)) {
2599 ui_hint(_("Press a key to continue."));
2600 getch();
2601 } else {
2602 char buf[64] = { 0 };
2603 rc = ui_get_string(_("Do you want to remove it? [Y]es/[N]o: "), NULL,
2604 buf, sizeof(buf));
2605 fdisk_enable_wipe(cf->cxt,
2606 rc > 0 && rpmatch(buf) == RPMATCH_YES ? 1 : 0);
2607 }
97ffbd43
KZ
2608 }
2609
aa36c2cf 2610 if (!fdisk_has_label(cf->cxt) || cf->zero_start) {
7aa0d529 2611 rc = ui_create_label(cf);
134b6296
KZ
2612 if (rc < 0) {
2613 errno = -rc;
2614 ui_err(EXIT_FAILURE,
7aa0d529 2615 _("failed to create a new disklabel"));
134b6296 2616 }
7aa0d529
KZ
2617 if (rc)
2618 return rc;
2619 }
2620
2621 cols_init(cf);
2622 rc = lines_refresh(cf);
2623 if (rc)
2624 ui_errx(EXIT_FAILURE, _("failed to read partitions"));
6dbe3af9 2625
3b411726 2626 menu_push(cf, main_menuitems);
63128bbf
KZ
2627 cf->menu->ignore_cb = main_menu_ignore_keys;
2628
8c3a5a44
KZ
2629 rc = ui_refresh(cf);
2630 if (rc)
2631 return rc;
6dbe3af9 2632
dda7fe12 2633 cf->show_extra = 1;
3542fc51 2634 ui_draw_extra(cf);
dda7fe12 2635
6a632136 2636 if (fdisk_is_readonly(cf->cxt))
0d182490 2637 ui_warnx(_("Device is open in read-only mode. Changes will remain in memory only."));
d527e8cf
KZ
2638 else if (cf->device_is_used)
2639 ui_warnx(_("Device is currently in use, repartitioning is probably a bad idea."));
f9fb8290 2640 else if (cf->wrong_order)
a2d0dbb4 2641 ui_info(_("Note that partition table entries are not in disk order now."));
e146ae4e 2642
502c5186 2643 while (!sig_die) {
7ee26cbf 2644 int key = getch();
6dbe3af9 2645
7ee26cbf 2646 rc = 0;
502c5186
KZ
2647
2648 if (sig_die)
2649 break;
c431d901 2650 if (sig_resize)
7556c944
KZ
2651 /* Note that ncurses getch() returns ERR when interrupted
2652 * by signal, but SLang does not interrupt at all. */
2653 ui_resize_refresh(cf);
2654 if (key == ERR)
2655 continue;
2f4eb047
KZ
2656 if (key == '\014') { /* ^L refresh */
2657 ui_resize_refresh(cf);
2658 continue;
2659 }
ac27ea5c
KZ
2660 if (ui_menu_move(cf, key) == 0)
2661 continue;
2662
2f4eb047 2663 DBG(UI, ul_debug("main action key >%1$c< [\\0%1$o].", key));
f019ce1f 2664
8c3a5a44
KZ
2665 switch (key) {
2666 case KEY_DOWN:
2667 case '\016': /* ^N */
2668 case 'j': /* Vi-like alternative */
2669 ui_table_goto(cf, cf->lines_idx + 1);
2670 break;
2671 case KEY_UP:
2672 case '\020': /* ^P */
2673 case 'k': /* Vi-like alternative */
f019ce1f 2674 ui_table_goto(cf, (int) cf->lines_idx - 1);
8c3a5a44 2675 break;
f019ce1f
KZ
2676 case KEY_PPAGE:
2677 if (cf->page_sz) {
2678 ui_table_goto(cf, (int) cf->lines_idx - cf->page_sz);
2679 break;
2680 }
08099e41 2681 /* fallthrough */
8c3a5a44
KZ
2682 case KEY_HOME:
2683 ui_table_goto(cf, 0);
2684 break;
f019ce1f
KZ
2685 case KEY_NPAGE:
2686 if (cf->page_sz) {
2687 ui_table_goto(cf, cf->lines_idx + cf->page_sz);
2688 break;
2689 }
08099e41 2690 /* fallthrough */
8c3a5a44 2691 case KEY_END:
f019ce1f 2692 ui_table_goto(cf, (int) cf->nlines - 1);
8c3a5a44 2693 break;
8c3a5a44
KZ
2694 case KEY_ENTER:
2695 case '\n':
2696 case '\r':
ed8a13e6 2697 rc = main_menu_action(cf, 0);
8c3a5a44 2698 break;
80351b1f 2699 case 'X':
3542fc51 2700 case 'x': /* Extra */
a2d0dbb4 2701 toggle_show_extra(cf);
3542fc51 2702 break;
8c3a5a44 2703 default:
ed8a13e6 2704 rc = main_menu_action(cf, key);
8460875d 2705 if (rc < 0)
8c3a5a44
KZ
2706 beep();
2707 break;
2708 }
8460875d
KZ
2709
2710 if (rc == 1)
2711 break; /* quit */
502c5186 2712 }
6dbe3af9 2713
8c3a5a44 2714 menu_pop(cf);
6dbe3af9 2715
14620822 2716 DBG(UI, ul_debug("end"));
8c3a5a44
KZ
2717 return 0;
2718}
6dbe3af9 2719
86be6a32 2720static void __attribute__((__noreturn__)) usage(void)
04915c3f 2721{
86be6a32 2722 FILE *out = stdout;
04915c3f 2723 fputs(USAGE_HEADER, out);
04915c3f
KZ
2724 fprintf(out,
2725 _(" %1$s [options] <disk>\n"), program_invocation_short_name);
2726
451dbcfa
BS
2727 fputs(USAGE_SEPARATOR, out);
2728 fputs(_("Display or manipulate a disk partition table.\n"), out);
2729
04915c3f 2730 fputs(USAGE_OPTIONS, out);
a7466bdc
SK
2731 fprintf(out,
2732 _(" -L, --color[=<when>] colorize output (%s, %s or %s)\n"), "auto", "always", "never");
5d51dc2a
KZ
2733 fprintf(out,
2734 " %s\n", USAGE_COLORS_DEFAULT);
2735 fputs(_(" -z, --zero start with zeroed partition table\n"), out);
ec8f7121
KZ
2736 fprintf(out,
2737 _(" --lock[=<mode>] use exclusive device lock (%s, %s or %s)\n"), "yes", "no", "nonblock");
0d182490 2738 fputs(_(" -r, --read-only forced open cfdisk in read-only mode\n"), out);
04915c3f
KZ
2739
2740 fputs(USAGE_SEPARATOR, out);
bad4c729 2741 fprintf(out, USAGE_HELP_OPTIONS(26));
04915c3f 2742
bad4c729 2743 fprintf(out, USAGE_MAN_TAIL("cfdisk(8)"));
86be6a32 2744 exit(EXIT_SUCCESS);
04915c3f
KZ
2745}
2746
8c3a5a44
KZ
2747int main(int argc, char *argv[])
2748{
ec8f7121 2749 const char *diskpath = NULL, *lockmode = NULL;
ad9fe47e 2750 int rc, c, colormode = UL_COLORMODE_UNDEF;
0d182490 2751 int read_only = 0;
8c3a5a44
KZ
2752 struct cfdisk _cf = { .lines_idx = 0 },
2753 *cf = &_cf;
ec8f7121
KZ
2754 enum {
2755 OPT_LOCK = CHAR_MAX + 1
2756 };
04915c3f
KZ
2757 static const struct option longopts[] = {
2758 { "color", optional_argument, NULL, 'L' },
ec8f7121 2759 { "lock", optional_argument, NULL, OPT_LOCK },
04915c3f
KZ
2760 { "help", no_argument, NULL, 'h' },
2761 { "version", no_argument, NULL, 'V' },
d121efdb 2762 { "zero", no_argument, NULL, 'z' },
0d182490 2763 { "read-only", no_argument, NULL, 'r' },
87918040 2764 { NULL, 0, NULL, 0 },
04915c3f
KZ
2765 };
2766
8c3a5a44
KZ
2767 setlocale(LC_ALL, "");
2768 bindtextdomain(PACKAGE, LOCALEDIR);
2769 textdomain(PACKAGE);
2c308875 2770 close_stdout_atexit();
6dbe3af9 2771
0d182490 2772 while((c = getopt_long(argc, argv, "L::hVzr", longopts, NULL)) != -1) {
04915c3f
KZ
2773 switch(c) {
2774 case 'h':
86be6a32 2775 usage();
04915c3f
KZ
2776 break;
2777 case 'L':
2778 colormode = UL_COLORMODE_AUTO;
2779 if (optarg)
2780 colormode = colormode_or_err(optarg,
2781 _("unsupported color mode"));
2782 break;
0d182490
DC
2783 case 'r':
2784 read_only = 1;
2785 break;
04915c3f 2786 case 'V':
2c308875 2787 print_version(EXIT_SUCCESS);
d121efdb
KZ
2788 case 'z':
2789 cf->zero_start = 1;
2790 break;
ec8f7121
KZ
2791 case OPT_LOCK:
2792 lockmode = "1";
2793 if (optarg) {
2794 if (*optarg == '=')
2795 optarg++;
2796 lockmode = optarg;
2797 }
2798 break;
677ec86c
KZ
2799 default:
2800 errtryhelp(EXIT_FAILURE);
04915c3f
KZ
2801 }
2802 }
2803
210bb492 2804 colors_init(colormode, "cfdisk");
04915c3f 2805
8c3a5a44 2806 fdisk_init_debug(0);
710ed55d 2807 scols_init_debug(0);
14620822 2808 cfdisk_init_debug();
8c3a5a44
KZ
2809 cf->cxt = fdisk_new_context();
2810 if (!cf->cxt)
2811 err(EXIT_FAILURE, _("failed to allocate libfdisk context"));
6dbe3af9 2812
6a632136 2813 fdisk_set_ask(cf->cxt, ask_callback, (void *) cf);
6dbe3af9 2814
6e51ab0c
KZ
2815 if (optind == argc) {
2816 size_t i;
2817
2818 for (i = 0; i < ARRAY_SIZE(default_disks); i++) {
2819 if (access(default_disks[i], F_OK) == 0) {
2820 diskpath = default_disks[i];
2821 break;
2822 }
2823 }
2824 if (!diskpath)
2825 diskpath = default_disks[0]; /* default, used for "cannot open" */
2826 } else
a4f0a42d 2827 diskpath = argv[optind];
6dbe3af9 2828
0d182490
DC
2829 rc = fdisk_assign_device(cf->cxt, diskpath, read_only);
2830 if (rc == -EACCES && read_only == 0)
6a632136 2831 rc = fdisk_assign_device(cf->cxt, diskpath, 1);
e146ae4e 2832 if (rc != 0)
6e51ab0c 2833 err(EXIT_FAILURE, _("cannot open %s"), diskpath);
6dbe3af9 2834
044ebc0c 2835 if (!fdisk_is_readonly(cf->cxt)) {
ec8f7121
KZ
2836 if (blkdev_lock(fdisk_get_devfd(cf->cxt), diskpath, lockmode) != 0)
2837 return EXIT_FAILURE;
2838
044ebc0c
KZ
2839 cf->device_is_used = fdisk_device_is_used(cf->cxt);
2840 fdisk_get_partitions(cf->cxt, &cf->original_layout);
2841 }
2842
8c3a5a44
KZ
2843 /* Don't use err(), warn() from this point */
2844 ui_init(cf);
2845 ui_run(cf);
7aa0d529 2846 ui_end();
6dbe3af9 2847
dda7fe12 2848 cfdisk_free_lines(cf);
8c3a5a44 2849 free(cf->linesbuf);
41994e00 2850 free(cf->fields);
ed8a13e6 2851
dda7fe12
OO
2852 fdisk_unref_table(cf->table);
2853#ifdef HAVE_LIBMOUNT
2854 mnt_unref_table(cf->fstab);
2855 mnt_unref_table(cf->mtab);
2856 mnt_unref_cache(cf->mntcache);
2857#endif
6a632136 2858 rc = fdisk_deassign_device(cf->cxt, cf->nwrites == 0);
c7119037 2859 fdisk_unref_context(cf->cxt);
14620822 2860 DBG(MISC, ul_debug("bye! [rc=%d]", rc));
ed8a13e6 2861 return rc == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
6dbe3af9 2862}