]> git.ipfire.org Git - thirdparty/util-linux.git/blame - fdisks/fdisk-menu.c
libfdisk: clean up sun geometry stuff
[thirdparty/util-linux.git] / fdisks / fdisk-menu.c
CommitLineData
161b0d1a
KZ
1
2#include <stdio.h>
3#include <stdlib.h>
4#include <string.h>
5#include <ctype.h>
6#include <stdint.h>
7
8#include "c.h"
9#include "fdisk.h"
10
11struct menu_entry {
12 const char key;
13 const char *title;
14 unsigned int normal : 1,
15 expert : 1,
16 hidden : 1;
17
18 enum fdisk_labeltype exclude;
19};
20
21#define IS_MENU_SEP(e) ((e)->key == '-')
22#define IS_MENU_HID(e) ((e)->hidden)
23
24struct menu {
25 enum fdisk_labeltype label; /* only for this label */
26 enum fdisk_labeltype exclude; /* all labels except this */
27
a410f8df
KZ
28 int (*callback)(struct fdisk_context *,
29 const struct menu *,
30 const struct menu_entry *);
161b0d1a
KZ
31
32 struct menu_entry entries[]; /* NULL terminated array */
33};
34
35struct menu_context {
36 size_t menu_idx; /* the current menu */
37 size_t entry_idx; /* index with in the current menu */
38};
39
40#define MENU_CXT_EMPTY { 0, 0 }
41
b9e94cd7
KZ
42static int gpt_menu_cb(struct fdisk_context *cxt,
43 const struct menu *menu,
44 const struct menu_entry *ent);
45
161b0d1a
KZ
46/*
47 * Menu entry macros:
48 * MENU_X* expert mode only
49 * MENU_B* both -- expert + normal mode
50 *
51 * *_E exclude
52 * *_H hidden
53 */
54
55/* separator */
56#define MENU_SEP(t) { .title = t, .key = '-', .normal = 1 }
57#define MENU_XSEP(t) { .title = t, .key = '-', .expert = 1 }
58#define MENU_BSEP(t) { .title = t, .key = '-', .expert = 1, .normal = 1 }
59
60/* entry */
61#define MENU_ENT(k, t) { .title = t, .key = k, .normal = 1 }
62#define MENU_ENT_E(k, t, l) { .title = t, .key = k, .normal = 1, .exclude = l }
63
64#define MENU_XENT(k, t) { .title = t, .key = k, .expert = 1 }
65#define MENU_XENT_H(k, t) { .title = t, .key = k, .expert = 1, .hidden = 1 }
66
67#define MENU_BENT(k, t) { .title = t, .key = k, .expert = 1, .normal = 1 }
68
69
70/* Generic menu */
71struct menu menu_generic = {
72/* .callback = generic_menu_cb,*/
73 .entries = {
6ae5e1e0 74 MENU_BSEP(N_("Generic")),
161b0d1a
KZ
75 MENU_ENT ('d', N_("delete a partition")),
76 MENU_ENT ('l', N_("list known partition types")),
77 MENU_ENT ('n', N_("add a new partition")),
78 MENU_BENT ('p', N_("print the partition table")),
6ae5e1e0 79 MENU_ENT ('t', N_("change a partition type")),
161b0d1a
KZ
80 MENU_ENT ('v', N_("verify the partition table")),
81
6ae5e1e0
KZ
82 MENU_XENT('d', N_("print the raw data of the first sector")),
83
161b0d1a
KZ
84 MENU_SEP(N_("Misc")),
85 MENU_BENT ('m', N_("print this menu")),
86 MENU_ENT_E('u', N_("change display/entry units"), FDISK_DISKLABEL_GPT),
87 MENU_ENT ('x', N_("extra functionality (experts only)")),
88
2a1a67df 89 MENU_BSEP(N_("Save & Exit")),
161b0d1a
KZ
90 MENU_ENT_E('w', N_("write table to disk and exit"), FDISK_DISKLABEL_OSF),
91 MENU_BENT ('q', N_("quit without saving changes")),
92 MENU_XENT ('r', N_("return to main menu")),
93
94 { 0, NULL }
95 }
96};
97
98struct menu menu_createlabel = {
99/* .callback = createlabel_menu_cb, */
100 .exclude = FDISK_DISKLABEL_OSF,
101 .entries = {
102 MENU_SEP(N_("Create a new label")),
103 MENU_ENT('g', N_("create a new empty GPT partition table")),
104 MENU_ENT('G', N_("create a new empty SGI (IRIX) partition table")),
105 MENU_ENT('o', N_("create a new empty DOS partition table")),
106 MENU_ENT('s', N_("create a new empty Sun partition table")),
107
108 /* backward compatibility -- be sensitive to 'g', but don't
109 * print it in the expert menu */
110 MENU_XENT_H('g', N_("create an IRIX (SGI) partition table")),
111 { 0, NULL }
112 }
113};
114
115struct menu menu_gpt = {
b9e94cd7 116 .callback = gpt_menu_cb,
161b0d1a
KZ
117 .label = FDISK_DISKLABEL_GPT,
118 .entries = {
119 MENU_XSEP(N_("GPT")),
120 MENU_XENT('u', N_("change partition UUID")),
121 MENU_XENT('n', N_("change partition name")),
122 { 0, NULL }
123 }
124};
125
2a1a67df
KZ
126struct menu menu_sun = {
127/* .callback = sun_menu_cb, */
128 .label = FDISK_DISKLABEL_SUN,
129 .entries = {
130 MENU_BSEP(N_("Sun")),
131 MENU_ENT('a', N_("toggle a read only flag")),
132 MENU_ENT('c', N_("toggle the mountable flag")),
133
134 MENU_XENT('a', N_("change number of alternate cylinders")),
135 MENU_XENT('c', N_("change number of cylinders")),
136 MENU_XENT('e', N_("change number of extra sectors per cylinder")),
137 MENU_XENT('h', N_("change number of heads")),
138 MENU_XENT('i', N_("change interleave factor")),
139 MENU_XENT('o', N_("change rotation speed (rpm)")),
140 MENU_XENT('s', N_("change number of sectors/track")),
141 MENU_XENT('y', N_("change number of physical cylinders")),
142 { 0, NULL }
143 }
144};
145
6ae5e1e0
KZ
146struct menu menu_sgi = {
147/* .callback = sgi_menu_cb, */
148 .label = FDISK_DISKLABEL_SGI,
149 .entries = {
150 MENU_SEP(N_("SGI")),
151 MENU_ENT('a', N_("select bootable partition")),
152 MENU_ENT('b', N_("edit bootfile entry")),
153 MENU_ENT('c', N_("select sgi swap partition")),
154 { 0, NULL }
155 }
156};
157
158struct menu menu_dos = {
159/* .callback = dos_menu_cb, */
160 .label = FDISK_DISKLABEL_DOS,
161 .entries = {
162 MENU_BSEP(N_("DOS (MBR)")),
163 MENU_ENT('a', N_("toggle a bootable flag")),
164 MENU_ENT('b', N_("edit nested BSD disklabel")),
165 MENU_ENT('c', N_("toggle the dos compatibility flag")),
166
167 MENU_XENT('b', N_("move beginning of data in a partition")),
168 MENU_XENT('c', N_("change number of cylinders")), MENU_XENT('e', N_("list extended partitions")),
169 MENU_XENT('f', N_("fix partition order")),
170 MENU_XENT('h', N_("change number of heads")),
171 MENU_XENT('i', N_("change the disk identifier")),
172 MENU_XENT('s', N_("change number of sectors/track")),
173 { 0, NULL }
174 }
175};
176
177struct menu menu_bsd = {
178/* .callback = bsd_menu_cb, */
179 .label = FDISK_DISKLABEL_OSF,
180 .entries = {
181 MENU_SEP(N_("BSD")),
182 MENU_ENT('e', N_("edit drive data")),
183 MENU_ENT('i', N_("install bootstrap")),
184 MENU_ENT('s', N_("show complete disklabel")),
185 MENU_ENT('w', N_("write disklabel to disk")),
186#if !defined (__alpha__)
187 MENU_ENT('x', N_("link BSD partition to non-BSD partition")),
188#endif
189 { 0, NULL }
190 }
191};
192
161b0d1a 193static const struct menu *menus[] = {
6ae5e1e0
KZ
194 &menu_gpt,
195 &menu_sun,
196 &menu_sgi,
197 &menu_dos,
198 &menu_bsd,
161b0d1a
KZ
199 &menu_generic,
200 &menu_createlabel,
161b0d1a
KZ
201};
202
203static const struct menu_entry *next_menu_entry(
204 struct fdisk_context *cxt,
205 struct menu_context *mc)
206{
207 while (mc->menu_idx < ARRAY_SIZE(menus)) {
208 const struct menu *m = menus[mc->menu_idx];
209 const struct menu_entry *e = &(m->entries[mc->entry_idx]);
210
211 /* move to the next submenu if there is no more entries */
212 if (e->title == NULL ||
213 (m->label && cxt->label && !(m->label & cxt->label->id))) {
214 mc->menu_idx++;
215 mc->entry_idx = 0;
216 continue;
217 }
218
219 /* is the entry excluded for the current label? */
220 if ((e->exclude && cxt->label &&
221 e->exclude & cxt->label->id) ||
222 /* exclude non-expert entries in expect mode */
223 (e->expert == 0 && fdisk_context_display_details(cxt)) ||
224 /* exclude non-normal entries in normal mode */
225 (e->normal == 0 && !fdisk_context_display_details(cxt))) {
226
227 mc->entry_idx++;
228 continue;
229 }
230 mc->entry_idx++;
231 return e;
232
233 }
234 return NULL;
235}
236
3b4f9f16
KZ
237/* returns @menu and menu entry for then @key */
238static const struct menu_entry *get_fdisk_menu_entry(
239 struct fdisk_context *cxt,
240 int key,
241 const struct menu **menu)
242{
243 struct menu_context mc = MENU_CXT_EMPTY;
244 const struct menu_entry *e;
245
246 while ((e = next_menu_entry(cxt, &mc))) {
247 if (IS_MENU_SEP(e) || e->key != key)
248 continue;
249
250 if (menu)
251 *menu = menus[mc.menu_idx];
252 return e;
253 }
254
255 return NULL;
256}
257
258static int menu_detect_collisions(struct fdisk_context *cxt)
259{
260 struct menu_context mc = MENU_CXT_EMPTY;
261 const struct menu_entry *e, *r;
262
263 while ((e = next_menu_entry(cxt, &mc))) {
264 if (IS_MENU_SEP(e))
265 continue;
266
267 r = get_fdisk_menu_entry(cxt, e->key, NULL);
268 if (!r) {
36050e70 269 DBG(FRONTEND, dbgprint("warning: not found "
3b4f9f16
KZ
270 "entry for %c", e->key));
271 return -1;
272 }
273 if (r != e) {
36050e70 274 DBG(FRONTEND, dbgprint("warning: duplicate key '%c'",
3b4f9f16 275 e->key));
36050e70
KZ
276 DBG(FRONTEND, dbgprint(" %s", e->title));
277 DBG(FRONTEND, dbgprint(" %s", r->title));
3b4f9f16
KZ
278 abort();
279 }
280 }
281
282 return 0;
283}
284
39f01b7b 285int print_fdisk_menu(struct fdisk_context *cxt)
161b0d1a
KZ
286{
287 struct menu_context mc = MENU_CXT_EMPTY;
288 const struct menu_entry *e;
289
36050e70 290 ON_DBG(FRONTEND, menu_detect_collisions(cxt));
3b4f9f16 291
161b0d1a 292 if (fdisk_context_display_details(cxt))
39f01b7b 293 printf(_("\nHelp (expert commands):\n"));
161b0d1a 294 else
39f01b7b 295 printf(_("\nHelp:\n"));
161b0d1a
KZ
296
297 while ((e = next_menu_entry(cxt, &mc))) {
298 if (IS_MENU_HID(e))
299 continue; /* hidden entry */
300 if (IS_MENU_SEP(e))
301 printf("\n %s\n", _(e->title));
302 else
303 printf(" %c %s\n", e->key, _(e->title));
304 }
305 fputc('\n', stdout);
306
307 return 0;
308}
309
a410f8df
KZ
310/* Asks for command, verify the key and perform the command or
311 * returns the command key if no callback for the command is
312 * implemented.
313 *
314 * Returns: <0 on error
315 * 0 on success (the command performed)
316 * >0 if no callback (then returns the key)
317 */
318int process_fdisk_menu(struct fdisk_context *cxt)
319{
320 const struct menu_entry *ent;
321 const struct menu *menu;
322 int key, rc;
323 const char *prompt;
324 char buf[BUFSIZ];
325
326 if (fdisk_context_display_details(cxt))
327 prompt = _("Expert command (m for help): ");
328 else
329 prompt = _("Command (m for help): ");
330
331 fputc('\n',stdout);
332 rc = get_user_reply(cxt, prompt, buf, sizeof(buf));
333 if (rc)
334 return rc;
335
336 key = buf[0];
337 ent = get_fdisk_menu_entry(cxt, key, &menu);
338 if (!ent) {
339 fdisk_warnx(cxt, _("%c: unknown command"), key);
340 return -EINVAL;
341 }
342
36050e70 343 DBG(FRONTEND, dbgprint("selected: key=%c, entry='%s'",
a410f8df
KZ
344 key, ent->title));
345 /* hardcoded help */
346 if (key == 'm') {
347 print_fdisk_menu(cxt);
348 return 0;
349
350 /* menu has implemented callback, use it */
351 } else if (menu->callback)
352 return menu->callback(cxt, menu, ent);
353
354 /* no callback, return the key */
355 return key;
356}
357
b9e94cd7
KZ
358/*
359 * This is fdisk frontend for GPT specific libfdisk functions that
360 * are not expported by generic libfdisk API.
361 */
362static int gpt_menu_cb(struct fdisk_context *cxt,
363 const struct menu *menu __attribute__((__unused__)),
364 const struct menu_entry *ent)
365{
366 size_t n;
367 int rc;
368
369 assert(cxt);
370 assert(ent);
371 assert(fdisk_is_disklabel(cxt, GPT));
372
36050e70 373 DBG(FRONTEND, dbgprint("enter GPT menu"));
b9e94cd7
KZ
374
375 rc = fdisk_ask_partnum(cxt, &n, FALSE);
376 if (rc)
377 return rc;
378
379 switch(ent->key) {
380 case 'u':
381 rc = fdisk_gpt_partition_set_uuid(cxt, n);
382 break;
383 case 'n':
1054699c 384 rc = fdisk_gpt_partition_set_name(cxt, n);
b9e94cd7
KZ
385 break;
386 }
387 return rc;
388}
389
a410f8df 390
161b0d1a
KZ
391#ifdef TEST_PROGRAM
392struct fdisk_label *fdisk_new_dos_label(struct fdisk_context *cxt) { return NULL; }
393struct fdisk_label *fdisk_new_bsd_label(struct fdisk_context *cxt) { return NULL; }
394struct fdisk_label *fdisk_new_mac_label(struct fdisk_context *cxt) { return NULL; }
395struct fdisk_label *fdisk_new_sgi_label(struct fdisk_context *cxt) { return NULL; }
396
397int main(int argc, char *argv[])
398{
399 struct fdisk_context *cxt;
400 int idx = 1;
401
402 fdisk_init_debug(0);
403 cxt = fdisk_new_context();
404
405 if (argc > idx && strcmp(argv[idx], "--expert") == 0) {
406 fdisk_context_enable_details(cxt, 1);
407 idx++;
408 }
409 fdisk_context_switch_label(cxt, argc > idx ? argv[idx] : "gpt");
410
411 print_fdisk_menu(cxt);
412 return 0;
413}
414#endif