]>
Commit | Line | Data |
---|---|---|
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) | |
45 | ||
8460875d KZ |
46 | struct cfdisk; |
47 | typedef int (menu_callback_t)(struct cfdisk *, int); | |
48 | ||
49 | static int menu_cb_main(struct cfdisk *cf, int key); | |
50 | ||
8c3a5a44 KZ |
51 | |
52 | struct cfdisk_menudesc { | |
53 | int key; /* keyboard shortcut */ | |
54 | const char *name; /* item name */ | |
55 | const char *desc; /* item description */ | |
749af4b6 KZ |
56 | }; |
57 | ||
8c3a5a44 KZ |
58 | struct cfdisk_menu { |
59 | struct cfdisk_menudesc *desc; | |
60 | char *ignore; | |
61 | size_t id; | |
62 | size_t width; | |
63 | size_t nitems; | |
8460875d KZ |
64 | |
65 | menu_callback_t *callback; | |
66 | ||
8c3a5a44 | 67 | struct cfdisk_menu *prev; |
749af4b6 KZ |
68 | }; |
69 | ||
8c3a5a44 KZ |
70 | static struct cfdisk_menudesc menu_main[] = { |
71 | { 'b', N_("Bootable"), N_("Toggle bootable flag of the current partition") }, | |
72 | { 'd', N_("Delete"), N_("Delete the current partition") }, | |
73 | // { 'g', N_("Geometry"), N_("Change disk geometry (experts only)") }, | |
74 | // { 'h', N_("Help"), N_("Print help screen") }, | |
75 | // { 'm', N_("Maximize"), N_("Maximize disk usage of the current partition (experts only)") }, | |
76 | { 'n', N_("New"), N_("Create new partition from free space") }, | |
77 | // { 'p', N_("Print"), N_("Print partition table to the screen or to a file") }, | |
78 | { 'q', N_("Quit"), N_("Quit program without writing partition table") }, | |
79 | { 't', N_("Type"), N_("Change the partition type") }, | |
80 | // { 'u', N_("Units"), N_("Change units of the partition size display (MB, sect, cyl)") }, | |
81 | { 'W', N_("Write"), N_("Write partition table to disk (this might destroy data)") }, | |
82 | { 0, NULL, NULL } | |
83 | }; | |
6dbe3af9 | 84 | |
8c3a5a44 KZ |
85 | enum { |
86 | CFDISK_MENU_MAIN = 0, | |
5c36a0eb KZ |
87 | }; |
88 | ||
8c3a5a44 KZ |
89 | static struct cfdisk_menudesc *menus[] = { |
90 | [CFDISK_MENU_MAIN] = menu_main | |
91 | }; | |
7eda085c | 92 | |
8460875d KZ |
93 | static menu_callback_t *menu_callbacks[] = { |
94 | [CFDISK_MENU_MAIN] = menu_cb_main | |
95 | }; | |
96 | ||
97 | ||
8c3a5a44 KZ |
98 | struct cfdisk { |
99 | struct fdisk_context *cxt; /* libfdisk context */ | |
100 | struct fdisk_table *table; /* partition table */ | |
7eda085c | 101 | |
8c3a5a44 KZ |
102 | struct cfdisk_menu *menu; /* the current menu */ |
103 | size_t menu_idx; | |
7eda085c | 104 | |
8c3a5a44 KZ |
105 | int *cols; /* output columns */ |
106 | size_t ncols; /* number of columns */ | |
7eda085c | 107 | |
8c3a5a44 KZ |
108 | char *linesbuf; /* table as string */ |
109 | size_t linesbufsz; /* size of the tb_buf */ | |
7eda085c | 110 | |
8c3a5a44 KZ |
111 | char **lines; /* array with lines */ |
112 | size_t nlines; /* number of lines */ | |
113 | size_t lines_idx; /* current line <0..N>, exclude header */ | |
5c36a0eb | 114 | |
8c3a5a44 KZ |
115 | unsigned int ui_enabled : 1; |
116 | }; | |
5c36a0eb | 117 | |
8c3a5a44 KZ |
118 | static int cols_init(struct cfdisk *cf) |
119 | { | |
120 | assert(cf); | |
5c36a0eb | 121 | |
8c3a5a44 KZ |
122 | free(cf->cols); |
123 | cf->cols = NULL; | |
124 | cf->ncols = 0; | |
5c36a0eb | 125 | |
8c3a5a44 | 126 | return fdisk_get_columns(cf->cxt, 0, &cf->cols, &cf->ncols); |
5c36a0eb KZ |
127 | } |
128 | ||
8c3a5a44 KZ |
129 | /* It would be possible to use fdisk_table_to_string(), but we want some |
130 | * extension to the output format, so let's do it without libfdisk | |
131 | */ | |
132 | static char *table_to_string(struct cfdisk *cf, struct fdisk_table *tb) | |
133 | { | |
134 | struct fdisk_partition *pa; | |
135 | const struct fdisk_column *col; | |
136 | struct fdisk_label *lb; | |
137 | struct fdisk_iter *itr = NULL; | |
138 | struct tt *tt = NULL; | |
139 | char *res = NULL; | |
140 | size_t i; | |
141 | ||
142 | DBG(FRONTEND, dbgprint("table: convert to string")); | |
143 | ||
144 | assert(cf); | |
145 | assert(cf->cxt); | |
146 | assert(cf->cols); | |
147 | assert(tb); | |
148 | ||
149 | lb = fdisk_context_get_label(cf->cxt, NULL); | |
150 | assert(lb); | |
151 | ||
152 | tt = tt_new_table(TT_FL_FREEDATA | TT_FL_MAX); | |
153 | if (!tt) | |
154 | goto done; | |
155 | itr = fdisk_new_iter(FDISK_ITER_FORWARD); | |
156 | if (!itr) | |
157 | goto done; | |
5c36a0eb | 158 | |
8c3a5a44 KZ |
159 | /* headers */ |
160 | for (i = 0; i < cf->ncols; i++) { | |
161 | col = fdisk_label_get_column(lb, cf->cols[i]); | |
162 | if (col) | |
163 | tt_define_column(tt, col->name, | |
164 | col->width, | |
165 | col->tt_flags); | |
166 | } | |
167 | ||
168 | /* data */ | |
169 | while (fdisk_table_next_partition(tb, itr, &pa) == 0) { | |
170 | struct tt_line *ln = tt_add_line(tt, NULL); | |
171 | if (!ln) | |
172 | goto done; | |
173 | for (i = 0; i < cf->ncols; i++) { | |
174 | char *cdata = NULL; | |
175 | ||
176 | col = fdisk_label_get_column(lb, cf->cols[i]); | |
177 | if (!col) | |
178 | continue; | |
179 | if (fdisk_partition_to_string(pa, cf->cxt, col->id, &cdata)) | |
180 | continue; | |
181 | tt_line_set_data(ln, i, cdata); | |
182 | } | |
183 | } | |
6dbe3af9 | 184 | |
8c3a5a44 KZ |
185 | if (!tt_is_empty(tt)) { |
186 | tt_set_termreduce(tt, ARROW_CURSOR_WIDTH); | |
187 | tt_print_table_to_string(tt, &res); | |
188 | } | |
189 | done: | |
190 | tt_free_table(tt); | |
191 | fdisk_free_iter(itr); | |
6dbe3af9 | 192 | |
8c3a5a44 | 193 | return res; |
2b6fc908 KZ |
194 | } |
195 | ||
8460875d | 196 | static int lines_refresh(struct cfdisk *cf) |
8c3a5a44 KZ |
197 | { |
198 | int rc; | |
199 | char *p; | |
200 | size_t i; | |
7eda085c | 201 | |
8c3a5a44 | 202 | assert(cf); |
2b6fc908 | 203 | |
8c3a5a44 | 204 | DBG(FRONTEND, dbgprint("refresing buffer")); |
c64061c9 | 205 | |
8c3a5a44 KZ |
206 | free(cf->linesbuf); |
207 | free(cf->lines); | |
208 | cf->linesbuf = NULL; | |
209 | cf->linesbufsz = 0; | |
210 | cf->lines = NULL; | |
211 | cf->nlines = 0; | |
6dbe3af9 | 212 | |
8c3a5a44 KZ |
213 | fdisk_unref_table(cf->table); |
214 | fdisk_context_enable_freespace(cf->cxt, 1); | |
6dbe3af9 | 215 | |
8c3a5a44 KZ |
216 | rc = fdisk_get_table(cf->cxt, &cf->table); |
217 | if (rc) | |
218 | return rc; | |
0d8589c5 | 219 | |
8c3a5a44 KZ |
220 | cf->linesbuf = table_to_string(cf, cf->table); |
221 | if (!cf->linesbuf) | |
222 | return -ENOMEM; | |
6dbe3af9 | 223 | |
8c3a5a44 KZ |
224 | cf->linesbufsz = strlen(cf->linesbuf); |
225 | cf->nlines = fdisk_table_get_nents(cf->table) + 1; /* 1 for header line */ | |
6dbe3af9 | 226 | |
8c3a5a44 KZ |
227 | cf->lines = calloc(cf->nlines, sizeof(char *)); |
228 | if (!cf->lines) | |
229 | return -ENOMEM; | |
6dbe3af9 | 230 | |
8c3a5a44 KZ |
231 | for (p = cf->linesbuf, i = 0; p && i < cf->nlines; i++) { |
232 | cf->lines[i] = p; | |
233 | p = strchr(p, '\n'); | |
234 | if (p) { | |
235 | *p = '\0'; | |
236 | p++; | |
237 | } | |
238 | } | |
6dbe3af9 | 239 | |
8c3a5a44 | 240 | return 0; |
6dbe3af9 KZ |
241 | } |
242 | ||
00b4f26a KZ |
243 | static struct fdisk_partition *get_current_partition(struct cfdisk *cf) |
244 | { | |
245 | assert(cf); | |
246 | assert(cf->table); | |
247 | ||
248 | return fdisk_table_get_partition(cf->table, cf->lines_idx); | |
249 | } | |
250 | ||
8c3a5a44 KZ |
251 | static int ask_callback(struct fdisk_context *cxt, struct fdisk_ask *ask, |
252 | void *data __attribute__((__unused__))) | |
253 | { | |
254 | int rc = 0; | |
6dbe3af9 | 255 | |
8c3a5a44 KZ |
256 | assert(cxt); |
257 | assert(ask); | |
6dbe3af9 | 258 | |
8c3a5a44 KZ |
259 | switch(fdisk_ask_get_type(ask)) { |
260 | case FDISK_ASKTYPE_INFO: | |
261 | fputs(fdisk_ask_print_get_mesg(ask), stdout); | |
262 | fputc('\n', stdout); | |
263 | break; | |
264 | case FDISK_ASKTYPE_WARNX: | |
265 | fputs(fdisk_ask_print_get_mesg(ask), stderr); | |
266 | fputc('\n', stderr); | |
267 | break; | |
268 | case FDISK_ASKTYPE_WARN: | |
269 | fputs(fdisk_ask_print_get_mesg(ask), stderr); | |
270 | errno = fdisk_ask_print_get_errno(ask); | |
271 | fprintf(stderr, ": %m\n"); | |
272 | break; | |
273 | default: | |
274 | warnx(_("internal error: unsupported dialog type %d"), fdisk_ask_get_type(ask)); | |
275 | return -EINVAL; | |
276 | } | |
277 | return rc; | |
fd6b7a7f | 278 | } |
6dbe3af9 | 279 | |
6dbe3af9 | 280 | |
8c3a5a44 KZ |
281 | static int ui_end(struct cfdisk *cf) |
282 | { | |
283 | if (cf && !cf->ui_enabled) | |
284 | return -EINVAL; | |
285 | ||
48d7b13a | 286 | #if defined(HAVE_SLCURSES_H) || defined(HAVE_SLANG_SLCURSES_H) |
8c3a5a44 KZ |
287 | SLsmg_gotorc(LINES - 1, 0); |
288 | SLsmg_refresh(); | |
2b6fc908 | 289 | #else |
8c3a5a44 | 290 | mvcur(0, COLS - 1, LINES-1, 0); |
2b6fc908 | 291 | #endif |
8c3a5a44 KZ |
292 | nl(); |
293 | endwin(); | |
294 | printf("\n"); | |
295 | return 0; | |
6dbe3af9 KZ |
296 | } |
297 | ||
8c3a5a44 | 298 | static void ui_print_center(int line, const char *fmt, ...) |
f609e92e | 299 | { |
8c3a5a44 KZ |
300 | size_t width; |
301 | va_list ap; | |
302 | char *buf = NULL; | |
f609e92e | 303 | |
8c3a5a44 KZ |
304 | move(line, 0); |
305 | clrtoeol(); | |
f609e92e | 306 | |
8c3a5a44 KZ |
307 | va_start(ap, fmt); |
308 | xvasprintf(&buf, fmt, ap); | |
309 | va_end(ap); | |
fd6b7a7f | 310 | |
8c3a5a44 KZ |
311 | width = strlen(buf); /* TODO: count cells! */ |
312 | mvaddstr(line, (COLS - width) / 2, buf); | |
313 | free(buf); | |
6dbe3af9 KZ |
314 | } |
315 | ||
6dbe3af9 | 316 | |
8c3a5a44 KZ |
317 | static void die_on_signal(int dummy __attribute__((__unused__))) |
318 | { | |
319 | ui_end(NULL); | |
320 | exit(EXIT_FAILURE); | |
6dbe3af9 KZ |
321 | } |
322 | ||
8c3a5a44 KZ |
323 | static void menu_update_ignore(struct cfdisk *cf) |
324 | { | |
00b4f26a KZ |
325 | char ignore[128] = { 0 }; |
326 | int i = 0; | |
327 | struct fdisk_partition *pa; | |
8c3a5a44 KZ |
328 | struct cfdisk_menu *m; |
329 | struct cfdisk_menudesc *d; | |
6dbe3af9 | 330 | |
8c3a5a44 | 331 | assert(cf); |
6dbe3af9 | 332 | |
8c3a5a44 KZ |
333 | m = cf->menu; |
334 | DBG(FRONTEND, dbgprint("menu: update menu ignored keys")); | |
6dbe3af9 | 335 | |
8c3a5a44 KZ |
336 | switch (m->id) { |
337 | case CFDISK_MENU_MAIN: | |
00b4f26a KZ |
338 | pa = get_current_partition(cf); |
339 | if (!pa) | |
340 | break; | |
341 | if (fdisk_partition_is_freespace(pa)) { | |
342 | ignore[i++] = 'd'; /* delete */ | |
343 | ignore[i++] = 't'; /* set type */ | |
344 | ignore[i++] = 'b'; /* set bootable */ | |
345 | } else | |
346 | ignore[i++] = 'n'; | |
347 | ||
8c3a5a44 | 348 | break; |
fd6b7a7f | 349 | } |
6dbe3af9 | 350 | |
00b4f26a KZ |
351 | ignore[i] = '\0'; |
352 | ||
8c3a5a44 | 353 | /* return if no change */ |
00b4f26a KZ |
354 | if ( (!m->ignore && !*ignore) |
355 | || (m->ignore && *ignore && strcmp(m->ignore, ignore) == 0)) { | |
8c3a5a44 | 356 | return; |
fd6b7a7f | 357 | } |
6dbe3af9 | 358 | |
8c3a5a44 | 359 | free(m->ignore); |
8460875d | 360 | m->ignore = xstrdup(ignore); |
8c3a5a44 | 361 | m->nitems = 0; |
6dbe3af9 | 362 | |
8c3a5a44 KZ |
363 | for (d = m->desc; d->name; d++) { |
364 | if (m->ignore && strchr(m->ignore, d->key)) | |
8460875d KZ |
365 | continue; |
366 | m->nitems++; | |
8c3a5a44 | 367 | } |
6dbe3af9 KZ |
368 | } |
369 | ||
8c3a5a44 KZ |
370 | static struct cfdisk_menu *menu_push(struct cfdisk *cf, size_t id) |
371 | { | |
372 | struct cfdisk_menu *m = xcalloc(1, sizeof(*m)); | |
373 | struct cfdisk_menudesc *d; | |
6dbe3af9 | 374 | |
8c3a5a44 KZ |
375 | assert(cf); |
376 | assert(id < ARRAY_SIZE(menus)); | |
6dbe3af9 | 377 | |
8c3a5a44 | 378 | DBG(FRONTEND, dbgprint("menu: new menu")); |
6dbe3af9 | 379 | |
8c3a5a44 KZ |
380 | m->prev = cf->menu; |
381 | m->id = id; | |
382 | m->desc = menus[id]; | |
8460875d | 383 | m->callback = menu_callbacks[id]; |
6dbe3af9 | 384 | |
8c3a5a44 KZ |
385 | for (d = m->desc; d->name; d++) { |
386 | const char *name = _(d->name); | |
387 | size_t len = strlen(name); /* TODO: we care about cells! */ | |
388 | if (len > m->width) | |
389 | m->width = len; | |
390 | m->nitems++; | |
391 | } | |
6dbe3af9 | 392 | |
8c3a5a44 KZ |
393 | cf->menu = m; |
394 | return m; | |
6dbe3af9 KZ |
395 | } |
396 | ||
8c3a5a44 | 397 | static struct cfdisk_menu *menu_pop(struct cfdisk *cf) |
6dbe3af9 | 398 | { |
8c3a5a44 | 399 | struct cfdisk_menu *m = NULL; |
6dbe3af9 | 400 | |
8c3a5a44 | 401 | assert(cf); |
7eda085c | 402 | |
8c3a5a44 | 403 | DBG(FRONTEND, dbgprint("menu: rem menu")); |
7eda085c | 404 | |
8c3a5a44 KZ |
405 | if (cf->menu) { |
406 | m = cf->menu->prev; | |
407 | free(cf->menu->ignore); | |
408 | free(cf->menu); | |
c07ebfa1 | 409 | } |
8c3a5a44 KZ |
410 | cf->menu = m; |
411 | return cf->menu; | |
6dbe3af9 KZ |
412 | } |
413 | ||
8460875d KZ |
414 | /* returns: error: < 0, success: 0, quit: 1 */ |
415 | static int menu_cb_main(struct cfdisk *cf, int key) | |
416 | { | |
417 | switch (key) { | |
418 | case 'd': /* Delete */ | |
419 | break; | |
420 | case 'n': /* New */ | |
421 | break; | |
422 | case 'q': /* Quit */ | |
423 | return 1; | |
424 | case 't': /* Type */ | |
425 | break; | |
426 | case 'W': /* Write */ | |
427 | break; | |
428 | default: | |
429 | return -EINVAL; | |
430 | } | |
431 | return 0; | |
432 | } | |
7eda085c | 433 | |
8c3a5a44 KZ |
434 | static int ui_init(struct cfdisk *cf) |
435 | { | |
436 | struct sigaction sa; | |
6dbe3af9 | 437 | |
8c3a5a44 | 438 | DBG(FRONTEND, dbgprint("ui: init")); |
6dbe3af9 | 439 | |
8c3a5a44 KZ |
440 | /* setup SIGCHLD handler */ |
441 | sigemptyset(&sa.sa_mask); | |
442 | sa.sa_flags = 0; | |
443 | sa.sa_handler = die_on_signal; | |
444 | sigaction(SIGINT, &sa, NULL); | |
445 | sigaction(SIGTERM, &sa, NULL); | |
6dbe3af9 | 446 | |
8c3a5a44 KZ |
447 | cf->ui_enabled = 1; |
448 | initscr(); | |
6dbe3af9 | 449 | |
8c3a5a44 KZ |
450 | cbreak(); |
451 | noecho(); | |
452 | nonl(); | |
453 | curs_set(0); | |
454 | keypad(stdscr, TRUE); | |
6dbe3af9 | 455 | |
8c3a5a44 | 456 | return 0; |
7eda085c KZ |
457 | } |
458 | ||
8c3a5a44 KZ |
459 | static size_t menuitem_get_line(struct cfdisk *cf, size_t idx) |
460 | { | |
461 | size_t len = cf->menu->width + 4 + MENU_PADDING; /* item width */ | |
462 | size_t items = COLS / len; /* items per line */ | |
7eda085c | 463 | |
8c3a5a44 | 464 | return MENU_START_LINE + ((idx / items)); |
7eda085c KZ |
465 | } |
466 | ||
8c3a5a44 KZ |
467 | static int menuitem_get_column(struct cfdisk *cf, size_t idx) |
468 | { | |
469 | size_t len = cf->menu->width + 4 + MENU_PADDING; /* item width */ | |
470 | size_t items = COLS / len; /* items per line */ | |
471 | size_t extra = items < cf->menu->nitems ? /* extra space on line */ | |
472 | COLS % len : /* - multi-line menu */ | |
473 | COLS - (cf->menu->nitems * len); /* - one line menu */ | |
df1dddf9 | 474 | |
8c3a5a44 | 475 | extra += MENU_PADDING; /* add padding after last item to extra */ |
e66ac5d3 | 476 | |
8c3a5a44 KZ |
477 | if (idx < items) |
478 | return (idx * len) + (extra / 2); | |
479 | return ((idx % items) * len) + (extra / 2); | |
df1dddf9 KZ |
480 | } |
481 | ||
8c3a5a44 KZ |
482 | static struct cfdisk_menudesc *menu_get_menuitem(struct cfdisk *cf, size_t idx) |
483 | { | |
484 | struct cfdisk_menudesc *d; | |
485 | size_t i; | |
7eda085c | 486 | |
8c3a5a44 KZ |
487 | for (i = 0, d = cf->menu->desc; d->name; d++) { |
488 | if (cf->menu->ignore && strchr(cf->menu->ignore, d->key)) | |
489 | continue; | |
490 | if (i++ == idx) | |
491 | return d; | |
d26aa358 | 492 | } |
7eda085c | 493 | |
8c3a5a44 | 494 | return NULL; |
6dbe3af9 KZ |
495 | } |
496 | ||
8c3a5a44 KZ |
497 | static void ui_draw_menuitem(struct cfdisk *cf, |
498 | struct cfdisk_menudesc *d, | |
499 | size_t idx) | |
500 | { | |
501 | char buf[80 * MB_CUR_MAX]; | |
502 | const char *name; | |
503 | size_t width = cf->menu->width + 2; /* 2 = blank around string */ | |
504 | int ln, cl; | |
505 | ||
506 | name = _(d->name); | |
507 | mbsalign(name, buf, sizeof(buf), &width, MBS_ALIGN_CENTER, 0); | |
508 | ||
509 | ln = menuitem_get_line(cf, idx); | |
510 | cl = menuitem_get_column(cf, idx); | |
511 | ||
512 | DBG(FRONTEND, dbgprint("ui: menuitem: cl=%d, ln=%d, item='%s'", | |
513 | cl, ln, buf)); | |
514 | ||
515 | if (cf->menu_idx == idx) { | |
516 | standout(); | |
517 | mvprintw(ln, cl, "[%s]", buf); | |
518 | standend(); | |
519 | if (d->desc) | |
520 | ui_print_center(LINES - 1, d->desc); | |
521 | } else | |
522 | mvprintw(ln, cl, "[%s]", buf); | |
6dbe3af9 KZ |
523 | } |
524 | ||
8c3a5a44 KZ |
525 | static void ui_draw_menu(struct cfdisk *cf) |
526 | { | |
527 | struct cfdisk_menudesc *d; | |
528 | size_t i = 0; | |
7eda085c | 529 | |
8c3a5a44 KZ |
530 | assert(cf); |
531 | assert(cf->menu); | |
fd6b7a7f | 532 | |
8c3a5a44 | 533 | DBG(FRONTEND, dbgprint("ui: menu: draw start")); |
6dbe3af9 | 534 | |
00b4f26a KZ |
535 | for (i = MENU_START_LINE; i < (size_t) LINES - 1; i++) { |
536 | move(i, 0); | |
537 | clrtoeol(); | |
538 | } | |
539 | ||
8c3a5a44 | 540 | menu_update_ignore(cf); |
6dbe3af9 | 541 | |
00b4f26a | 542 | i = 0; |
8c3a5a44 KZ |
543 | while ((d = menu_get_menuitem(cf, i))) |
544 | ui_draw_menuitem(cf, d, i++); | |
6dbe3af9 | 545 | |
8c3a5a44 | 546 | DBG(FRONTEND, dbgprint("ui: menu: draw end.")); |
6dbe3af9 KZ |
547 | } |
548 | ||
8c3a5a44 KZ |
549 | static void ui_menu_goto(struct cfdisk *cf, int where) |
550 | { | |
551 | struct cfdisk_menudesc *d; | |
552 | size_t old; | |
553 | ||
554 | if (where < 0) | |
555 | where = cf->menu->nitems - 1; | |
556 | else if ((size_t) where > cf->menu->nitems - 1) | |
557 | where = 0; | |
558 | if ((size_t) where == cf->menu_idx) | |
559 | return; | |
6dbe3af9 | 560 | |
8c3a5a44 KZ |
561 | old = cf->menu_idx; |
562 | cf->menu_idx = where; | |
6dbe3af9 | 563 | |
8c3a5a44 KZ |
564 | d = menu_get_menuitem(cf, old); |
565 | ui_draw_menuitem(cf, d, old); | |
6dbe3af9 | 566 | |
8c3a5a44 KZ |
567 | d = menu_get_menuitem(cf, where); |
568 | ui_draw_menuitem(cf, d, where); | |
6dbe3af9 KZ |
569 | } |
570 | ||
8460875d | 571 | /* returns: error: < 0, success: 0, quit: 1 */ |
8c3a5a44 KZ |
572 | static int ui_menu_action(struct cfdisk *cf, int key) |
573 | { | |
8460875d KZ |
574 | assert(cf); |
575 | assert(cf->menu); | |
576 | assert(cf->menu->callback); | |
577 | ||
578 | if (key == 0) { | |
579 | struct cfdisk_menudesc *d = menu_get_menuitem(cf, cf->menu_idx); | |
580 | if (!d) | |
581 | return 0; | |
582 | key = d->key; | |
00b4f26a KZ |
583 | |
584 | } else if (key != 'w' && key != 'W') | |
585 | key = tolower(key); /* case insensitive except 'W'rite */ | |
8460875d KZ |
586 | |
587 | DBG(FRONTEND, dbgprint("ui: menu action: key=%c", key)); | |
588 | ||
589 | if (cf->menu->ignore && strchr(cf->menu->ignore, key)) { | |
590 | DBG(FRONTEND, dbgprint(" ignore '%c'", key)); | |
591 | return 0; | |
592 | } | |
593 | ||
594 | return cf->menu->callback(cf, key); | |
6dbe3af9 KZ |
595 | } |
596 | ||
8c3a5a44 KZ |
597 | static void ui_draw_partition(struct cfdisk *cf, size_t i) |
598 | { | |
599 | int ln = TABLE_START_LINE + 1 + i; /* skip table header */ | |
600 | int cl = ARROW_CURSOR_WIDTH; /* we need extra space for cursor */ | |
6dbe3af9 | 601 | |
8c3a5a44 | 602 | DBG(FRONTEND, dbgprint("ui: draw partition %zu", i)); |
6dbe3af9 | 603 | |
8c3a5a44 KZ |
604 | if (cf->lines_idx == i) { |
605 | standout(); | |
606 | mvaddstr(ln, 0, ARROW_CURSOR_STRING); | |
607 | mvaddstr(ln, cl, cf->lines[i + 1]); | |
608 | standend(); | |
6dbe3af9 | 609 | } else { |
8c3a5a44 KZ |
610 | mvaddstr(ln, 0, ARROW_CURSOR_DUMMY); |
611 | mvaddstr(ln, cl, cf->lines[i + 1]); | |
6dbe3af9 KZ |
612 | } |
613 | ||
6dbe3af9 KZ |
614 | } |
615 | ||
8c3a5a44 KZ |
616 | static int ui_draw_table(struct cfdisk *cf) |
617 | { | |
618 | int cl = ARROW_CURSOR_WIDTH; | |
619 | size_t i, nparts = fdisk_table_get_nents(cf->table); | |
7eda085c | 620 | |
8c3a5a44 | 621 | DBG(FRONTEND, dbgprint("ui: draw table")); |
6dbe3af9 | 622 | |
8c3a5a44 KZ |
623 | if (cf->nlines - 2 < cf->lines_idx) |
624 | cf->lines_idx = cf->nlines - 2; /* don't count header */ | |
6dbe3af9 | 625 | |
8c3a5a44 KZ |
626 | /* print header */ |
627 | attron(A_BOLD); | |
628 | mvaddstr(TABLE_START_LINE, cl, cf->lines[0]); | |
629 | attroff(A_BOLD); | |
6dbe3af9 | 630 | |
8c3a5a44 KZ |
631 | /* print partitions */ |
632 | for (i = 0; i < nparts; i++) | |
633 | ui_draw_partition(cf, i); | |
6dbe3af9 | 634 | |
8c3a5a44 | 635 | return 0; |
6dbe3af9 KZ |
636 | } |
637 | ||
8c3a5a44 KZ |
638 | static int ui_table_goto(struct cfdisk *cf, int where) |
639 | { | |
640 | size_t old; | |
641 | size_t nparts = fdisk_table_get_nents(cf->table); | |
6dbe3af9 | 642 | |
8c3a5a44 | 643 | DBG(FRONTEND, dbgprint("ui: goto table %d", where)); |
6dbe3af9 | 644 | |
8c3a5a44 KZ |
645 | if (where < 0) |
646 | where = 0; | |
647 | else if ((size_t) where > nparts - 1) | |
648 | where = nparts - 1; | |
6dbe3af9 | 649 | |
8c3a5a44 KZ |
650 | if ((size_t) where == cf->lines_idx) |
651 | return 0; | |
6dbe3af9 | 652 | |
8c3a5a44 KZ |
653 | old = cf->lines_idx; |
654 | cf->lines_idx = where; | |
6dbe3af9 | 655 | |
8c3a5a44 KZ |
656 | ui_draw_partition(cf, old); /* cleanup old */ |
657 | ui_draw_partition(cf, where); /* draw new */ | |
658 | ui_draw_menu(cf); | |
659 | refresh(); | |
660 | return 0; | |
6dbe3af9 KZ |
661 | } |
662 | ||
8c3a5a44 KZ |
663 | static int ui_refresh(struct cfdisk *cf) |
664 | { | |
665 | char *id = NULL; | |
666 | uint64_t bytes = cf->cxt->total_sectors * cf->cxt->sector_size; | |
667 | char *strsz = size_to_human_string(SIZE_SUFFIX_SPACE | |
668 | | SIZE_SUFFIX_3LETTER, bytes); | |
669 | erase(); | |
670 | ||
671 | if (!cf->ui_enabled) | |
672 | return -EINVAL; | |
673 | ||
674 | /* header */ | |
675 | attron(A_BOLD); | |
676 | ui_print_center(0, _("Disk: %s"), cf->cxt->dev_path); | |
677 | attroff(A_BOLD); | |
678 | ui_print_center(1, _("Size: %s, %ju bytes, %ju sectors"), | |
679 | strsz, bytes, (uintmax_t) cf->cxt->total_sectors); | |
680 | if (fdisk_get_disklabel_id(cf->cxt, &id) == 0 && id) | |
681 | ui_print_center(2, _("Label: %s, identifier: %s"), | |
682 | cf->cxt->label->name, id); | |
7eda085c | 683 | else |
8c3a5a44 KZ |
684 | ui_print_center(2, _("Label: %s")); |
685 | free(strsz); | |
6dbe3af9 | 686 | |
8c3a5a44 KZ |
687 | ui_draw_table(cf); |
688 | ui_draw_menu(cf); | |
6dbe3af9 | 689 | refresh(); |
8c3a5a44 | 690 | return 0; |
6dbe3af9 KZ |
691 | } |
692 | ||
8c3a5a44 KZ |
693 | static int ui_run(struct cfdisk *cf) |
694 | { | |
695 | int rc; | |
6dbe3af9 | 696 | |
8c3a5a44 | 697 | DBG(FRONTEND, dbgprint("ui: start COLS=%d, LINES=%d", COLS, LINES)); |
6dbe3af9 | 698 | |
8c3a5a44 | 699 | menu_push(cf, CFDISK_MENU_MAIN); |
6dbe3af9 | 700 | |
8c3a5a44 KZ |
701 | rc = ui_refresh(cf); |
702 | if (rc) | |
703 | return rc; | |
6dbe3af9 | 704 | |
8c3a5a44 | 705 | do { |
8460875d | 706 | int rc = 0, key = getch(); |
6dbe3af9 | 707 | |
8c3a5a44 KZ |
708 | switch (key) { |
709 | case KEY_DOWN: | |
710 | case '\016': /* ^N */ | |
711 | case 'j': /* Vi-like alternative */ | |
712 | ui_table_goto(cf, cf->lines_idx + 1); | |
713 | break; | |
714 | case KEY_UP: | |
715 | case '\020': /* ^P */ | |
716 | case 'k': /* Vi-like alternative */ | |
717 | ui_table_goto(cf, cf->lines_idx - 1); | |
718 | break; | |
719 | case KEY_HOME: | |
720 | ui_table_goto(cf, 0); | |
721 | break; | |
722 | case KEY_END: | |
723 | ui_table_goto(cf, cf->nlines - 1); | |
724 | break; | |
725 | ui_menu_action(cf, 0); | |
726 | break; | |
727 | case KEY_LEFT: | |
728 | #ifdef KEY_BTAB | |
729 | case KEY_BTAB: | |
6dbe3af9 | 730 | #endif |
8c3a5a44 KZ |
731 | ui_menu_goto(cf, cf->menu_idx - 1); |
732 | break; | |
733 | case KEY_RIGHT: | |
734 | case '\t': | |
735 | ui_menu_goto(cf, cf->menu_idx + 1); | |
736 | break; | |
737 | case KEY_ENTER: | |
738 | case '\n': | |
739 | case '\r': | |
8460875d | 740 | rc = ui_menu_action(cf, 0); |
8c3a5a44 KZ |
741 | break; |
742 | default: | |
8460875d KZ |
743 | rc = ui_menu_action(cf, key); |
744 | if (rc < 0) | |
8c3a5a44 KZ |
745 | beep(); |
746 | break; | |
747 | } | |
8460875d KZ |
748 | |
749 | if (rc == 1) | |
750 | break; /* quit */ | |
8c3a5a44 | 751 | } while (1); |
6dbe3af9 | 752 | |
8c3a5a44 | 753 | menu_pop(cf); |
6dbe3af9 | 754 | |
8c3a5a44 KZ |
755 | DBG(FRONTEND, dbgprint("ui: end")); |
756 | ||
757 | return 0; | |
758 | } | |
6dbe3af9 | 759 | |
8c3a5a44 KZ |
760 | int main(int argc, char *argv[]) |
761 | { | |
762 | struct cfdisk _cf = { .lines_idx = 0 }, | |
763 | *cf = &_cf; | |
6dbe3af9 | 764 | |
8c3a5a44 KZ |
765 | setlocale(LC_ALL, ""); |
766 | bindtextdomain(PACKAGE, LOCALEDIR); | |
767 | textdomain(PACKAGE); | |
768 | atexit(close_stdout); | |
6dbe3af9 | 769 | |
8c3a5a44 KZ |
770 | fdisk_init_debug(0); |
771 | cf->cxt = fdisk_new_context(); | |
772 | if (!cf->cxt) | |
773 | err(EXIT_FAILURE, _("failed to allocate libfdisk context")); | |
6dbe3af9 | 774 | |
8c3a5a44 KZ |
775 | fdisk_context_set_ask(cf->cxt, ask_callback, (void *) cf); |
776 | fdisk_context_enable_freespace(cf->cxt, 1); | |
6dbe3af9 | 777 | |
8c3a5a44 KZ |
778 | if (argc != 2) |
779 | err(EXIT_FAILURE, "usage: %s <device>", argv[0]); | |
6dbe3af9 | 780 | |
8c3a5a44 KZ |
781 | if (fdisk_context_assign_device(cf->cxt, argv[optind], 0) != 0) |
782 | err(EXIT_FAILURE, _("cannot open %s"), argv[optind]); | |
6dbe3af9 | 783 | |
8c3a5a44 | 784 | cols_init(cf); |
fd6b7a7f | 785 | |
8460875d | 786 | if (lines_refresh(cf)) |
8c3a5a44 | 787 | errx(EXIT_FAILURE, _("failed to read partitions")); |
6dbe3af9 | 788 | |
8c3a5a44 KZ |
789 | /* Don't use err(), warn() from this point */ |
790 | ui_init(cf); | |
791 | ui_run(cf); | |
792 | ui_end(cf); | |
6dbe3af9 | 793 | |
8c3a5a44 KZ |
794 | free(cf->lines); |
795 | free(cf->linesbuf); | |
796 | fdisk_unref_table(cf->table); | |
797 | fdisk_free_context(cf->cxt); | |
798 | return EXIT_SUCCESS; | |
6dbe3af9 | 799 | } |