]>
Commit | Line | Data |
---|---|---|
fd6b7a7f | 1 | /* |
fd6b7a7f | 2 | * Copyright (C) 1995 Andries E. Brouwer (aeb@cwi.nl) |
1881390d | 3 | * Copyright (C) 2014 Karel Zak <kzak@redhat.com> |
fd6b7a7f KZ |
4 | * |
5 | * This program is free software. You can redistribute it and/or | |
6 | * modify it under the terms of the GNU General Public License | |
7 | * as published by the Free Software Foundation: either Version 1 | |
8 | * or (at your option) any later version. | |
9 | * | |
10 | * A.V. Le Blanc (LeBlanc@mcc.ac.uk) wrote Linux fdisk 1992-1994, | |
11 | * patched by various people (faith@cs.unc.edu, martin@cs.unc.edu, | |
12 | * leisner@sdsp.mc.xerox.com, esr@snark.thyrsus.com, aeb@cwi.nl) | |
13 | * 1993-1995, with version numbers (as far as I have seen) 0.93 - 2.0e. | |
14 | * This program had (head,sector,cylinder) as basic unit, and was | |
15 | * (therefore) broken in several ways for the use on larger disks - | |
16 | * for example, my last patch (from 2.0d to 2.0e) was required | |
17 | * to allow a partition to cross cylinder 8064, and to write an | |
18 | * extended partition past the 4GB mark. | |
19 | * | |
1881390d KZ |
20 | * Karel Zak wrote new sfdisk based on libfdisk from util-linux |
21 | * in 2014. | |
fd6b7a7f KZ |
22 | */ |
23 | ||
1881390d | 24 | #include <unistd.h> |
fd6b7a7f | 25 | #include <stdio.h> |
1881390d KZ |
26 | #include <stdlib.h> |
27 | #include <string.h> | |
fd6b7a7f | 28 | #include <ctype.h> |
1881390d | 29 | #include <errno.h> |
fd6b7a7f | 30 | #include <getopt.h> |
fd6b7a7f | 31 | #include <sys/stat.h> |
9c1f9dd3 | 32 | #include <assert.h> |
11ef0c35 KZ |
33 | |
34 | #include "c.h" | |
109dbc4f | 35 | #include "xalloc.h" |
1881390d KZ |
36 | #include "nls.h" |
37 | #include "debug.h" | |
9912f01b | 38 | #include "strutils.h" |
1881390d | 39 | #include "closestream.h" |
9c1f9dd3 | 40 | #include "colors.h" |
d2eb1457 | 41 | #include "blkdev.h" |
fd6b7a7f | 42 | |
1881390d | 43 | #include "libfdisk.h" |
9c1f9dd3 | 44 | #include "fdisk-list.h" |
fd6b7a7f KZ |
45 | |
46 | /* | |
1881390d | 47 | * sfdisk debug stuff (see fdisk.h and include/debug.h) |
fd6b7a7f | 48 | */ |
1881390d KZ |
49 | UL_DEBUG_DEFINE_MASK(sfdisk); |
50 | UL_DEBUG_DEFINE_MASKANEMS(sfdisk) = UL_DEBUG_EMPTY_MASKNAMES; | |
fd6b7a7f | 51 | |
1881390d KZ |
52 | #define SFDISKPROG_DEBUG_INIT (1 << 1) |
53 | #define SFDISKPROG_DEBUG_PARSE (1 << 2) | |
54 | #define SFDISKPROG_DEBUG_MISC (1 << 3) | |
e8813494 | 55 | #define SFDISKPROG_DEBUG_ASK (1 << 4) |
1881390d | 56 | #define SFDISKPROG_DEBUG_ALL 0xFFFF |
fd6b7a7f | 57 | |
1881390d KZ |
58 | #define DBG(m, x) __UL_DBG(sfdisk, SFDISKPROG_DEBUG_, m, x) |
59 | #define ON_DBG(m, x) __UL_DBG_CALL(sfdisk, SFDISKPROG_DEBUG_, m, x) | |
fd6b7a7f | 60 | |
9c1f9dd3 KZ |
61 | enum { |
62 | ACT_FDISK = 0, /* default */ | |
63 | ||
64 | ACT_ACTIVATE, | |
65 | ACT_CHANGE_ID, | |
66 | ACT_DUMP, | |
67 | ACT_LIST, | |
9c1f9dd3 | 68 | ACT_LIST_TYPES, |
d2eb1457 | 69 | ACT_SHOW_SIZE, |
9c1f9dd3 KZ |
70 | ACT_VERIFY |
71 | }; | |
72 | ||
73 | struct sfdisk { | |
74 | int act; /* action */ | |
7324f1bf KZ |
75 | int partno; /* -N <partno>, default -1 */ |
76 | const char *label; /* --label <label> */ | |
9c1f9dd3 KZ |
77 | |
78 | struct fdisk_context *cxt; /* libfdisk context */ | |
79 | }; | |
80 | ||
fd6b7a7f | 81 | |
1881390d KZ |
82 | static void sfdiskprog_init_debug(void) |
83 | { | |
84 | __UL_INIT_DEBUG(sfdisk, SFDISKPROG_DEBUG_, 0, SFDISK_DEBUG); | |
fd6b7a7f KZ |
85 | } |
86 | ||
e8813494 KZ |
87 | |
88 | static int get_user_reply(const char *prompt, char *buf, size_t bufsz) | |
89 | { | |
90 | char *p; | |
91 | size_t sz; | |
92 | ||
93 | fputs(prompt, stdout); | |
94 | fflush(stdout); | |
95 | ||
96 | if (!fgets(buf, bufsz, stdin)) | |
97 | return 1; | |
98 | ||
99 | for (p = buf; *p && !isgraph(*p); p++); /* get first non-blank */ | |
100 | ||
101 | if (p > buf) | |
102 | memmove(buf, p, p - buf); /* remove blank space */ | |
103 | sz = strlen(buf); | |
104 | if (sz && *(buf + sz - 1) == '\n') | |
105 | *(buf + sz - 1) = '\0'; | |
106 | ||
107 | DBG(ASK, ul_debug("user's reply: >>>%s<<<", buf)); | |
108 | return 0; | |
109 | } | |
110 | ||
9c1f9dd3 KZ |
111 | static int ask_callback(struct fdisk_context *cxt, struct fdisk_ask *ask, |
112 | void *data __attribute__((__unused__))) | |
113 | { | |
e8813494 KZ |
114 | int rc = 0; |
115 | ||
9c1f9dd3 KZ |
116 | assert(cxt); |
117 | assert(ask); | |
118 | ||
119 | switch(fdisk_ask_get_type(ask)) { | |
120 | case FDISK_ASKTYPE_INFO: | |
121 | fputs(fdisk_ask_print_get_mesg(ask), stdout); | |
122 | fputc('\n', stdout); | |
123 | break; | |
124 | case FDISK_ASKTYPE_WARNX: | |
125 | color_scheme_fenable("warn", UL_COLOR_RED, stderr); | |
126 | fputs(fdisk_ask_print_get_mesg(ask), stderr); | |
127 | color_fdisable(stderr); | |
128 | fputc('\n', stderr); | |
129 | break; | |
130 | case FDISK_ASKTYPE_WARN: | |
131 | color_scheme_fenable("warn", UL_COLOR_RED, stderr); | |
132 | fputs(fdisk_ask_print_get_mesg(ask), stderr); | |
133 | errno = fdisk_ask_print_get_errno(ask); | |
134 | fprintf(stderr, ": %m\n"); | |
135 | color_fdisable(stderr); | |
136 | break; | |
e8813494 KZ |
137 | case FDISK_ASKTYPE_YESNO: |
138 | { | |
139 | char buf[BUFSIZ]; | |
140 | fputc('\n', stdout); | |
141 | do { | |
142 | int x; | |
143 | fputs(fdisk_ask_get_query(ask), stdout); | |
144 | rc = get_user_reply(_(" [Y]es/[N]o: "), buf, sizeof(buf)); | |
145 | if (rc) | |
146 | break; | |
147 | x = rpmatch(buf); | |
148 | if (x == 1 || x == 0) { | |
149 | fdisk_ask_yesno_set_result(ask, x); | |
150 | break; | |
151 | } | |
152 | } while(1); | |
153 | DBG(ASK, ul_debug("yes-no ask: reply '%s' [rc=%d]", buf, rc)); | |
154 | break; | |
155 | } | |
9c1f9dd3 KZ |
156 | default: |
157 | break; | |
158 | } | |
e8813494 | 159 | return rc; |
9c1f9dd3 KZ |
160 | } |
161 | ||
162 | static void sfdisk_init(struct sfdisk *sf) | |
163 | { | |
164 | fdisk_init_debug(0); | |
165 | sfdiskprog_init_debug(); | |
166 | ||
167 | colors_init(UL_COLORMODE_UNDEF, "sfdisk"); | |
168 | ||
169 | sf->cxt = fdisk_new_context(); | |
170 | if (!sf->cxt) | |
171 | err(EXIT_FAILURE, _("failed to allocate libfdisk context")); | |
172 | fdisk_set_ask(sf->cxt, ask_callback, NULL); | |
173 | } | |
174 | ||
175 | static int sfdisk_deinit(struct sfdisk *sf) | |
176 | { | |
177 | int rc; | |
178 | ||
179 | assert(sf); | |
180 | assert(sf->cxt); | |
181 | ||
9c1f9dd3 KZ |
182 | fdisk_unref_context(sf->cxt); |
183 | memset(sf, 0, sizeof(*sf)); | |
184 | ||
185 | return rc; | |
186 | } | |
187 | ||
148f6e6d KZ |
188 | /* |
189 | * sfdisk --list [<device ..] | |
190 | */ | |
9c1f9dd3 KZ |
191 | static int command_list_partitions(struct sfdisk *sf, int argc, char **argv) |
192 | { | |
9c1f9dd3 KZ |
193 | fdisk_enable_listonly(sf->cxt, 1); |
194 | ||
207de32a | 195 | if (argc) { |
d2eb1457 | 196 | int i, ct = 0; |
8a8d204c KZ |
197 | |
198 | for (i = 0; i < argc; i++) { | |
199 | if (ct) | |
200 | fputs("\n\n", stdout); | |
201 | if (print_device_pt(sf->cxt, argv[i], 0) == 0) | |
202 | ct++; | |
203 | } | |
9c1f9dd3 KZ |
204 | } else |
205 | print_all_devices_pt(sf->cxt); | |
206 | ||
207 | return 0; | |
208 | } | |
209 | ||
148f6e6d | 210 | static int get_size(const char *dev, int silent, uintmax_t *sz) |
d2eb1457 | 211 | { |
148f6e6d KZ |
212 | int fd, rc = 0; |
213 | ||
214 | fd = open(dev, O_RDONLY); | |
d2eb1457 KZ |
215 | if (fd < 0) { |
216 | if (!silent) | |
217 | warn(_("cannot open: %s"), dev); | |
218 | return -errno; | |
219 | } | |
d2eb1457 KZ |
220 | |
221 | if (blkdev_get_sectors(fd, (unsigned long long *) sz) == -1) { | |
222 | if (!silent) | |
223 | warn(_("Cannot get size of %s"), dev); | |
224 | rc = -errno; | |
225 | } | |
226 | ||
227 | close(fd); | |
228 | return rc; | |
229 | } | |
230 | ||
148f6e6d KZ |
231 | /* |
232 | * sfdisk --show-size [<device ..] | |
233 | * | |
234 | * (silly, but just for backward compatibility) | |
235 | */ | |
d2eb1457 KZ |
236 | static int command_show_size(struct sfdisk *sf __attribute__((__unused__)), |
237 | int argc, char **argv) | |
238 | { | |
239 | uintmax_t sz; | |
240 | ||
241 | if (argc) { | |
242 | int i; | |
243 | for (i = 0; i < argc; i++) { | |
244 | if (get_size(argv[i], 0, &sz) == 0) | |
245 | printf("%ju\n", sz / 2); | |
246 | } | |
247 | } else { | |
248 | FILE *f = NULL; | |
249 | uintmax_t total = 0; | |
250 | char *dev; | |
251 | ||
252 | while ((dev = next_proc_partition(&f))) { | |
253 | if (get_size(dev, 1, &sz) == 0) { | |
254 | printf("%s: %9ju\n", dev, sz / 2); | |
255 | total += sz / 2; | |
256 | } | |
257 | free(dev); | |
258 | } | |
259 | if (total) | |
260 | printf(_("total: %ju blocks\n"), total); | |
261 | } | |
262 | ||
263 | return 0; | |
264 | } | |
265 | ||
254b1dfc KZ |
266 | /* |
267 | * sfdisk --activate <device> [<partno> ...] | |
268 | */ | |
54b13b0c KZ |
269 | static int command_activate(struct sfdisk *sf, int argc, char **argv) |
270 | { | |
271 | int rc, nparts, i; | |
272 | struct fdisk_partition *pa = NULL; | |
273 | const char *devname = NULL; | |
274 | ||
275 | if (argc) | |
276 | devname = argv[0]; | |
277 | else | |
278 | errx(EXIT_FAILURE, _("no disk device specified")); | |
279 | if (argc > 2) | |
280 | errx(EXIT_FAILURE, _("uneexpected arguments")); | |
281 | ||
282 | rc = fdisk_assign_device(sf->cxt, devname, 0); | |
283 | if (rc) | |
284 | err(EXIT_FAILURE, _("cannot open %s"), devname); | |
285 | ||
286 | if (!fdisk_is_label(sf->cxt, DOS)) | |
287 | errx(EXIT_FAILURE, _("toggle boot flags is supported for MBR only")); | |
288 | ||
289 | nparts = fdisk_get_npartitions(sf->cxt); | |
290 | for (i = 0; i < nparts; i++) { | |
291 | char *data = NULL; | |
292 | ||
293 | /* note that fdisk_get_partition() reuses the @pa pointer, you | |
294 | * don't have to (re)allocate it */ | |
295 | if (fdisk_get_partition(sf->cxt, i, &pa) != 0) | |
296 | continue; | |
297 | ||
298 | /* sfdisk --activate list bootable partitions */ | |
299 | if (argc == 1) { | |
300 | if (!fdisk_partition_is_bootable(pa)) | |
301 | continue; | |
302 | if (fdisk_partition_to_string(pa, sf->cxt, | |
303 | FDISK_FIELD_DEVICE, &data) == 0) { | |
304 | printf("%s\n", data); | |
305 | free(data); | |
306 | } | |
307 | ||
308 | /* deactivate all active partitions */ | |
309 | } else if (fdisk_partition_is_bootable(pa)) | |
310 | fdisk_partition_toggle_flag(sf->cxt, i, DOS_FLAG_ACTIVE); | |
311 | } | |
312 | ||
313 | /* sfdisk --activate <partno> [..] */ | |
314 | for (i = 1; i < argc; i++) { | |
315 | int n = strtou32_or_err(argv[i], _("failed to parse partition number")); | |
316 | ||
254b1dfc KZ |
317 | rc = fdisk_partition_toggle_flag(sf->cxt, n - 1, DOS_FLAG_ACTIVE); |
318 | if (rc) | |
319 | errx(EXIT_FAILURE, | |
320 | _("%s: #%d: failed to toggle bootable flag"), | |
321 | devname, i + 1); | |
54b13b0c KZ |
322 | } |
323 | ||
324 | fdisk_unref_partition(pa); | |
325 | rc = fdisk_write_disklabel(sf->cxt); | |
326 | if (!rc) | |
327 | rc = fdisk_deassign_device(sf->cxt, 1); | |
328 | return rc; | |
329 | } | |
330 | ||
148f6e6d KZ |
331 | /* |
332 | * sfdisk --dump <device> | |
333 | */ | |
8a8d204c KZ |
334 | static int command_dump(struct sfdisk *sf, int argc, char **argv) |
335 | { | |
336 | const char *devname = NULL; | |
337 | struct fdisk_script *dp; | |
338 | int rc; | |
339 | ||
340 | if (argc) | |
341 | devname = argv[0]; | |
342 | if (!devname) | |
343 | errx(EXIT_FAILURE, _("no disk device specified")); | |
344 | ||
345 | rc = fdisk_assign_device(sf->cxt, devname, 1); | |
346 | if (rc) | |
347 | err(EXIT_FAILURE, _("cannot open %s"), devname); | |
348 | ||
349 | dp = fdisk_new_script(sf->cxt); | |
350 | if (!dp) | |
351 | err(EXIT_FAILURE, _("failed to allocate dump struct")); | |
352 | ||
353 | rc = fdisk_script_read_context(dp, NULL); | |
354 | if (rc) | |
355 | err(EXIT_FAILURE, _("failed to dump partition table")); | |
356 | ||
357 | fdisk_script_write_file(dp, stdout); | |
358 | ||
359 | fdisk_unref_script(dp); | |
360 | return 0; | |
361 | } | |
362 | ||
7324f1bf KZ |
363 | |
364 | static void sfdisk_print_partition(struct sfdisk *sf, int n) | |
365 | { | |
c3bc7483 | 366 | struct fdisk_partition *pa = NULL; |
7324f1bf KZ |
367 | char *data; |
368 | ||
369 | assert(sf); | |
370 | ||
371 | if (fdisk_get_partition(sf->cxt, n, &pa) != 0) | |
372 | return; | |
373 | ||
374 | fdisk_partition_to_string(pa, sf->cxt, FDISK_FIELD_DEVICE, &data); | |
375 | printf("%12s : ", data); | |
376 | ||
377 | fdisk_partition_to_string(pa, sf->cxt, FDISK_FIELD_START, &data); | |
378 | printf("%12s ", data); | |
379 | ||
380 | fdisk_partition_to_string(pa, sf->cxt, FDISK_FIELD_END, &data); | |
381 | printf("%12s ", data); | |
382 | ||
383 | fdisk_partition_to_string(pa, sf->cxt, FDISK_FIELD_SIZE, &data); | |
384 | printf("(%s) ", data); | |
385 | ||
386 | fdisk_partition_to_string(pa, sf->cxt, FDISK_FIELD_TYPE, &data); | |
387 | printf("%s\n", data); | |
388 | ||
389 | fdisk_unref_partition(pa); | |
390 | } | |
391 | ||
3186f4a9 KZ |
392 | static void command_fdisk_help(void) |
393 | { | |
394 | fputs(_("\nHelp:\n"), stdout); | |
395 | ||
396 | fputc('\n', stdout); | |
397 | color_scheme_enable("help-title", UL_COLOR_BOLD); | |
398 | fputs(_(" Commands:\n"), stdout); | |
399 | color_disable(); | |
e8813494 KZ |
400 | fputs(_(" write write table to disk and exit\n"), stdout); |
401 | fputs(_(" quit show new situation and wait for user's feedbadk before write\n"), stdout); | |
402 | fputs(_(" abort exit sfdisk shell\n"), stdout); | |
3186f4a9 KZ |
403 | fputs(_(" print print partition table.\n"), stdout); |
404 | fputs(_(" help this help.\n"), stdout); | |
405 | ||
406 | fputc('\n', stdout); | |
407 | color_scheme_enable("help-title", UL_COLOR_BOLD); | |
408 | fputs(_(" Input format:\n"), stdout); | |
409 | color_disable(); | |
410 | fputs(_(" <start> <size> <typy> <bootable>\n"), stdout); | |
411 | ||
412 | fputc('\n', stdout); | |
413 | fputs(_(" <start> begin of the partition in sectors. The default is the first\n" | |
414 | " free space.\n"), stdout); | |
415 | ||
416 | fputc('\n', stdout); | |
417 | fputs(_(" <size> size of the partition in sectors if specified in format\n" | |
418 | " <number>{K,M,G,T,P,E,Z,Y} then it's interpreted as size\n" | |
419 | " in bytes. The default is all available space.\n"), stdout); | |
420 | ||
421 | fputc('\n', stdout); | |
422 | fputs(_(" <type> partition type. The default is Linux data partition.\n"), stdout); | |
423 | fputs(_(" MBR: hex or L,S,E,X shortcuts.\n"), stdout); | |
424 | fputs(_(" GPT: uuid or L,S,H shortcuts.\n"), stdout); | |
425 | ||
426 | fputc('\n', stdout); | |
427 | fputs(_(" <bootable> '*' to mark MBR partition as bootable. \n"), stdout); | |
428 | ||
429 | fputc('\n', stdout); | |
430 | color_scheme_enable("help-title", UL_COLOR_BOLD); | |
431 | fputs(_(" Example:\n"), stdout); | |
432 | color_disable(); | |
433 | fputs(_(" , 4G creates 4GiB partition on default start offset.\n"), stdout); | |
434 | fputc('\n', stdout); | |
435 | } | |
436 | ||
e8813494 KZ |
437 | enum { |
438 | SFDISK_DONE_NONE = 0, | |
439 | SFDISK_DONE_EOF, | |
440 | SFDISK_DONE_ABORT, | |
441 | SFDISK_DONE_WRITE, | |
442 | SFDISK_DONE_ASK | |
443 | }; | |
444 | ||
445 | /* returns: 0 on success, <0 on error, 1 successfully stop sfdisk */ | |
446 | static int loop_control_commands(struct sfdisk *sf, | |
447 | struct fdisk_script *dp, | |
448 | char *buf) | |
449 | { | |
450 | const char *p = skip_blank(buf); | |
451 | int rc = SFDISK_DONE_NONE; | |
452 | ||
453 | if (strcmp(p, "print") == 0) | |
454 | list_disklabel(sf->cxt); | |
455 | else if (strcmp(p, "help") == 0) | |
456 | command_fdisk_help(); | |
457 | else if (strcmp(p, "quit") == 0) | |
458 | rc = SFDISK_DONE_ASK; | |
459 | else if (strcmp(p, "write") == 0) | |
460 | rc = SFDISK_DONE_WRITE; | |
461 | else if (strcmp(p, "abort") == 0) | |
462 | rc = SFDISK_DONE_ABORT; | |
463 | else { | |
464 | if (isatty(STDIN_FILENO)) | |
465 | fdisk_warnx(sf->cxt, _("unsupported command")); | |
466 | else { | |
467 | fdisk_warnx(sf->cxt, _("line %d: unsupported command"), | |
468 | fdisk_script_get_nlines(dp)); | |
469 | rc = -EINVAL; | |
470 | } | |
471 | } | |
472 | return rc; | |
473 | } | |
474 | ||
3186f4a9 | 475 | |
254b1dfc KZ |
476 | /* |
477 | * sfdisk <device> [[-N] <partno>] | |
478 | * | |
479 | * Note that the option -N is there for backward compatibility only. | |
480 | */ | |
7324f1bf | 481 | static int command_fdisk(struct sfdisk *sf, int argc, char **argv) |
9c1f9dd3 | 482 | { |
7324f1bf KZ |
483 | int rc = 0, partno = sf->partno, created = 0; |
484 | struct fdisk_script *dp; | |
485 | struct fdisk_table *tb = NULL; | |
486 | const char *devname = NULL, *label; | |
487 | char buf[BUFSIZ]; | |
c3bc7483 | 488 | size_t next_partno = (size_t) -1; |
9c1f9dd3 | 489 | |
8a8d204c KZ |
490 | if (argc) |
491 | devname = argv[0]; | |
254b1dfc | 492 | if (partno < 0 && argc > 1) |
54b13b0c | 493 | partno = strtou32_or_err(argv[1], |
9c1f9dd3 | 494 | _("failed to parse partition number")); |
8a8d204c | 495 | if (!devname) |
9c1f9dd3 KZ |
496 | errx(EXIT_FAILURE, _("no disk device specified")); |
497 | ||
7324f1bf KZ |
498 | dp = fdisk_new_script(sf->cxt); |
499 | if (!dp) | |
500 | err(EXIT_FAILURE, _("failed to allocate script handler")); | |
501 | ||
8a8d204c KZ |
502 | rc = fdisk_assign_device(sf->cxt, devname, 0); |
503 | if (rc) | |
504 | err(EXIT_FAILURE, _("cannot open %s"), devname); | |
9c1f9dd3 | 505 | |
3186f4a9 KZ |
506 | if (isatty(STDIN_FILENO)) { |
507 | color_scheme_enable("welcome", UL_COLOR_GREEN); | |
508 | fdisk_info(sf->cxt, _("\nWelcome to sfdisk (%s)."), PACKAGE_STRING); | |
509 | color_disable(); | |
510 | fdisk_info(sf->cxt, _("Changes will remain in memory only, until you decide to write them.\n" | |
511 | "Be careful before using the write command.\n")); | |
512 | } | |
513 | ||
7324f1bf | 514 | list_disk_geometry(sf->cxt); |
3186f4a9 KZ |
515 | if (fdisk_has_label(sf->cxt)) { |
516 | fdisk_info(sf->cxt, _("\nOld situation:")); | |
517 | list_disklabel(sf->cxt); | |
518 | } | |
7324f1bf KZ |
519 | |
520 | if (sf->label) | |
521 | label = sf->label; | |
522 | else if (fdisk_has_label(sf->cxt)) | |
523 | label = fdisk_label_get_name(fdisk_get_label(sf->cxt, NULL)); | |
524 | else | |
525 | label = "dos"; /* just for backward compatibility */ | |
526 | ||
527 | fdisk_script_set_header(dp, "label", label); | |
528 | ||
3186f4a9 KZ |
529 | if (isatty(STDIN_FILENO)) { |
530 | if (!fdisk_has_label(sf->cxt) && !sf->label) | |
531 | fdisk_info(sf->cxt, | |
532 | _("\nsfdisk is going to create a new '%s' disk label.\n" | |
533 | "Use 'label: <name>' before you define a first partition\n" | |
534 | "to override the default."), label); | |
535 | fdisk_info(sf->cxt, _("\nType 'help' to get more information.\n")); | |
536 | } else | |
537 | fputc('\n', stdout); | |
7324f1bf KZ |
538 | |
539 | tb = fdisk_script_get_table(dp); | |
c3bc7483 | 540 | assert(tb); |
7324f1bf KZ |
541 | |
542 | do { | |
c3bc7483 | 543 | size_t nparts; |
7324f1bf | 544 | |
c3bc7483 KZ |
545 | DBG(PARSE, ul_debug("<---next-line--->")); |
546 | if (next_partno == (size_t) -1) | |
547 | next_partno = fdisk_table_get_nents(tb); | |
548 | ||
3186f4a9 KZ |
549 | if (created) { |
550 | char *partname = fdisk_partname(devname, next_partno + 1); | |
551 | if (!partname) | |
552 | err(EXIT_FAILURE, _("failed to allocate partition name")); | |
553 | printf("%s: ", partname); | |
554 | free(partname); | |
555 | } else | |
556 | printf(">>> "); | |
7324f1bf KZ |
557 | |
558 | rc = fdisk_script_read_line(dp, stdin, buf, sizeof(buf)); | |
e8813494 | 559 | if (rc < 0) { |
c3bc7483 | 560 | DBG(PARSE, ul_debug("script parsing failed, trying sfdisk specific commands")); |
7324f1bf | 561 | buf[sizeof(buf) - 1] = '\0'; |
e8813494 KZ |
562 | rc = loop_control_commands(sf, dp, buf); |
563 | if (rc) | |
7324f1bf | 564 | break; |
7324f1bf | 565 | continue; |
e8813494 KZ |
566 | } else if (rc == 1) { |
567 | rc = SFDISK_DONE_EOF; | |
568 | break; | |
7324f1bf KZ |
569 | } |
570 | ||
571 | nparts = fdisk_table_get_nents(tb); | |
572 | if (nparts) { | |
c3bc7483 | 573 | size_t cur_partno; |
7324f1bf KZ |
574 | struct fdisk_partition *pa = fdisk_table_get_partition(tb, nparts - 1); |
575 | ||
c3bc7483 | 576 | assert(pa); |
3186f4a9 KZ |
577 | |
578 | if (!fdisk_partition_get_start(pa) && | |
579 | !fdisk_partition_start_is_default(pa)) { | |
580 | fdisk_info(sf->cxt, _("Ignore partition %zu"), next_partno + 1); | |
581 | continue; | |
582 | } | |
7324f1bf KZ |
583 | if (!created) { /* create a disklabel */ |
584 | rc = fdisk_apply_script_headers(sf->cxt, dp); | |
585 | created = !rc; | |
586 | } | |
587 | if (!rc) /* cretate partition */ | |
c3bc7483 | 588 | rc = fdisk_add_partition(sf->cxt, pa, &cur_partno); |
7324f1bf | 589 | |
c3bc7483 KZ |
590 | if (!rc) { /* success, print reult */ |
591 | sfdisk_print_partition(sf, cur_partno); | |
592 | next_partno = cur_partno + 1; | |
593 | } else if (pa) /* error, drop partition from script */ | |
7324f1bf KZ |
594 | fdisk_table_remove_partition(tb, pa); |
595 | } else | |
3186f4a9 | 596 | fdisk_info(sf->cxt, _("Script header accepted.")); |
7324f1bf | 597 | } while (1); |
254b1dfc | 598 | |
e8813494 | 599 | if (rc != SFDISK_DONE_ABORT) { |
3186f4a9 | 600 | fdisk_info(sf->cxt, _("\nNew situation:")); |
7324f1bf KZ |
601 | list_disklabel(sf->cxt); |
602 | } | |
e8813494 KZ |
603 | |
604 | switch (rc) { | |
605 | case SFDISK_DONE_ASK: | |
606 | if (isatty(STDIN_FILENO)) { | |
607 | int yes = 0; | |
608 | fdisk_ask_yesno(sf->cxt, _("Do you want to write this to disk?"), &yes); | |
609 | if (!yes) { | |
610 | printf(_("Leaving.\n")); | |
611 | rc = 0; | |
612 | break; | |
613 | } | |
614 | } | |
615 | case SFDISK_DONE_EOF: | |
616 | case SFDISK_DONE_WRITE: | |
254b1dfc | 617 | rc = fdisk_write_disklabel(sf->cxt); |
e8813494 KZ |
618 | if (!rc) { |
619 | fdisk_info(sf->cxt, _("\nThe partition table has been altered.")); | |
620 | fdisk_reread_partition_table(sf->cxt); | |
621 | rc = fdisk_deassign_device(sf->cxt, 0); | |
622 | } | |
623 | break; | |
624 | case SFDISK_DONE_ABORT: | |
625 | printf(_("Leaving.\n")); | |
626 | break; | |
3186f4a9 | 627 | } |
e8813494 | 628 | |
7324f1bf | 629 | fdisk_unref_script(dp); |
9c1f9dd3 KZ |
630 | return rc; |
631 | } | |
632 | ||
1881390d KZ |
633 | static void __attribute__ ((__noreturn__)) usage(FILE *out) |
634 | { | |
635 | fputs(USAGE_HEADER, out); | |
fd6b7a7f | 636 | |
1881390d | 637 | fprintf(out, |
54b13b0c KZ |
638 | _(" %1$s [options] --dump <device>\n" |
639 | " %1$s [options] --list [<device> ...]\n" | |
640 | " %1$s [options] --activate <device> [<partno> ...]\n"), | |
e3bb13d9 | 641 | program_invocation_short_name); |
fd6b7a7f | 642 | |
1881390d | 643 | fputs(USAGE_OPTIONS, out); |
54b13b0c | 644 | fputs(_(" -a, --activate mark MBR partitions as bootable\n"), out); |
e3bb13d9 KZ |
645 | fputs(_(" -d, --dump dump partition table (suitable for later input)\n"), out); |
646 | fputs(_(" -l, --list list partitions of each device\n"), out); | |
8a8d204c | 647 | |
1881390d KZ |
648 | fputs(USAGE_SEPARATOR, out); |
649 | fputs(USAGE_HELP, out); | |
650 | fputs(USAGE_VERSION, out); | |
fd6b7a7f | 651 | |
1881390d KZ |
652 | fprintf(out, USAGE_MAN_TAIL("sfdisk(8)")); |
653 | exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS); | |
fd6b7a7f KZ |
654 | } |
655 | ||
9c1f9dd3 KZ |
656 | |
657 | ||
1881390d KZ |
658 | int main(int argc, char *argv[]) |
659 | { | |
7324f1bf KZ |
660 | int rc = -EINVAL, c; |
661 | struct sfdisk _sf = { | |
662 | .act = 0, | |
663 | .partno = -1 | |
664 | }, *sf = &_sf; | |
1881390d KZ |
665 | |
666 | static const struct option longopts[] = { | |
54b13b0c | 667 | { "activate",no_argument, NULL, 'a' }, |
9c1f9dd3 | 668 | { "list", no_argument, NULL, 'l' }, |
8a8d204c | 669 | { "dump", no_argument, NULL, 'd' }, |
1881390d | 670 | { "help", no_argument, NULL, 'h' }, |
d2eb1457 | 671 | { "show-size", no_argument, NULL, 's' }, |
254b1dfc | 672 | { "partno", required_argument, NULL, 'N' }, |
7324f1bf | 673 | { "label", required_argument, NULL, 'X' }, |
1881390d KZ |
674 | { "version", no_argument, NULL, 'v' }, |
675 | { NULL, 0, 0, 0 }, | |
676 | }; | |
677 | ||
678 | setlocale(LC_ALL, ""); | |
679 | bindtextdomain(PACKAGE, LOCALEDIR); | |
680 | textdomain(PACKAGE); | |
681 | atexit(close_stdout); | |
682 | ||
7324f1bf | 683 | while ((c = getopt_long(argc, argv, "adhlN:svX:", longopts, NULL)) != -1) { |
1881390d | 684 | switch(c) { |
54b13b0c KZ |
685 | case 'a': |
686 | sf->act = ACT_ACTIVATE; | |
687 | break; | |
1881390d KZ |
688 | case 'h': |
689 | usage(stdout); | |
690 | break; | |
9c1f9dd3 KZ |
691 | case 'l': |
692 | sf->act = ACT_LIST; | |
693 | break; | |
8a8d204c KZ |
694 | case 'd': |
695 | sf->act = ACT_DUMP; | |
696 | break; | |
254b1dfc | 697 | case 'N': |
7324f1bf KZ |
698 | sf->partno = strtou32_or_err(optarg, _("failed to parse partition number")); |
699 | break; | |
700 | case 'X': | |
701 | sf->label = optarg; | |
254b1dfc | 702 | break; |
d2eb1457 KZ |
703 | case 's': |
704 | sf->act = ACT_SHOW_SIZE; | |
705 | break; | |
1881390d KZ |
706 | case 'v': |
707 | printf(_("%s from %s\n"), program_invocation_short_name, | |
708 | PACKAGE_STRING); | |
709 | return EXIT_SUCCESS; | |
7324f1bf KZ |
710 | default: |
711 | usage(stderr); | |
37b94458 | 712 | } |
37b94458 | 713 | } |
fd6b7a7f | 714 | |
9c1f9dd3 | 715 | sfdisk_init(sf); |
22853e4a | 716 | |
9c1f9dd3 | 717 | switch (sf->act) { |
54b13b0c KZ |
718 | case ACT_ACTIVATE: |
719 | rc = command_activate(sf, argc - optind, argv + optind); | |
720 | break; | |
721 | ||
9c1f9dd3 KZ |
722 | case ACT_LIST: |
723 | rc = command_list_partitions(sf, argc - optind, argv + optind); | |
724 | break; | |
fd6b7a7f | 725 | |
9c1f9dd3 | 726 | case ACT_FDISK: |
7324f1bf | 727 | rc = command_fdisk(sf, argc - optind, argv + optind); |
9c1f9dd3 | 728 | break; |
8a8d204c KZ |
729 | |
730 | case ACT_DUMP: | |
731 | rc = command_dump(sf, argc - optind, argv + optind); | |
732 | break; | |
d2eb1457 KZ |
733 | |
734 | case ACT_SHOW_SIZE: | |
735 | rc = command_show_size(sf, argc - optind, argv + optind); | |
736 | break; | |
9c1f9dd3 | 737 | } |
fd6b7a7f | 738 | |
9c1f9dd3 | 739 | sfdisk_deinit(sf); |
fd6b7a7f | 740 | |
1881390d KZ |
741 | DBG(MISC, ul_debug("bye! [rc=%d]", rc)); |
742 | return rc == 0 ? EXIT_SUCCESS : EXIT_FAILURE; | |
4b1cc035 KZ |
743 | } |
744 |