]> git.ipfire.org Git - thirdparty/util-linux.git/blame - disk-utils/sfdisk.c
Merge branch 'master' of https://github.com/Rufflewind/util-linux
[thirdparty/util-linux.git] / disk-utils / sfdisk.c
CommitLineData
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>
f42205d8 33#include <fcntl.h>
053939a4 34#include <libsmartcols.h>
7159b496
KZ
35#ifdef HAVE_LIBREADLINE
36# include <readline/readline.h>
37#endif
11ef0c35
KZ
38
39#include "c.h"
109dbc4f 40#include "xalloc.h"
1881390d
KZ
41#include "nls.h"
42#include "debug.h"
9912f01b 43#include "strutils.h"
1881390d 44#include "closestream.h"
9c1f9dd3 45#include "colors.h"
d2eb1457 46#include "blkdev.h"
ab02d87e 47#include "all-io.h"
6340e913 48#include "rpmatch.h"
a53e37f9 49#include "loopdev.h"
f42205d8 50#include "xalloc.h"
fd6b7a7f 51
1881390d 52#include "libfdisk.h"
9c1f9dd3 53#include "fdisk-list.h"
fd6b7a7f
KZ
54
55/*
1881390d 56 * sfdisk debug stuff (see fdisk.h and include/debug.h)
fd6b7a7f 57 */
1881390d 58UL_DEBUG_DEFINE_MASK(sfdisk);
819d9a29 59UL_DEBUG_DEFINE_MASKNAMES(sfdisk) = UL_DEBUG_EMPTY_MASKNAMES;
fd6b7a7f 60
1881390d
KZ
61#define SFDISKPROG_DEBUG_INIT (1 << 1)
62#define SFDISKPROG_DEBUG_PARSE (1 << 2)
63#define SFDISKPROG_DEBUG_MISC (1 << 3)
e8813494 64#define SFDISKPROG_DEBUG_ASK (1 << 4)
1881390d 65#define SFDISKPROG_DEBUG_ALL 0xFFFF
fd6b7a7f 66
1881390d
KZ
67#define DBG(m, x) __UL_DBG(sfdisk, SFDISKPROG_DEBUG_, m, x)
68#define ON_DBG(m, x) __UL_DBG_CALL(sfdisk, SFDISKPROG_DEBUG_, m, x)
fd6b7a7f 69
9c1f9dd3 70enum {
d2c47697 71 ACT_FDISK = 1,
9c1f9dd3
KZ
72 ACT_ACTIVATE,
73 ACT_CHANGE_ID,
74 ACT_DUMP,
75 ACT_LIST,
8abdb912 76 ACT_LIST_FREE,
9c1f9dd3 77 ACT_LIST_TYPES,
9a17d946 78 ACT_REORDER,
d2eb1457 79 ACT_SHOW_SIZE,
d420a7f9 80 ACT_SHOW_GEOM,
8eab3194
KZ
81 ACT_VERIFY,
82 ACT_PARTTYPE,
351fad50 83 ACT_PARTUUID,
e36fb07a 84 ACT_PARTLABEL,
bc9e8547 85 ACT_PARTATTRS,
aab9be66 86 ACT_DELETE
9c1f9dd3
KZ
87};
88
89struct sfdisk {
3692c28d 90 int act; /* ACT_* */
7324f1bf 91 int partno; /* -N <partno>, default -1 */
15b5e942 92 int wipemode; /* remove foreign signatures */
7324f1bf 93 const char *label; /* --label <label> */
e1422de3 94 const char *label_nested; /* --label-nested <label> */
ab02d87e 95 const char *backup_file; /* -O <path> */
f42205d8 96 const char *move_typescript; /* --movedata <typescript> */
7159b496 97 char *prompt;
9c1f9dd3 98
f42205d8
KZ
99 struct fdisk_context *cxt; /* libfdisk context */
100 struct fdisk_partition *orig_pa; /* -N <partno> before the change */
d2c47697 101
f0edb076 102 unsigned int verify : 1, /* call fdisk_verify_disklabel() */
f01f2528 103 quiet : 1, /* suppres extra messages */
8be199ea 104 interactive : 1, /* running on tty */
db48b6a1
KZ
105 noreread : 1, /* don't check device is in use */
106 force : 1, /* do also stupid things */
ab02d87e 107 backup : 1, /* backup sectors before write PT */
e54b1c6f 108 container : 1, /* PT contains container (MBR extended) partitions */
347a7f77 109 append : 1, /* don't create new PT, append partitions only */
a592b4b5 110 json : 1, /* JSON dump */
f42205d8 111 movedata: 1, /* move data after resize */
f01f2528 112 noact : 1; /* do not write to device */
9c1f9dd3
KZ
113};
114
7159b496 115#define SFDISK_PROMPT ">>> "
fd6b7a7f 116
1881390d
KZ
117static void sfdiskprog_init_debug(void)
118{
119 __UL_INIT_DEBUG(sfdisk, SFDISKPROG_DEBUG_, 0, SFDISK_DEBUG);
fd6b7a7f
KZ
120}
121
e8813494
KZ
122
123static int get_user_reply(const char *prompt, char *buf, size_t bufsz)
124{
125 char *p;
126 size_t sz;
127
7159b496
KZ
128#ifdef HAVE_LIBREADLINE
129 if (isatty(STDIN_FILENO)) {
130 p = readline(prompt);
131 if (!p)
132 return 1;
133 memcpy(buf, p, bufsz);
134 free(p);
135 } else
136#endif
137 {
138 fputs(prompt, stdout);
139 fflush(stdout);
e8813494 140
7159b496
KZ
141 if (!fgets(buf, bufsz, stdin))
142 return 1;
143 }
e8813494
KZ
144
145 for (p = buf; *p && !isgraph(*p); p++); /* get first non-blank */
146
147 if (p > buf)
148 memmove(buf, p, p - buf); /* remove blank space */
149 sz = strlen(buf);
150 if (sz && *(buf + sz - 1) == '\n')
151 *(buf + sz - 1) = '\0';
152
153 DBG(ASK, ul_debug("user's reply: >>>%s<<<", buf));
154 return 0;
155}
156
ffab025d 157static int ask_callback(struct fdisk_context *cxt __attribute__((__unused__)),
f0edb076
KZ
158 struct fdisk_ask *ask,
159 void *data)
9c1f9dd3 160{
f0edb076 161 struct sfdisk *sf = (struct sfdisk *) data;
e8813494
KZ
162 int rc = 0;
163
9c1f9dd3
KZ
164 assert(ask);
165
166 switch(fdisk_ask_get_type(ask)) {
167 case FDISK_ASKTYPE_INFO:
f0edb076
KZ
168 if (sf->quiet)
169 break;
9c1f9dd3
KZ
170 fputs(fdisk_ask_print_get_mesg(ask), stdout);
171 fputc('\n', stdout);
172 break;
173 case FDISK_ASKTYPE_WARNX:
174 color_scheme_fenable("warn", UL_COLOR_RED, stderr);
175 fputs(fdisk_ask_print_get_mesg(ask), stderr);
176 color_fdisable(stderr);
177 fputc('\n', stderr);
178 break;
179 case FDISK_ASKTYPE_WARN:
180 color_scheme_fenable("warn", UL_COLOR_RED, stderr);
181 fputs(fdisk_ask_print_get_mesg(ask), stderr);
182 errno = fdisk_ask_print_get_errno(ask);
183 fprintf(stderr, ": %m\n");
184 color_fdisable(stderr);
185 break;
e8813494
KZ
186 case FDISK_ASKTYPE_YESNO:
187 {
188 char buf[BUFSIZ];
189 fputc('\n', stdout);
190 do {
191 int x;
192 fputs(fdisk_ask_get_query(ask), stdout);
193 rc = get_user_reply(_(" [Y]es/[N]o: "), buf, sizeof(buf));
194 if (rc)
195 break;
196 x = rpmatch(buf);
cd2a6f1c 197 if (x == RPMATCH_YES || x == RPMATCH_NO) {
e8813494
KZ
198 fdisk_ask_yesno_set_result(ask, x);
199 break;
200 }
201 } while(1);
202 DBG(ASK, ul_debug("yes-no ask: reply '%s' [rc=%d]", buf, rc));
203 break;
204 }
9c1f9dd3
KZ
205 default:
206 break;
207 }
e8813494 208 return rc;
9c1f9dd3
KZ
209}
210
211static void sfdisk_init(struct sfdisk *sf)
212{
213 fdisk_init_debug(0);
053939a4 214 scols_init_debug(0);
9c1f9dd3
KZ
215 sfdiskprog_init_debug();
216
9c1f9dd3
KZ
217 sf->cxt = fdisk_new_context();
218 if (!sf->cxt)
219 err(EXIT_FAILURE, _("failed to allocate libfdisk context"));
f0edb076 220 fdisk_set_ask(sf->cxt, ask_callback, (void *) sf);
62656395 221 fdisk_enable_bootbits_protection(sf->cxt, 1);
e1422de3
KZ
222
223 if (sf->label_nested) {
224 struct fdisk_context *x = fdisk_new_nested_context(sf->cxt,
225 sf->label_nested);
226 if (!x)
227 err(EXIT_FAILURE, _("failed to allocate nested libfdisk context"));
228 /* the original context is available by fdisk_get_parent() */
229 sf->cxt = x;
230 }
9c1f9dd3
KZ
231}
232
233static int sfdisk_deinit(struct sfdisk *sf)
234{
e1422de3 235 struct fdisk_context *parent;
9c1f9dd3
KZ
236
237 assert(sf);
238 assert(sf->cxt);
239
e1422de3
KZ
240 parent = fdisk_get_parent(sf->cxt);
241 if (parent) {
242 fdisk_unref_context(sf->cxt);
243 sf->cxt = parent;
244 }
245
9c1f9dd3 246 fdisk_unref_context(sf->cxt);
7159b496 247 free(sf->prompt);
9c1f9dd3 248
7159b496 249 memset(sf, 0, sizeof(*sf));
5d365139 250 return 0;
9c1f9dd3
KZ
251}
252
f42205d8
KZ
253static struct fdisk_partition *get_partition(struct fdisk_context *cxt, size_t partno)
254{
255 struct fdisk_table *tb = NULL;
256 struct fdisk_partition *pa;
257
258 if (fdisk_get_partitions(cxt, &tb) != 0)
259 return NULL;
260
261 pa = fdisk_table_get_partition_by_partno(tb, partno);
262 if (pa)
263 fdisk_ref_partition(pa);
264 fdisk_unref_table(tb);
265 return pa;
266}
267
ab02d87e
KZ
268static void backup_sectors(struct sfdisk *sf,
269 const char *tpl,
270 const char *name,
271 const char *devname,
9bbcf43f 272 uint64_t offset, size_t size)
ab02d87e
KZ
273{
274 char *fname;
275 int fd, devfd;
276
277 devfd = fdisk_get_devfd(sf->cxt);
278 assert(devfd >= 0);
279
280 xasprintf(&fname, "%s0x%08jx.bak", tpl, offset);
281
282 fd = open(fname, O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR);
283 if (fd < 0)
284 goto fail;
285
9bbcf43f 286 if (lseek(devfd, (off_t) offset, SEEK_SET) == (off_t) -1) {
ab02d87e
KZ
287 fdisk_warn(sf->cxt, _("cannot seek %s"), devname);
288 goto fail;
289 } else {
290 unsigned char *buf = xmalloc(size);
291
292 if (read_all(devfd, (char *) buf, size) != (ssize_t) size) {
293 fdisk_warn(sf->cxt, _("cannot read %s"), devname);
294 goto fail;
295 }
296 if (write_all(fd, buf, size) != 0) {
297 fdisk_warn(sf->cxt, _("cannot write %s"), fname);
298 goto fail;
299 }
300 free(buf);
301 }
302
303 fdisk_info(sf->cxt, _("%12s (offset %5ju, size %5ju): %s"),
304 name, (uintmax_t) offset, (uintmax_t) size, fname);
305 close(fd);
306 free(fname);
307 return;
308fail:
309 errx(EXIT_FAILURE, _("%s: failed to create a backup"), devname);
310}
311
f42205d8
KZ
312static char *mk_backup_filename_tpl(const char *filename, const char *devname, const char *suffix)
313{
314 char *tpl = NULL;
315 char *name, *buf = xstrdup(devname);
316
317 name = basename(buf);
318
319 if (!filename) {
320 const char *home = getenv ("HOME");
321 if (!home)
322 errx(EXIT_FAILURE, _("failed to create a backup file, $HOME undefined"));
323 xasprintf(&tpl, "%s/sfdisk-%s%s", home, name, suffix);
324 } else
325 xasprintf(&tpl, "%s-%s%s", filename, name, suffix);
326
327 free(buf);
328 return tpl;
329}
330
331
ab02d87e
KZ
332static void backup_partition_table(struct sfdisk *sf, const char *devname)
333{
334 const char *name;
335 char *tpl;
9bbcf43f 336 uint64_t offset = 0;
ab02d87e
KZ
337 size_t size = 0;
338 int i = 0;
339
340 assert(sf);
341
342 if (!fdisk_has_label(sf->cxt))
343 return;
344
f42205d8 345 tpl = mk_backup_filename_tpl(sf->backup_file, devname, "-");
ab02d87e
KZ
346
347 color_scheme_enable("header", UL_COLOR_BOLD);
348 fdisk_info(sf->cxt, _("Backup files:"));
349 color_disable();
350
351 while (fdisk_locate_disklabel(sf->cxt, i++, &name, &offset, &size) == 0 && size)
352 backup_sectors(sf, tpl, name, devname, offset, size);
353
354 if (!sf->quiet)
355 fputc('\n', stdout);
356 free(tpl);
357}
358
f42205d8
KZ
359static int move_partition_data(struct sfdisk *sf, size_t partno, struct fdisk_partition *orig_pa)
360{
361 struct fdisk_partition *pa = get_partition(sf->cxt, partno);
362 char *devname, *typescript;
363 FILE *f;
d85a7fa7 364 int ok = 0, fd, backward = 0;
f42205d8
KZ
365 fdisk_sector_t nsectors, from, to, step, i;
366 size_t ss, step_bytes, cc;
367 uintmax_t src, dst;
368 char *buf;
369
370 assert(sf->movedata);
371
372 if (!pa)
373 warnx(_("failed to read new partition from device (ignore --move-data)"));
374 else if (!fdisk_partition_has_size(pa))
375 warnx(_("failed to get size of the new partition (ignore --move-data)"));
376 else if (!fdisk_partition_has_start(pa))
377 warnx(_("failed to get start of the new partition (ignore --move-data)"));
378 else if (!fdisk_partition_has_size(orig_pa))
379 warnx(_("failed to get size of the old partition (ignore --move-data)"));
380 else if (!fdisk_partition_has_start(orig_pa))
381 warnx(_("failed to get start of the old partition (ignore --move-data)"));
382 else if (fdisk_partition_get_start(pa) == fdisk_partition_get_start(orig_pa))
383 warnx(_("begin of the partition has not been moved (ignore --move-data)"));
384 else if (fdisk_partition_get_size(orig_pa) < fdisk_partition_get_size(pa))
385 warnx(_("new partition is smaller than original (ignore --move-data)"));
386 else
387 ok = 1;
388 if (!ok)
389 return -EINVAL;
390
d85a7fa7
KZ
391 DBG(MISC, ul_debug("moving data"));
392
f42205d8
KZ
393 fd = fdisk_get_devfd(sf->cxt);
394
395 ss = fdisk_get_sector_size(sf->cxt);
396 nsectors = fdisk_partition_get_size(orig_pa);
397 from = fdisk_partition_get_start(orig_pa);
398 to = fdisk_partition_get_start(pa);
d85a7fa7
KZ
399
400 if ((to >= from && from + nsectors >= to) ||
401 (from >= to && to + nsectors >= from)) {
402 /* source and target overlay, check if we need to copy
403 * backwardly from end of the source */
404 DBG(MISC, ul_debug("overlay between source and target"));
405 backward = from < to;
406 DBG(MISC, ul_debug(" copy order: %s", backward ? "backward" : "forward"));
407
408 step = from > to ? from - to : to - from;
409 if (step > nsectors)
410 step = nsectors;
411 } else
412 step = nsectors;
413
414 /* make step usable for malloc() */
415 if (step * ss > (getpagesize() * 256U))
f42205d8 416 step = (getpagesize() * 256) / ss;
d85a7fa7
KZ
417
418 /* align the step (note that nsectors does not have to be power of 2) */
419 while (nsectors % step)
420 step--;
421
f42205d8 422 step_bytes = step * ss;
d85a7fa7 423 DBG(MISC, ul_debug(" step: %ju (%ju bytes)", step, step_bytes));
f42205d8
KZ
424
425#if defined(POSIX_FADV_SEQUENTIAL) && defined(HAVE_POSIX_FADVISE)
d85a7fa7
KZ
426 if (!backward)
427 posix_fadvise(fd, from * ss, nsectors * ss, POSIX_FADV_SEQUENTIAL);
f42205d8
KZ
428#endif
429 devname = fdisk_partname(fdisk_get_devname(sf->cxt), partno+1);
430 typescript = mk_backup_filename_tpl(sf->move_typescript, devname, ".move");
431
432 if (!sf->quiet) {
433 fdisk_info(sf->cxt,"");
434 color_scheme_enable("header", UL_COLOR_BOLD);
435 fdisk_info(sf->cxt, _("Data move:"));
436 color_disable();
437 fdisk_info(sf->cxt, _(" typescript file: %s"), typescript);
438 printf(_(" old start: %ju, new start: %ju (move %ju sectors)\n"),
439 (uintmax_t) from, (uintmax_t) to, nsectors);
440 fflush(stdout);
441 }
442
443 if (sf->interactive) {
444 int yes = 0;
445 fdisk_ask_yesno(sf->cxt, _("Do you want to move partition data?"), &yes);
446 if (!yes) {
447 fdisk_info(sf->cxt, _("Leaving."));
448 return 0;
449 }
450 }
451
452 f = fopen(typescript, "w");
453 if (!f)
454 goto fail;
455
456 /* don't translate */
457 fprintf(f, "# sfdisk: " PACKAGE_STRING "\n");
458 fprintf(f, "# Disk: %s\n", devname);
459 fprintf(f, "# Partition: %zu\n", partno + 1);
460 fprintf(f, "# Operation: move data\n");
d85a7fa7
KZ
461 fprintf(f, "# Original start offset (sectors/bytes): %ju/%ju\n", from, from * ss);
462 fprintf(f, "# New start offset (sectors/bytes): %ju/%ju\n", to, to * ss);
463 fprintf(f, "# Area size (sectors/bytes): %ju/%ju\n", nsectors, nsectors * ss);
464 fprintf(f, "# Sector size: %zu\n", ss);
f42205d8
KZ
465 fprintf(f, "# Step size (in bytes): %zu\n", step_bytes);
466 fprintf(f, "# Steps: %zu\n", nsectors / step);
467 fprintf(f, "#\n");
468 fprintf(f, "# <step>: <from> <to> (step offsets in bytes)\n");
469
470 src = (backward ? from + nsectors : from) * ss;
471 dst = (backward ? to + nsectors : to) * ss;
472 buf = xmalloc(step_bytes);
473
31c79e18
KZ
474 DBG(MISC, ul_debug(" initial: src=%ju dst=%ju", src, dst));
475
f42205d8
KZ
476 for (cc = 1, i = 0; i < nsectors; i += step, cc++) {
477 ssize_t rc;
478
479 if (backward)
480 src -= step_bytes, dst -= step_bytes;
481
31c79e18
KZ
482 DBG(MISC, ul_debug("#%05zu: src=%ju dst=%ju", cc, src, dst));
483
484 /* read source */
485 if (lseek(fd, src, SEEK_SET) == (off_t) -1)
486 goto fail;
f42205d8
KZ
487 rc = read(fd, buf, step_bytes);
488 if (rc < 0 || rc != (ssize_t) step_bytes)
489 goto fail;
490
31c79e18
KZ
491 /* write target */
492 if (lseek(fd, dst, SEEK_SET) == (off_t) -1)
493 goto fail;
f42205d8
KZ
494 rc = write(fd, buf, step_bytes);
495 if (rc < 0 || rc != (ssize_t) step_bytes)
496 goto fail;
497 fsync(fd);
498
31c79e18 499 /* write log */
f42205d8
KZ
500 fprintf(f, "%05zu: %12ju %12ju\n", cc, src, dst);
501
502#if defined(POSIX_FADV_DONTNEED) && defined(HAVE_POSIX_FADVISE)
503 posix_fadvise(fd, src, step_bytes, POSIX_FADV_DONTNEED);
504#endif
505 if (!backward)
506 src += step_bytes, dst += step_bytes;
507 }
508
509 fclose(f);
510 free(buf);
511 free(devname);
512 free(typescript);
513 return 0;
514fail:
31c79e18 515 warn(_("%s: failed to move data"), devname);
f42205d8 516 fclose(f);
31c79e18 517 return -errno;
f42205d8
KZ
518}
519
351fad50
KZ
520static int write_changes(struct sfdisk *sf)
521{
522 int rc = 0;
523
524 if (sf->noact)
54fefa07 525 fdisk_info(sf->cxt, _("The partition table is unchanged (--no-act)."));
351fad50
KZ
526 else {
527 rc = fdisk_write_disklabel(sf->cxt);
f42205d8
KZ
528 if (rc == 0 && sf->movedata && sf->orig_pa)
529 rc = move_partition_data(sf, sf->partno, sf->orig_pa);
351fad50
KZ
530 if (!rc) {
531 fdisk_info(sf->cxt, _("\nThe partition table has been altered."));
532 fdisk_reread_partition_table(sf->cxt);
533 }
534 }
535 if (!rc)
536 rc = fdisk_deassign_device(sf->cxt, sf->noact); /* no-sync when no-act */
537 return rc;
538}
ab02d87e 539
148f6e6d
KZ
540/*
541 * sfdisk --list [<device ..]
542 */
9c1f9dd3
KZ
543static int command_list_partitions(struct sfdisk *sf, int argc, char **argv)
544{
9c1f9dd3
KZ
545 fdisk_enable_listonly(sf->cxt, 1);
546
207de32a 547 if (argc) {
d2eb1457 548 int i, ct = 0;
8a8d204c
KZ
549
550 for (i = 0; i < argc; i++) {
551 if (ct)
552 fputs("\n\n", stdout);
d2c47697 553 if (print_device_pt(sf->cxt, argv[i], 0, sf->verify) == 0)
8a8d204c
KZ
554 ct++;
555 }
9c1f9dd3 556 } else
d2c47697 557 print_all_devices_pt(sf->cxt, sf->verify);
9c1f9dd3
KZ
558
559 return 0;
560}
561
8abdb912
KZ
562/*
563 * sfdisk --list-free [<device ..]
564 */
565static int command_list_freespace(struct sfdisk *sf, int argc, char **argv)
566{
567 fdisk_enable_listonly(sf->cxt, 1);
568
569 if (argc) {
570 int i, ct = 0;
571
572 for (i = 0; i < argc; i++) {
573 if (ct)
574 fputs("\n\n", stdout);
575 if (print_device_freespace(sf->cxt, argv[i], 0) == 0)
576 ct++;
577 }
578 } else
579 print_all_devices_freespace(sf->cxt);
580
581 return 0;
582}
583
058dd97a
KZ
584/*
585 * sfdisk --list-types
586 */
587static int command_list_types(struct sfdisk *sf)
588{
589 const struct fdisk_parttype *t;
590 struct fdisk_label *lb;
591 const char *name;
592 size_t i = 0;
593 int codes;
594
595 assert(sf);
596 assert(sf->cxt);
597
598 name = sf->label ? sf->label : "dos";
599 lb = fdisk_get_label(sf->cxt, name);
600 if (!lb)
601 errx(EXIT_FAILURE, _("unsupported label '%s'"), name);
602
603 codes = fdisk_label_has_code_parttypes(lb);
604 fputs(_("Id Name\n\n"), stdout);
605
606 while ((t = fdisk_label_get_parttype(lb, i++))) {
607 if (codes)
608 printf("%2x %s\n", fdisk_parttype_get_code(t),
609 fdisk_parttype_get_name(t));
610 else
611 printf("%s %s\n", fdisk_parttype_get_string(t),
612 fdisk_parttype_get_name(t));
613 }
614
615 return 0;
616}
617
d2c47697
KZ
618static int verify_device(struct sfdisk *sf, const char *devname)
619{
620 int rc = 1;
621
622 fdisk_enable_listonly(sf->cxt, 1);
623
624 if (fdisk_assign_device(sf->cxt, devname, 1)) {
54fefa07 625 warn(_("cannot open %s"), devname);
d2c47697
KZ
626 return 1;
627 }
628
629 color_scheme_enable("header", UL_COLOR_BOLD);
630 fdisk_info(sf->cxt, "%s:", devname);
631 color_disable();
632
633 if (!fdisk_has_label(sf->cxt))
634 fdisk_info(sf->cxt, _("unrecognized partition table type"));
635 else
636 rc = fdisk_verify_disklabel(sf->cxt);
637
638 fdisk_deassign_device(sf->cxt, 1);
639 return rc;
640}
641
642/*
643 * sfdisk --verify [<device ..]
644 */
645static int command_verify(struct sfdisk *sf, int argc, char **argv)
646{
647 int nfails = 0, ct = 0;
648
649 if (argc) {
650 int i;
651 for (i = 0; i < argc; i++) {
652 if (i)
653 fdisk_info(sf->cxt, " ");
654 if (verify_device(sf, argv[i]) < 0)
655 nfails++;
656 }
657 } else {
658 FILE *f = NULL;
659 char *dev;
660
661 while ((dev = next_proc_partition(&f))) {
662 if (ct)
663 fdisk_info(sf->cxt, " ");
664 if (verify_device(sf, dev) < 0)
665 nfails++;
666 free(dev);
667 ct++;
668 }
669 }
670
671 return nfails;
672}
673
148f6e6d 674static int get_size(const char *dev, int silent, uintmax_t *sz)
d2eb1457 675{
148f6e6d
KZ
676 int fd, rc = 0;
677
678 fd = open(dev, O_RDONLY);
d2eb1457
KZ
679 if (fd < 0) {
680 if (!silent)
54fefa07 681 warn(_("cannot open %s"), dev);
d2eb1457
KZ
682 return -errno;
683 }
d2eb1457
KZ
684
685 if (blkdev_get_sectors(fd, (unsigned long long *) sz) == -1) {
686 if (!silent)
687 warn(_("Cannot get size of %s"), dev);
688 rc = -errno;
689 }
690
691 close(fd);
692 return rc;
693}
694
148f6e6d
KZ
695/*
696 * sfdisk --show-size [<device ..]
697 *
698 * (silly, but just for backward compatibility)
699 */
d2eb1457
KZ
700static int command_show_size(struct sfdisk *sf __attribute__((__unused__)),
701 int argc, char **argv)
702{
703 uintmax_t sz;
704
705 if (argc) {
706 int i;
707 for (i = 0; i < argc; i++) {
708 if (get_size(argv[i], 0, &sz) == 0)
709 printf("%ju\n", sz / 2);
710 }
711 } else {
712 FILE *f = NULL;
713 uintmax_t total = 0;
714 char *dev;
715
716 while ((dev = next_proc_partition(&f))) {
717 if (get_size(dev, 1, &sz) == 0) {
718 printf("%s: %9ju\n", dev, sz / 2);
719 total += sz / 2;
720 }
721 free(dev);
722 }
723 if (total)
724 printf(_("total: %ju blocks\n"), total);
725 }
726
727 return 0;
728}
729
d420a7f9
KZ
730static int print_geom(struct sfdisk *sf, const char *devname)
731{
732 fdisk_enable_listonly(sf->cxt, 1);
733
734 if (fdisk_assign_device(sf->cxt, devname, 1)) {
54fefa07 735 warn(_("cannot open %s"), devname);
d420a7f9
KZ
736 return 1;
737 }
738
739 fdisk_info(sf->cxt, "%s: %ju cylinders, %ju heads, %ju sectors/track",
740 devname,
741 (uintmax_t) fdisk_get_geom_cylinders(sf->cxt),
742 (uintmax_t) fdisk_get_geom_heads(sf->cxt),
743 (uintmax_t) fdisk_get_geom_sectors(sf->cxt));
744
745 fdisk_deassign_device(sf->cxt, 1);
746 return 0;
747}
748
749/*
750 * sfdisk --show-geometry [<device ..]
751 */
752static int command_show_geometry(struct sfdisk *sf, int argc, char **argv)
753{
754 int nfails = 0;
755
756 if (argc) {
757 int i;
758 for (i = 0; i < argc; i++) {
759 if (print_geom(sf, argv[i]) < 0)
760 nfails++;
761 }
762 } else {
763 FILE *f = NULL;
764 char *dev;
765
766 while ((dev = next_proc_partition(&f))) {
767 if (print_geom(sf, dev) < 0)
768 nfails++;
769 free(dev);
770 }
771 }
772
773 return nfails;
774}
775
254b1dfc
KZ
776/*
777 * sfdisk --activate <device> [<partno> ...]
778 */
54b13b0c
KZ
779static int command_activate(struct sfdisk *sf, int argc, char **argv)
780{
21ca986d 781 int rc, nparts, i, listonly;
54b13b0c
KZ
782 struct fdisk_partition *pa = NULL;
783 const char *devname = NULL;
784
21ca986d 785 if (argc < 1)
54b13b0c 786 errx(EXIT_FAILURE, _("no disk device specified"));
8eab3194
KZ
787 devname = argv[0];
788
21ca986d
KZ
789 /* --activate <device> */
790 listonly = argc == 1;
54b13b0c 791
21ca986d 792 rc = fdisk_assign_device(sf->cxt, devname, listonly);
54b13b0c
KZ
793 if (rc)
794 err(EXIT_FAILURE, _("cannot open %s"), devname);
795
796 if (!fdisk_is_label(sf->cxt, DOS))
797 errx(EXIT_FAILURE, _("toggle boot flags is supported for MBR only"));
798
ab02d87e
KZ
799 if (!listonly && sf->backup)
800 backup_partition_table(sf, devname);
21ca986d 801
54b13b0c
KZ
802 nparts = fdisk_get_npartitions(sf->cxt);
803 for (i = 0; i < nparts; i++) {
804 char *data = NULL;
805
806 /* note that fdisk_get_partition() reuses the @pa pointer, you
807 * don't have to (re)allocate it */
808 if (fdisk_get_partition(sf->cxt, i, &pa) != 0)
809 continue;
810
811 /* sfdisk --activate list bootable partitions */
21ca986d 812 if (listonly) {
54b13b0c
KZ
813 if (!fdisk_partition_is_bootable(pa))
814 continue;
815 if (fdisk_partition_to_string(pa, sf->cxt,
816 FDISK_FIELD_DEVICE, &data) == 0) {
817 printf("%s\n", data);
818 free(data);
819 }
820
821 /* deactivate all active partitions */
822 } else if (fdisk_partition_is_bootable(pa))
a1ef792f 823 fdisk_toggle_partition_flag(sf->cxt, i, DOS_FLAG_ACTIVE);
54b13b0c
KZ
824 }
825
826 /* sfdisk --activate <partno> [..] */
827 for (i = 1; i < argc; i++) {
828 int n = strtou32_or_err(argv[i], _("failed to parse partition number"));
829
a1ef792f 830 rc = fdisk_toggle_partition_flag(sf->cxt, n - 1, DOS_FLAG_ACTIVE);
254b1dfc
KZ
831 if (rc)
832 errx(EXIT_FAILURE,
43a1ccec 833 _("%s: partition %d: failed to toggle bootable flag"),
254b1dfc 834 devname, i + 1);
54b13b0c
KZ
835 }
836
837 fdisk_unref_partition(pa);
351fad50
KZ
838 if (listonly)
839 rc = fdisk_deassign_device(sf->cxt, 1);
840 else
841 rc = write_changes(sf);
54b13b0c
KZ
842 return rc;
843}
844
aab9be66
KZ
845/*
846 * sfdisk --delete <device> [<partno> ...]
847 */
848static int command_delete(struct sfdisk *sf, int argc, char **argv)
849{
850 size_t i;
851 const char *devname = NULL;
852
853 if (argc < 1)
854 errx(EXIT_FAILURE, _("no disk device specified"));
855 devname = argv[0];
856
857 if (fdisk_assign_device(sf->cxt, devname, 0) != 0)
858 err(EXIT_FAILURE, _("cannot open %s"), devname);
859
860 if (sf->backup)
861 backup_partition_table(sf, devname);
862
863 /* delate all */
864 if (argc == 1) {
865 size_t nparts = fdisk_get_npartitions(sf->cxt);
866 for (i = 0; i < nparts; i++) {
867 if (fdisk_is_partition_used(sf->cxt, i) &&
868 fdisk_delete_partition(sf->cxt, i) != 0)
869 errx(EXIT_FAILURE, _("%s: partition %zu: failed to delete"), devname, i + 1);
870 }
871 /* delete specified */
872 } else {
873 for (i = 1; i < (size_t) argc; i++) {
874 size_t n = strtou32_or_err(argv[i], _("failed to parse partition number"));
875
876 if (fdisk_delete_partition(sf->cxt, n - 1) != 0)
877 errx(EXIT_FAILURE, _("%s: partition %zu: failed to delete"), devname, n);
878 }
879 }
880
881 return write_changes(sf);
882}
883
9a17d946
KZ
884/*
885 * sfdisk --reorder <device>
886 */
887static int command_reorder(struct sfdisk *sf, int argc, char **argv)
888{
889 const char *devname = NULL;
890 int rc;
891
892 if (argc)
893 devname = argv[0];
894 if (!devname)
895 errx(EXIT_FAILURE, _("no disk device specified"));
896
897 rc = fdisk_assign_device(sf->cxt, devname, 0); /* read-write */
898 if (rc)
899 err(EXIT_FAILURE, _("cannot open %s"), devname);
900
901 if (sf->backup)
902 backup_partition_table(sf, devname);
903
904 if (fdisk_reorder_partitions(sf->cxt) == 1) /* unchnaged */
905 rc = fdisk_deassign_device(sf->cxt, 1);
906 else
907 rc = write_changes(sf);
908
909 return rc;
910}
911
912
148f6e6d
KZ
913/*
914 * sfdisk --dump <device>
915 */
8a8d204c
KZ
916static int command_dump(struct sfdisk *sf, int argc, char **argv)
917{
918 const char *devname = NULL;
919 struct fdisk_script *dp;
920 int rc;
921
922 if (argc)
923 devname = argv[0];
924 if (!devname)
925 errx(EXIT_FAILURE, _("no disk device specified"));
926
f01f2528 927 rc = fdisk_assign_device(sf->cxt, devname, 1); /* read-only */
8a8d204c
KZ
928 if (rc)
929 err(EXIT_FAILURE, _("cannot open %s"), devname);
930
931 dp = fdisk_new_script(sf->cxt);
932 if (!dp)
933 err(EXIT_FAILURE, _("failed to allocate dump struct"));
934
935 rc = fdisk_script_read_context(dp, NULL);
936 if (rc)
937 err(EXIT_FAILURE, _("failed to dump partition table"));
938
a592b4b5
KZ
939 if (sf->json)
940 fdisk_script_enable_json(dp, 1);
8a8d204c
KZ
941 fdisk_script_write_file(dp, stdout);
942
943 fdisk_unref_script(dp);
f01f2528 944 fdisk_deassign_device(sf->cxt, 1); /* no-sync() */
8a8d204c
KZ
945 return 0;
946}
947
3a5bdedf
KZ
948static void assign_device_partition(struct sfdisk *sf,
949 const char *devname,
950 size_t partno,
951 int rdonly)
952{
953 int rc;
954 size_t n;
955 struct fdisk_label *lb = NULL;
956
957 assert(sf);
958 assert(devname);
959
960 /* read-only when a new <type> undefined */
961 rc = fdisk_assign_device(sf->cxt, devname, rdonly);
962 if (rc)
963 err(EXIT_FAILURE, _("cannot open %s"), devname);
964
965 lb = fdisk_get_label(sf->cxt, NULL);
966 if (!lb)
62eea9ce 967 errx(EXIT_FAILURE, _("%s: no partition table found"), devname);
3a5bdedf
KZ
968
969 n = fdisk_get_npartitions(sf->cxt);
970 if (partno > n)
54fefa07
BS
971 errx(EXIT_FAILURE, _("%s: partition %zu: partition table contains "
972 "only %zu partitions"), devname, partno, n);
3a5bdedf 973 if (!fdisk_is_partition_used(sf->cxt, partno - 1))
54fefa07 974 errx(EXIT_FAILURE, _("%s: partition %zu: partition is unused"),
3a5bdedf
KZ
975 devname, partno);
976}
977
8eab3194 978/*
e36fb07a 979 * sfdisk --part-type <device> <partno> [<type>]
8eab3194
KZ
980 */
981static int command_parttype(struct sfdisk *sf, int argc, char **argv)
982{
3a5bdedf 983 size_t partno;
8eab3194 984 struct fdisk_parttype *type = NULL;
3a5bdedf 985 struct fdisk_label *lb;
8eab3194
KZ
986 const char *devname = NULL, *typestr = NULL;
987
988 if (!argc)
989 errx(EXIT_FAILURE, _("no disk device specified"));
990 devname = argv[0];
991
992 if (argc < 2)
993 errx(EXIT_FAILURE, _("no partition number specified"));
994 partno = strtou32_or_err(argv[1], _("failed to parse partition number"));
995
996 if (argc == 3)
997 typestr = argv[2];
998 else if (argc > 3)
6e834d67 999 errx(EXIT_FAILURE, _("unexpected arguments"));
8eab3194
KZ
1000
1001 /* read-only when a new <type> undefined */
3a5bdedf 1002 assign_device_partition(sf, devname, partno, !typestr);
8eab3194
KZ
1003
1004 lb = fdisk_get_label(sf->cxt, NULL);
8eab3194
KZ
1005
1006 /* print partition type */
1007 if (!typestr) {
1008 const struct fdisk_parttype *t = NULL;
2e73a998 1009 struct fdisk_partition *pa = NULL;
8eab3194
KZ
1010
1011 if (fdisk_get_partition(sf->cxt, partno - 1, &pa) == 0)
1012 t = fdisk_partition_get_type(pa);
1013 if (!t)
1014 errx(EXIT_FAILURE, _("%s: partition %zu: failed to get partition type"),
1015 devname, partno);
1016
1017 if (fdisk_label_has_code_parttypes(lb))
1018 printf("%2x\n", fdisk_parttype_get_code(t));
1019 else
1020 printf("%s\n", fdisk_parttype_get_string(t));
1021
1022 fdisk_unref_partition(pa);
2e73a998 1023 fdisk_deassign_device(sf->cxt, 1);
8eab3194
KZ
1024 return 0;
1025 }
1026
ab02d87e
KZ
1027 if (sf->backup)
1028 backup_partition_table(sf, devname);
1029
bf031d89 1030 /* parse <type> and apply to PT */
8eab3194 1031 type = fdisk_label_parse_parttype(lb, typestr);
bf031d89 1032 if (!type)
2e73a998 1033 errx(EXIT_FAILURE, _("failed to parse %s partition type '%s'"),
8eab3194 1034 fdisk_label_get_name(lb), typestr);
8eab3194 1035
2e73a998
KZ
1036 else if (fdisk_set_partition_type(sf->cxt, partno - 1, type) != 0)
1037 errx(EXIT_FAILURE, _("%s: partition %zu: failed to set partition type"),
1038 devname, partno);
dfc6db2a 1039 fdisk_unref_parttype(type);
351fad50 1040 return write_changes(sf);
3a5bdedf
KZ
1041}
1042
1043/*
e36fb07a 1044 * sfdisk --part-uuid <device> <partno> [<uuid>]
3a5bdedf
KZ
1045 */
1046static int command_partuuid(struct sfdisk *sf, int argc, char **argv)
1047{
3a5bdedf
KZ
1048 size_t partno;
1049 struct fdisk_partition *pa = NULL;
1050 const char *devname = NULL, *uuid = NULL;
1051
1052 if (!argc)
1053 errx(EXIT_FAILURE, _("no disk device specified"));
1054 devname = argv[0];
1055
1056 if (argc < 2)
1057 errx(EXIT_FAILURE, _("no partition number specified"));
1058 partno = strtou32_or_err(argv[1], _("failed to parse partition number"));
1059
1060 if (argc == 3)
1061 uuid = argv[2];
1062 else if (argc > 3)
6e834d67 1063 errx(EXIT_FAILURE, _("unexpected arguments"));
3a5bdedf
KZ
1064
1065 /* read-only if uuid not given */
1066 assign_device_partition(sf, devname, partno, !uuid);
1067
1068 /* print partition uuid */
1069 if (!uuid) {
f0f2be20 1070 const char *str = NULL;
3a5bdedf
KZ
1071
1072 if (fdisk_get_partition(sf->cxt, partno - 1, &pa) == 0)
1073 str = fdisk_partition_get_uuid(pa);
1074 if (!str)
1075 errx(EXIT_FAILURE, _("%s: partition %zu: failed to get partition UUID"),
1076 devname, partno);
1077 printf("%s\n", str);
1078 fdisk_unref_partition(pa);
1079 fdisk_deassign_device(sf->cxt, 1);
1080 return 0;
1081 }
1082
1083 if (sf->backup)
1084 backup_partition_table(sf, devname);
1085
1086 pa = fdisk_new_partition();
1087 if (!pa)
1088 err(EXIT_FAILURE, _("failed to allocate partition object"));
1089
1090 if (fdisk_partition_set_uuid(pa, uuid) != 0 ||
1091 fdisk_set_partition(sf->cxt, partno - 1, pa) != 0)
1092 errx(EXIT_FAILURE, _("%s: partition %zu: failed to set partition UUID"),
1093 devname, partno);
351fad50
KZ
1094 fdisk_unref_partition(pa);
1095 return write_changes(sf);
1096}
1097
1098/*
e36fb07a 1099 * sfdisk --part-label <device> <partno> [<label>]
351fad50 1100 */
e36fb07a 1101static int command_partlabel(struct sfdisk *sf, int argc, char **argv)
351fad50
KZ
1102{
1103 size_t partno;
1104 struct fdisk_partition *pa = NULL;
1105 const char *devname = NULL, *name = NULL;
1106
1107 if (!argc)
1108 errx(EXIT_FAILURE, _("no disk device specified"));
1109 devname = argv[0];
1110
1111 if (argc < 2)
1112 errx(EXIT_FAILURE, _("no partition number specified"));
1113 partno = strtou32_or_err(argv[1], _("failed to parse partition number"));
1114
1115 if (argc == 3)
1116 name = argv[2];
1117 else if (argc > 3)
6e834d67 1118 errx(EXIT_FAILURE, _("unexpected arguments"));
351fad50
KZ
1119
1120 /* read-only if name not given */
1121 assign_device_partition(sf, devname, partno, !name);
1122
1123 /* print partition name */
1124 if (!name) {
f0f2be20 1125 const char *str = NULL;
351fad50
KZ
1126
1127 if (fdisk_get_partition(sf->cxt, partno - 1, &pa) == 0)
1128 str = fdisk_partition_get_name(pa);
1129 if (!str)
1130 errx(EXIT_FAILURE, _("%s: partition %zu: failed to get partition name"),
1131 devname, partno);
1132 printf("%s\n", str);
1133 fdisk_unref_partition(pa);
1134 fdisk_deassign_device(sf->cxt, 1);
1135 return 0;
1136 }
1137
1138 if (sf->backup)
1139 backup_partition_table(sf, devname);
1140
1141 pa = fdisk_new_partition();
1142 if (!pa)
1143 err(EXIT_FAILURE, _("failed to allocate partition object"));
1144
1145 if (fdisk_partition_set_name(pa, name) != 0 ||
1146 fdisk_set_partition(sf->cxt, partno - 1, pa) != 0)
1147 errx(EXIT_FAILURE, _("%s: partition %zu: failed to set partition name"),
1148 devname, partno);
1149
1150 fdisk_unref_partition(pa);
1151 return write_changes(sf);
8eab3194
KZ
1152}
1153
bc9e8547
KZ
1154/*
1155 * sfdisk --part-attrs <device> <partno> [<attrs>]
1156 */
1157static int command_partattrs(struct sfdisk *sf, int argc, char **argv)
1158{
1159 size_t partno;
1160 struct fdisk_partition *pa = NULL;
1161 const char *devname = NULL, *attrs = NULL;
1162
1163 if (!argc)
1164 errx(EXIT_FAILURE, _("no disk device specified"));
1165 devname = argv[0];
1166
1167 if (argc < 2)
1168 errx(EXIT_FAILURE, _("no partition number specified"));
1169 partno = strtou32_or_err(argv[1], _("failed to parse partition number"));
1170
1171 if (argc == 3)
1172 attrs = argv[2];
1173 else if (argc > 3)
6e834d67 1174 errx(EXIT_FAILURE, _("unexpected arguments"));
bc9e8547
KZ
1175
1176 /* read-only if name not given */
1177 assign_device_partition(sf, devname, partno, !attrs);
1178
1179 /* print partition name */
1180 if (!attrs) {
f0f2be20 1181 const char *str = NULL;
bc9e8547
KZ
1182
1183 if (fdisk_get_partition(sf->cxt, partno - 1, &pa) == 0)
1184 str = fdisk_partition_get_attrs(pa);
1185 if (str)
1186 printf("%s\n", str);
1187 fdisk_unref_partition(pa);
1188 fdisk_deassign_device(sf->cxt, 1);
1189 return 0;
1190 }
1191
1192 if (sf->backup)
1193 backup_partition_table(sf, devname);
1194
1195 pa = fdisk_new_partition();
1196 if (!pa)
1197 err(EXIT_FAILURE, _("failed to allocate partition object"));
1198
1199 if (fdisk_partition_set_attrs(pa, attrs) != 0 ||
1200 fdisk_set_partition(sf->cxt, partno - 1, pa) != 0)
1201 errx(EXIT_FAILURE, _("%s: partition %zu: failed to set partition attributes"),
1202 devname, partno);
1203
1204 fdisk_unref_partition(pa);
1205 return write_changes(sf);
1206}
1207
b4df449f 1208static void sfdisk_print_partition(struct sfdisk *sf, size_t n)
7324f1bf 1209{
c3bc7483 1210 struct fdisk_partition *pa = NULL;
7324f1bf
KZ
1211 char *data;
1212
1213 assert(sf);
1214
f0edb076
KZ
1215 if (sf->quiet)
1216 return;
7324f1bf
KZ
1217 if (fdisk_get_partition(sf->cxt, n, &pa) != 0)
1218 return;
1219
1220 fdisk_partition_to_string(pa, sf->cxt, FDISK_FIELD_DEVICE, &data);
1221 printf("%12s : ", data);
1222
1223 fdisk_partition_to_string(pa, sf->cxt, FDISK_FIELD_START, &data);
1224 printf("%12s ", data);
1225
1226 fdisk_partition_to_string(pa, sf->cxt, FDISK_FIELD_END, &data);
1227 printf("%12s ", data);
1228
1229 fdisk_partition_to_string(pa, sf->cxt, FDISK_FIELD_SIZE, &data);
1230 printf("(%s) ", data);
1231
1232 fdisk_partition_to_string(pa, sf->cxt, FDISK_FIELD_TYPE, &data);
1233 printf("%s\n", data);
1234
1235 fdisk_unref_partition(pa);
1236}
1237
3186f4a9
KZ
1238static void command_fdisk_help(void)
1239{
1240 fputs(_("\nHelp:\n"), stdout);
1241
1242 fputc('\n', stdout);
1243 color_scheme_enable("help-title", UL_COLOR_BOLD);
1244 fputs(_(" Commands:\n"), stdout);
1245 color_disable();
e8813494 1246 fputs(_(" write write table to disk and exit\n"), stdout);
6e834d67 1247 fputs(_(" quit show new situation and wait for user's feedback before write\n"), stdout);
e8813494 1248 fputs(_(" abort exit sfdisk shell\n"), stdout);
62eea9ce
BS
1249 fputs(_(" print display the partition table\n"), stdout);
1250 fputs(_(" help show this help text\n"), stdout);
333c3761 1251 fputc('\n', stdout);
62eea9ce 1252 fputs(_(" Ctrl-D the same as 'quit'\n"), stdout);
3186f4a9
KZ
1253
1254 fputc('\n', stdout);
1255 color_scheme_enable("help-title", UL_COLOR_BOLD);
1256 fputs(_(" Input format:\n"), stdout);
1257 color_disable();
6e834d67 1258 fputs(_(" <start>, <size>, <type>, <bootable>\n"), stdout);
3186f4a9
KZ
1259
1260 fputc('\n', stdout);
62eea9ce
BS
1261 fputs(_(" <start> Beginning of the partition in sectors, or bytes if\n"
1262 " specified in the format <number>{K,M,G,T,P,E,Z,Y}.\n"
1263 " The default is the first free space.\n"), stdout);
3186f4a9
KZ
1264
1265 fputc('\n', stdout);
62eea9ce
BS
1266 fputs(_(" <size> Size of the partition in sectors, or bytes if\n"
1267 " specified in the format <number>{K,M,G,T,P,E,Z,Y}.\n"
1268 " The default is all available space.\n"), stdout);
3186f4a9
KZ
1269
1270 fputc('\n', stdout);
62eea9ce 1271 fputs(_(" <type> The partition type. Default is a Linux data partition.\n"), stdout);
3186f4a9 1272 fputs(_(" MBR: hex or L,S,E,X shortcuts.\n"), stdout);
62eea9ce 1273 fputs(_(" GPT: UUID or L,S,H shortcuts.\n"), stdout);
3186f4a9
KZ
1274
1275 fputc('\n', stdout);
62eea9ce 1276 fputs(_(" <bootable> Use '*' to mark an MBR partition as bootable.\n"), stdout);
3186f4a9
KZ
1277
1278 fputc('\n', stdout);
1279 color_scheme_enable("help-title", UL_COLOR_BOLD);
1280 fputs(_(" Example:\n"), stdout);
1281 color_disable();
62eea9ce 1282 fputs(_(" , 4G Creates a 4GiB partition at default start offset.\n"), stdout);
3186f4a9
KZ
1283 fputc('\n', stdout);
1284}
1285
e8813494
KZ
1286enum {
1287 SFDISK_DONE_NONE = 0,
1288 SFDISK_DONE_EOF,
1289 SFDISK_DONE_ABORT,
1290 SFDISK_DONE_WRITE,
1291 SFDISK_DONE_ASK
1292};
1293
1294/* returns: 0 on success, <0 on error, 1 successfully stop sfdisk */
1295static int loop_control_commands(struct sfdisk *sf,
1296 struct fdisk_script *dp,
1297 char *buf)
1298{
1299 const char *p = skip_blank(buf);
1300 int rc = SFDISK_DONE_NONE;
1301
1302 if (strcmp(p, "print") == 0)
1303 list_disklabel(sf->cxt);
1304 else if (strcmp(p, "help") == 0)
1305 command_fdisk_help();
1306 else if (strcmp(p, "quit") == 0)
1307 rc = SFDISK_DONE_ASK;
1308 else if (strcmp(p, "write") == 0)
1309 rc = SFDISK_DONE_WRITE;
1310 else if (strcmp(p, "abort") == 0)
1311 rc = SFDISK_DONE_ABORT;
1312 else {
8be199ea 1313 if (sf->interactive)
e8813494
KZ
1314 fdisk_warnx(sf->cxt, _("unsupported command"));
1315 else {
1316 fdisk_warnx(sf->cxt, _("line %d: unsupported command"),
1317 fdisk_script_get_nlines(dp));
1318 rc = -EINVAL;
1319 }
1320 }
1321 return rc;
1322}
1323
e54b1c6f
KZ
1324static int has_container(struct sfdisk *sf)
1325{
1326 size_t i, nparts;
1327 struct fdisk_partition *pa = NULL;
1328
1329 if (sf->container)
1330 return sf->container;
1331
1332 nparts = fdisk_get_npartitions(sf->cxt);
e54b1c6f
KZ
1333 for (i = 0; i < nparts; i++) {
1334 if (fdisk_get_partition(sf->cxt, i, &pa) != 0)
1335 continue;
1336 if (fdisk_partition_is_container(pa)) {
1337 sf->container = 1;
1338 break;
1339 }
1340 }
1341
1342 fdisk_unref_partition(pa);
1343 return sf->container;
1344}
1345
347a7f77
KZ
1346static size_t last_pt_partno(struct sfdisk *sf)
1347{
1348 size_t i, nparts, partno = 0;
1349 struct fdisk_partition *pa = NULL;
1350
1351
1352 nparts = fdisk_get_npartitions(sf->cxt);
1353 for (i = 0; i < nparts; i++) {
1354 size_t x;
1355
1356 if (fdisk_get_partition(sf->cxt, i, &pa) != 0 ||
1357 !fdisk_partition_is_used(pa))
1358 continue;
1359 x = fdisk_partition_get_partno(pa);
1360 if (x > partno)
1361 partno = x;
1362 }
1363
1364 fdisk_unref_partition(pa);
1365 return partno;
1366}
1367
db48b6a1
KZ
1368static int is_device_used(struct sfdisk *sf)
1369{
1370#ifdef BLKRRPART
1371 struct stat st;
1372 int fd;
1373
1374 assert(sf);
1375 assert(sf->cxt);
1376
1377 fd = fdisk_get_devfd(sf->cxt);
1378 if (fd < 0)
1379 return 0;
1380
a53e37f9
KZ
1381 if (fstat(fd, &st) == 0 && S_ISBLK(st.st_mode)
1382 && major(st.st_rdev) != LOOPDEV_MAJOR)
db48b6a1
KZ
1383 return ioctl(fd, BLKRRPART) != 0;
1384#endif
1385 return 0;
1386}
3186f4a9 1387
3ba8e422 1388#ifdef HAVE_LIBREADLINE
7159b496
KZ
1389static char *sfdisk_fgets(struct fdisk_script *dp,
1390 char *buf, size_t bufsz, FILE *f)
1391{
1392 struct sfdisk *sf = (struct sfdisk *) fdisk_script_get_userdata(dp);
1393
1394 assert(dp);
1395 assert(buf);
1396 assert(bufsz > 2);
1397
3ba8e422 1398 if (sf->interactive) {
7159b496
KZ
1399 char *p = readline(sf->prompt);
1400 size_t len;
1401
1402 if (!p)
1403 return NULL;
1404 len = strlen(p);
1405 if (len > bufsz - 2)
1406 len = bufsz - 2;
1407
1408 memcpy(buf, p, len);
1409 buf[len] = '\n'; /* append \n to be compatible with libc fgetc() */
1410 buf[len + 1] = '\0';
1411 free(p);
3ba8e422 1412 fflush(stdout);
7159b496
KZ
1413 return buf;
1414 }
7159b496
KZ
1415 return fgets(buf, bufsz, f);
1416}
3ba8e422 1417#endif
7159b496 1418
2928068a
KZ
1419static int ignore_partition(struct fdisk_partition *pa)
1420{
1421 /* incomplete partition setting */
1422 if (!fdisk_partition_has_start(pa) && !fdisk_partition_start_is_default(pa))
1423 return 1;
1424 if (!fdisk_partition_has_size(pa) && !fdisk_partition_end_is_default(pa))
1425 return 1;
1426
1427 /* probably dump from old sfdisk with start=0 size=0 */
1428 if (fdisk_partition_has_start(pa) && fdisk_partition_get_start(pa) == 0 &&
1429 fdisk_partition_has_size(pa) && fdisk_partition_get_size(pa) == 0)
1430 return 1;
1431
1432 return 0;
1433}
1434
f42205d8
KZ
1435
1436
254b1dfc
KZ
1437/*
1438 * sfdisk <device> [[-N] <partno>]
1439 *
1440 * Note that the option -N is there for backward compatibility only.
1441 */
7324f1bf 1442static int command_fdisk(struct sfdisk *sf, int argc, char **argv)
9c1f9dd3 1443{
7324f1bf
KZ
1444 int rc = 0, partno = sf->partno, created = 0;
1445 struct fdisk_script *dp;
1446 struct fdisk_table *tb = NULL;
1447 const char *devname = NULL, *label;
1448 char buf[BUFSIZ];
c3bc7483 1449 size_t next_partno = (size_t) -1;
9c1f9dd3 1450
8a8d204c
KZ
1451 if (argc)
1452 devname = argv[0];
254b1dfc 1453 if (partno < 0 && argc > 1)
54b13b0c 1454 partno = strtou32_or_err(argv[1],
9c1f9dd3 1455 _("failed to parse partition number"));
8a8d204c 1456 if (!devname)
9c1f9dd3
KZ
1457 errx(EXIT_FAILURE, _("no disk device specified"));
1458
347a7f77
KZ
1459 rc = fdisk_assign_device(sf->cxt, devname, 0);
1460 if (rc)
1461 err(EXIT_FAILURE, _("cannot open %s"), devname);
b4df449f 1462
7324f1bf
KZ
1463 dp = fdisk_new_script(sf->cxt);
1464 if (!dp)
1465 err(EXIT_FAILURE, _("failed to allocate script handler"));
347a7f77 1466 fdisk_set_script(sf->cxt, dp);
3ba8e422 1467#ifdef HAVE_LIBREADLINE
7159b496 1468 fdisk_script_set_fgets(dp, sfdisk_fgets);
3ba8e422 1469#endif
7159b496 1470 fdisk_script_set_userdata(dp, (void *) sf);
9c1f9dd3 1471
b4df449f
KZ
1472 /*
1473 * Don't create a new disklabel when [-N] <partno> specified. In this
1474 * case reuse already specified disklabel. Let's check that the disk
1475 * really contains the partition.
1476 */
1477 if (partno >= 0) {
1478 size_t n;
d754d554 1479
b4df449f 1480 if (!fdisk_has_label(sf->cxt))
54fefa07
BS
1481 errx(EXIT_FAILURE, _("%s: cannot modify partition %d: "
1482 "no partition table was found"),
d754d554 1483 devname, partno + 1);
b4df449f
KZ
1484 n = fdisk_get_npartitions(sf->cxt);
1485 if ((size_t) partno > n)
54fefa07
BS
1486 errx(EXIT_FAILURE, _("%s: cannot modify partition %d: "
1487 "partition table contains only %zu "
1488 "partitions"),
d754d554
KZ
1489 devname, partno + 1, n);
1490
1491 if (!fdisk_is_partition_used(sf->cxt, partno))
1492 fdisk_warnx(sf->cxt, _("warning: %s: partition %d is not defined yet"),
1493 devname, partno + 1);
b4df449f
KZ
1494 created = 1;
1495 next_partno = partno;
f42205d8
KZ
1496
1497 if (sf->movedata)
1498 sf->orig_pa = get_partition(sf->cxt, partno);
b4df449f
KZ
1499 }
1500
347a7f77
KZ
1501 if (sf->append) {
1502 created = 1;
1503 next_partno = last_pt_partno(sf) + 1;
1504 }
1505
8be199ea 1506 if (!sf->quiet && sf->interactive) {
3186f4a9
KZ
1507 color_scheme_enable("welcome", UL_COLOR_GREEN);
1508 fdisk_info(sf->cxt, _("\nWelcome to sfdisk (%s)."), PACKAGE_STRING);
1509 color_disable();
1510 fdisk_info(sf->cxt, _("Changes will remain in memory only, until you decide to write them.\n"
1511 "Be careful before using the write command.\n"));
1512 }
1513
db48b6a1
KZ
1514 if (!sf->noact && !sf->noreread) {
1515 if (!sf->quiet)
1516 fputs(_("Checking that no-one is using this disk right now ..."), stdout);
1517 if (is_device_used(sf)) {
9d9a1b87
KZ
1518 if (!sf->quiet)
1519 fputs(_(" FAILED\n\n"), stdout);
db48b6a1
KZ
1520
1521 fdisk_warnx(sf->cxt, _(
1522 "This disk is currently in use - repartitioning is probably a bad idea.\n"
1523 "Umount all file systems, and swapoff all swap partitions on this disk.\n"
1524 "Use the --no-reread flag to suppress this check.\n"));
1525
1526 if (!sf->force)
1527 errx(EXIT_FAILURE, _("Use the --force flag to overrule all checks."));
9d9a1b87 1528 } else if (!sf->quiet)
db48b6a1
KZ
1529 fputs(_(" OK\n\n"), stdout);
1530 }
1531
15b5e942
KZ
1532 if (fdisk_get_collision(sf->cxt)) {
1533 int dowipe = sf->wipemode == WIPEMODE_ALWAYS ? 1 : 0;
1534
1535 fdisk_warnx(sf->cxt, _("%s: device already contains %s signature."),
1536 devname, fdisk_get_collision(sf->cxt));
1537
1538 if (sf->interactive && sf->wipemode == WIPEMODE_AUTO)
1539 dowipe = 1; /* do it in interactive mode */
1540
1541 fdisk_enable_wipe(sf->cxt, dowipe);
1542 if (dowipe)
1543 fdisk_warnx(sf->cxt, _(
1544 "The signature will be removed by write command."));
1545 else
1546 fdisk_warnx(sf->cxt, _(
1547 "It is strongly recommended to wipe the device with "
1548 "wipefs(8), in order to avoid possible collisions."));
1549 fputc('\n', stderr);
1550 }
1551
ab02d87e
KZ
1552 if (sf->backup)
1553 backup_partition_table(sf, devname);
1554
f0edb076
KZ
1555 if (!sf->quiet) {
1556 list_disk_geometry(sf->cxt);
1557 if (fdisk_has_label(sf->cxt)) {
1558 fdisk_info(sf->cxt, _("\nOld situation:"));
1559 list_disklabel(sf->cxt);
1560 }
3186f4a9 1561 }
7324f1bf
KZ
1562
1563 if (sf->label)
1564 label = sf->label;
1565 else if (fdisk_has_label(sf->cxt))
1566 label = fdisk_label_get_name(fdisk_get_label(sf->cxt, NULL));
1567 else
1568 label = "dos"; /* just for backward compatibility */
1569
1570 fdisk_script_set_header(dp, "label", label);
1571
15b5e942 1572
8be199ea 1573 if (!sf->quiet && sf->interactive) {
3186f4a9
KZ
1574 if (!fdisk_has_label(sf->cxt) && !sf->label)
1575 fdisk_info(sf->cxt,
1576 _("\nsfdisk is going to create a new '%s' disk label.\n"
1577 "Use 'label: <name>' before you define a first partition\n"
1578 "to override the default."), label);
1579 fdisk_info(sf->cxt, _("\nType 'help' to get more information.\n"));
f0edb076 1580 } else if (!sf->quiet)
3186f4a9 1581 fputc('\n', stdout);
7324f1bf
KZ
1582
1583 tb = fdisk_script_get_table(dp);
c3bc7483 1584 assert(tb);
7324f1bf
KZ
1585
1586 do {
c3bc7483 1587 size_t nparts;
7324f1bf 1588
c3bc7483
KZ
1589 DBG(PARSE, ul_debug("<---next-line--->"));
1590 if (next_partno == (size_t) -1)
1591 next_partno = fdisk_table_get_nents(tb);
1592
e54b1c6f
KZ
1593 if (created
1594 && partno < 0
347a7f77 1595 && next_partno == fdisk_get_npartitions(sf->cxt)
e54b1c6f
KZ
1596 && !has_container(sf)) {
1597 fdisk_info(sf->cxt, _("All partitions used."));
1598 rc = SFDISK_DONE_ASK;
1599 break;
1600 }
1601
3186f4a9
KZ
1602 if (created) {
1603 char *partname = fdisk_partname(devname, next_partno + 1);
1604 if (!partname)
1605 err(EXIT_FAILURE, _("failed to allocate partition name"));
7159b496
KZ
1606 if (!sf->prompt || !startswith(sf->prompt, partname)) {
1607 free(sf->prompt);
1608 xasprintf(&sf->prompt,"%s: ", partname);
1609 }
3186f4a9 1610 free(partname);
7159b496
KZ
1611 } else if (!sf->prompt || !startswith(sf->prompt, SFDISK_PROMPT)) {
1612 free(sf->prompt);
1613 sf->prompt = xstrdup(SFDISK_PROMPT);
1614 }
7324f1bf 1615
c809b20a 1616 if (sf->prompt && (sf->interactive || !sf->quiet)) {
3ba8e422 1617#ifndef HAVE_LIBREADLINE
3ba8e422
KZ
1618 fputs(sf->prompt, stdout);
1619#else
c809b20a
KZ
1620 if (!sf->interactive)
1621 fputs(sf->prompt, stdout);
3ba8e422 1622#endif
c809b20a
KZ
1623 }
1624
7324f1bf 1625 rc = fdisk_script_read_line(dp, stdin, buf, sizeof(buf));
e8813494 1626 if (rc < 0) {
c3bc7483 1627 DBG(PARSE, ul_debug("script parsing failed, trying sfdisk specific commands"));
7324f1bf 1628 buf[sizeof(buf) - 1] = '\0';
e8813494
KZ
1629 rc = loop_control_commands(sf, dp, buf);
1630 if (rc)
7324f1bf 1631 break;
7324f1bf 1632 continue;
e8813494
KZ
1633 } else if (rc == 1) {
1634 rc = SFDISK_DONE_EOF;
1635 break;
7324f1bf
KZ
1636 }
1637
1638 nparts = fdisk_table_get_nents(tb);
1639 if (nparts) {
c3bc7483 1640 size_t cur_partno;
7324f1bf
KZ
1641 struct fdisk_partition *pa = fdisk_table_get_partition(tb, nparts - 1);
1642
c3bc7483 1643 assert(pa);
3186f4a9 1644
2928068a
KZ
1645 if (ignore_partition(pa)) {
1646 fdisk_info(sf->cxt, _("Ignoring partition."));
1647 next_partno++;
3186f4a9
KZ
1648 continue;
1649 }
b4df449f 1650 if (!created) { /* create a new disklabel */
7324f1bf
KZ
1651 rc = fdisk_apply_script_headers(sf->cxt, dp);
1652 created = !rc;
90dc69e4
KZ
1653 if (rc)
1654 fdisk_warnx(sf->cxt, _(
1655 "Failed to apply script headers, "
1656 "disk label not created."));
7324f1bf 1657 }
b4df449f 1658 if (!rc && partno >= 0) { /* -N <partno>, modify partition */
0ecf3ab5 1659 rc = fdisk_set_partition(sf->cxt, partno, pa);
31c79e18 1660 rc = rc == 0 ? SFDISK_DONE_ASK : SFDISK_DONE_ABORT;
b4df449f 1661 break;
a8a4887b 1662 } else if (!rc) { /* add partition */
c3bc7483 1663 rc = fdisk_add_partition(sf->cxt, pa, &cur_partno);
a8a4887b
KZ
1664 if (rc) {
1665 errno = -rc;
90dc69e4 1666 fdisk_warn(sf->cxt, _("Failed to add partition"));
a8a4887b
KZ
1667 }
1668 }
7324f1bf 1669
c3bc7483 1670 if (!rc) { /* success, print reult */
8be199ea
KZ
1671 if (sf->interactive)
1672 sfdisk_print_partition(sf, cur_partno);
c3bc7483 1673 next_partno = cur_partno + 1;
90dc69e4 1674 } else if (pa) /* error, drop partition from script */
7324f1bf
KZ
1675 fdisk_table_remove_partition(tb, pa);
1676 } else
3186f4a9 1677 fdisk_info(sf->cxt, _("Script header accepted."));
e54b1c6f 1678
90dc69e4
KZ
1679 if (rc && !sf->interactive) {
1680 rc = SFDISK_DONE_ABORT;
1681 break;
1682 }
7324f1bf 1683 } while (1);
254b1dfc 1684
f0edb076 1685 if (!sf->quiet && rc != SFDISK_DONE_ABORT) {
3186f4a9 1686 fdisk_info(sf->cxt, _("\nNew situation:"));
7324f1bf
KZ
1687 list_disklabel(sf->cxt);
1688 }
e8813494
KZ
1689
1690 switch (rc) {
1691 case SFDISK_DONE_ASK:
05af8bd4 1692 case SFDISK_DONE_EOF:
8be199ea 1693 if (sf->interactive) {
e8813494
KZ
1694 int yes = 0;
1695 fdisk_ask_yesno(sf->cxt, _("Do you want to write this to disk?"), &yes);
1696 if (!yes) {
f01f2528 1697 fdisk_info(sf->cxt, _("Leaving."));
e8813494
KZ
1698 rc = 0;
1699 break;
1700 }
1701 }
e8813494 1702 case SFDISK_DONE_WRITE:
351fad50 1703 rc = write_changes(sf);
e8813494
KZ
1704 break;
1705 case SFDISK_DONE_ABORT:
b4df449f 1706 default: /* rc < 0 on error */
f0edb076 1707 fdisk_info(sf->cxt, _("Leaving.\n"));
e8813494 1708 break;
3186f4a9 1709 }
e8813494 1710
7324f1bf 1711 fdisk_unref_script(dp);
9c1f9dd3
KZ
1712 return rc;
1713}
1714
1881390d
KZ
1715static void __attribute__ ((__noreturn__)) usage(FILE *out)
1716{
1717 fputs(USAGE_HEADER, out);
fd6b7a7f 1718
1881390d 1719 fprintf(out,
43a1ccec
KZ
1720 _(" %1$s [options] <dev> [[-N] <part>]\n"
1721 " %1$s [options] <command>\n"), program_invocation_short_name);
1722
451dbcfa
BS
1723 fputs(USAGE_SEPARATOR, out);
1724 fputs(_("Display or manipulate a disk partition table.\n"), out);
1725
43a1ccec 1726 fputs(_("\nCommands:\n"), out);
703ab082 1727 fputs(_(" -A, --activate <dev> [<part> ...] list or set bootable MBR partitions\n"), out);
d420a7f9 1728 fputs(_(" -d, --dump <dev> dump partition table (usable for later input)\n"), out);
a592b4b5 1729 fputs(_(" -J, --json <dev> dump partition table in JSON format\n"), out);
d420a7f9
KZ
1730 fputs(_(" -g, --show-geometry [<dev> ...] list geometry of all or specified devices\n"), out);
1731 fputs(_(" -l, --list [<dev> ...] list partitions of each device\n"), out);
8abdb912 1732 fputs(_(" -F, --list-free [<dev> ...] list unpartitions free areas of each device\n"), out);
9a17d946 1733 fputs(_(" -r, --reorder <dev> fix partitions order (by start offset)\n"), out);
43a1ccec
KZ
1734 fputs(_(" -s, --show-size [<dev> ...] list sizes of all or specified devices\n"), out);
1735 fputs(_(" -T, --list-types print the recognized types (see -X)\n"), out);
3f43f5d0 1736 fputs(_(" -V, --verify [<dev> ...] test whether partitions seem correct\n"), out);
aab9be66 1737 fputs(_(" --delete <dev> [<part> ...] delete all or specified partitions\n"), out);
43a1ccec 1738
e36fb07a
KZ
1739 fputs(USAGE_SEPARATOR, out);
1740 fputs(_(" --part-label <dev> <part> [<str>] print or change partition label\n"), out);
1741 fputs(_(" --part-type <dev> <part> [<type>] print or change partition type\n"), out);
1742 fputs(_(" --part-uuid <dev> <part> [<uuid>] print or change partition uuid\n"), out);
bc9e8547 1743 fputs(_(" --part-attrs <dev> <part> [<str>] print or change partition attributes\n"), out);
e36fb07a 1744
43a1ccec 1745 fputs(USAGE_SEPARATOR, out);
ab02d87e
KZ
1746 fputs(_(" <dev> device (usually disk) path\n"), out);
1747 fputs(_(" <part> partition number\n"), out);
1748 fputs(_(" <type> partition type, GUID for GPT, hex for MBR\n"), out);
fd6b7a7f 1749
1881390d 1750 fputs(USAGE_OPTIONS, out);
703ab082 1751 fputs(_(" -a, --append append partitions to existing partition table\n"), out);
ab02d87e 1752 fputs(_(" -b, --backup backup partition table sectors (see -O)\n"), out);
57eae223 1753 fputs(_(" --bytes print SIZE in bytes rather than in human readable format\n"), out);
f42205d8 1754 fputs(_(" --move-data[=<typescript>] move partition data after relocation (requires -N)\n"), out);
ab02d87e 1755 fputs(_(" -f, --force disable all consistency checking\n"), out);
da25898b
KZ
1756 fputs(_(" --color[=<when>] colorize output (auto, always or never)\n"), out);
1757 fprintf(out,
1758 " %s\n", USAGE_COLORS_DEFAULT);
ab02d87e 1759 fputs(_(" -N, --partno <num> specify partition number\n"), out);
ab02d87e
KZ
1760 fputs(_(" -n, --no-act do everything except write to device\n"), out);
1761 fputs(_(" --no-reread do not check whether the device is in use\n"), out);
57eae223
BS
1762 fputs(_(" -O, --backup-file <path> override default backup file name\n"), out);
1763 fputs(_(" -o, --output <list> output columns\n"), out);
1764 fputs(_(" -q, --quiet suppress extra info messages\n"), out);
15b5e942 1765 fputs(_(" -w, --wipe <mode> wipe signatures (auto, always or never)\n"), out);
57eae223
BS
1766 fputs(_(" -X, --label <name> specify label type (dos, gpt, ...)\n"), out);
1767 fputs(_(" -Y, --label-nested <name> specify nested label type (dos, bsd)\n"), out);
35ce145f 1768 fputs(USAGE_SEPARATOR, out);
6e834d67 1769 fputs(_(" -L, --Linux deprecated, only for backward compatibility\n"), out);
57eae223 1770 fputs(_(" -u, --unit S deprecated, only sector unit is supported\n"), out);
058dd97a 1771
1881390d
KZ
1772 fputs(USAGE_SEPARATOR, out);
1773 fputs(USAGE_HELP, out);
edac3e2c 1774 fputs(_(" -v, --version output version information and exit\n"), out);
fd6b7a7f 1775
01f9286c
KZ
1776 list_available_columns(out);
1777
1881390d
KZ
1778 fprintf(out, USAGE_MAN_TAIL("sfdisk(8)"));
1779 exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
fd6b7a7f
KZ
1780}
1781
9c1f9dd3 1782
1881390d
KZ
1783int main(int argc, char *argv[])
1784{
01f9286c 1785 const char *outarg = NULL;
8de07279 1786 int rc = -EINVAL, c, longidx = -1, bytes = 0;
da25898b 1787 int colormode = UL_COLORMODE_UNDEF;
7324f1bf 1788 struct sfdisk _sf = {
8be199ea 1789 .partno = -1,
15b5e942 1790 .wipemode = WIPEMODE_AUTO,
8be199ea 1791 .interactive = isatty(STDIN_FILENO) ? 1 : 0,
7324f1bf 1792 }, *sf = &_sf;
1881390d 1793
8eab3194
KZ
1794 enum {
1795 OPT_CHANGE_ID = CHAR_MAX + 1,
1796 OPT_PRINT_ID,
db48b6a1 1797 OPT_ID,
351fad50 1798 OPT_NOREREAD,
e36fb07a
KZ
1799 OPT_PARTUUID,
1800 OPT_PARTLABEL,
1801 OPT_PARTTYPE,
bc9e8547 1802 OPT_PARTATTRS,
da25898b 1803 OPT_BYTES,
f42205d8
KZ
1804 OPT_COLOR,
1805 OPT_MOVEDATA,
aab9be66 1806 OPT_DELETE
8eab3194
KZ
1807 };
1808
1881390d 1809 static const struct option longopts[] = {
703ab082
KZ
1810 { "activate",no_argument, NULL, 'A' },
1811 { "append", no_argument, NULL, 'a' },
ab02d87e
KZ
1812 { "backup", no_argument, NULL, 'b' },
1813 { "backup-file", required_argument, NULL, 'O' },
354f8cc8 1814 { "bytes", no_argument, NULL, OPT_BYTES },
da25898b 1815 { "color", optional_argument, NULL, OPT_COLOR },
aab9be66 1816 { "delete", no_argument, NULL, OPT_DELETE },
8a8d204c 1817 { "dump", no_argument, NULL, 'd' },
1881390d 1818 { "help", no_argument, NULL, 'h' },
db48b6a1 1819 { "force", no_argument, NULL, 'f' },
a592b4b5 1820 { "json", no_argument, NULL, 'J' },
7324f1bf 1821 { "label", required_argument, NULL, 'X' },
e1422de3 1822 { "label-nested", required_argument, NULL, 'Y' },
d2c47697 1823 { "list", no_argument, NULL, 'l' },
8abdb912 1824 { "list-free", no_argument, NULL, 'F' },
058dd97a 1825 { "list-types", no_argument, NULL, 'T' },
f01f2528 1826 { "no-act", no_argument, NULL, 'n' },
db48b6a1 1827 { "no-reread", no_argument, NULL, OPT_NOREREAD },
f42205d8 1828 { "move-data", optional_argument, NULL, OPT_MOVEDATA },
01f9286c 1829 { "output", required_argument, NULL, 'o' },
d2c47697 1830 { "partno", required_argument, NULL, 'N' },
9a17d946 1831 { "reorder", no_argument, NULL, 'r' },
d2c47697 1832 { "show-size", no_argument, NULL, 's' },
d420a7f9 1833 { "show-geometry", no_argument, NULL, 'g' },
f0edb076 1834 { "quiet", no_argument, NULL, 'q' },
d2c47697
KZ
1835 { "verify", no_argument, NULL, 'V' },
1836 { "version", no_argument, NULL, 'v' },
15b5e942 1837 { "wipe", required_argument, NULL, 'w' },
e36fb07a
KZ
1838
1839 { "part-uuid", no_argument, NULL, OPT_PARTUUID },
1840 { "part-label", no_argument, NULL, OPT_PARTLABEL },
1841 { "part-type", no_argument, NULL, OPT_PARTTYPE },
bc9e8547 1842 { "part-attrs", no_argument, NULL, OPT_PARTATTRS },
35ce145f 1843
8be199ea 1844 { "unit", required_argument, NULL, 'u' },
35ce145f 1845 { "Linux", no_argument, NULL, 'L' }, /* deprecated */
8eab3194 1846
8eab3194 1847 { "change-id",no_argument, NULL, OPT_CHANGE_ID }, /* deprecated */
e36fb07a 1848 { "id", no_argument, NULL, 'c' }, /* deprecated */
8eab3194
KZ
1849 { "print-id",no_argument, NULL, OPT_PRINT_ID }, /* deprecated */
1850
1881390d
KZ
1851 { NULL, 0, 0, 0 },
1852 };
1853
1854 setlocale(LC_ALL, "");
1855 bindtextdomain(PACKAGE, LOCALEDIR);
1856 textdomain(PACKAGE);
1857 atexit(close_stdout);
1858
15b5e942 1859 while ((c = getopt_long(argc, argv, "aAbcdfFghJlLo:O:nN:qrsTu:vVX:Y:w:",
8eab3194 1860 longopts, &longidx)) != -1) {
1881390d 1861 switch(c) {
703ab082 1862 case 'A':
54b13b0c
KZ
1863 sf->act = ACT_ACTIVATE;
1864 break;
703ab082 1865 case 'a':
347a7f77
KZ
1866 sf->append = 1;
1867 break;
ab02d87e
KZ
1868 case 'b':
1869 sf->backup = 1;
1870 break;
8eab3194
KZ
1871 case OPT_CHANGE_ID:
1872 case OPT_PRINT_ID:
1873 case OPT_ID:
6e834d67 1874 warnx(_("%s is deprecated in favour of --part-type"),
8eab3194 1875 longopts[longidx].name);
e36fb07a 1876 sf->act = ACT_PARTTYPE;
54efd378 1877 break;
8eab3194 1878 case 'c':
6e834d67 1879 warnx(_("--id is deprecated in favour of --part-type"));
8eab3194
KZ
1880 sf->act = ACT_PARTTYPE;
1881 break;
a592b4b5
KZ
1882 case 'J':
1883 sf->json = 1;
1884 /* fallthrough */
e36fb07a
KZ
1885 case 'd':
1886 sf->act = ACT_DUMP;
1887 break;
8abdb912
KZ
1888 case 'F':
1889 sf->act = ACT_LIST_FREE;
1890 break;
db48b6a1
KZ
1891 case 'f':
1892 sf->force = 1;
1893 break;
e36fb07a
KZ
1894 case 'g':
1895 sf->act = ACT_SHOW_GEOM;
1896 break;
1881390d
KZ
1897 case 'h':
1898 usage(stdout);
1899 break;
9c1f9dd3
KZ
1900 case 'l':
1901 sf->act = ACT_LIST;
1902 break;
35ce145f 1903 case 'L':
e36fb07a 1904 warnx(_("--Linux option is unnecessary and deprecated"));
35ce145f 1905 break;
01f9286c
KZ
1906 case 'o':
1907 outarg = optarg;
1908 break;
ab02d87e
KZ
1909 case 'O':
1910 sf->backup = 1;
1911 sf->backup_file = optarg;
1912 break;
f01f2528
KZ
1913 case 'n':
1914 sf->noact = 1;
1915 break;
254b1dfc 1916 case 'N':
b4df449f 1917 sf->partno = strtou32_or_err(optarg, _("failed to parse partition number")) - 1;
7324f1bf 1918 break;
f0edb076
KZ
1919 case 'q':
1920 sf->quiet = 1;
1921 break;
9a17d946
KZ
1922 case 'r':
1923 sf->act = ACT_REORDER;
1924 break;
d2eb1457
KZ
1925 case 's':
1926 sf->act = ACT_SHOW_SIZE;
1927 break;
058dd97a
KZ
1928 case 'T':
1929 sf->act = ACT_LIST_TYPES;
1930 break;
d420a7f9 1931 case 'u':
d420a7f9 1932 if (*optarg != 'S')
54fefa07 1933 errx(EXIT_FAILURE, _("unsupported unit '%c'"), *optarg);
d420a7f9 1934 break;
1881390d
KZ
1935 case 'v':
1936 printf(_("%s from %s\n"), program_invocation_short_name,
1937 PACKAGE_STRING);
1938 return EXIT_SUCCESS;
d2c47697
KZ
1939 case 'V':
1940 sf->verify = 1;
1941 break;
15b5e942
KZ
1942 case 'w':
1943 sf->wipemode = wipemode_from_string(optarg);
1944 if (sf->wipemode < 0)
1945 errx(EXIT_FAILURE, _("unsupported wipe mode"));
1946 break;
e36fb07a
KZ
1947 case 'X':
1948 sf->label = optarg;
1949 break;
e1422de3
KZ
1950 case 'Y':
1951 sf->label_nested = optarg;
1952 break;
e36fb07a
KZ
1953
1954 case OPT_PARTUUID:
1955 sf->act = ACT_PARTUUID;
1956 break;
1957 case OPT_PARTTYPE:
1958 sf->act = ACT_PARTTYPE;
1959 break;
1960 case OPT_PARTLABEL:
1961 sf->act = ACT_PARTLABEL;
351fad50 1962 break;
bc9e8547
KZ
1963 case OPT_PARTATTRS:
1964 sf->act = ACT_PARTATTRS;
1965 break;
db48b6a1
KZ
1966 case OPT_NOREREAD:
1967 sf->noreread = 1;
1968 break;
354f8cc8 1969 case OPT_BYTES:
8de07279 1970 bytes = 1;
354f8cc8 1971 break;
da25898b
KZ
1972 case OPT_COLOR:
1973 colormode = UL_COLORMODE_AUTO;
1974 if (optarg)
1975 colormode = colormode_or_err(optarg,
1976 _("unsupported color mode"));
1977 break;
f42205d8
KZ
1978 case OPT_MOVEDATA:
1979 sf->movedata = 1;
1980 sf->move_typescript = optarg;
1981 break;
aab9be66
KZ
1982 case OPT_DELETE:
1983 sf->act = ACT_DELETE;
1984 break;
7324f1bf
KZ
1985 default:
1986 usage(stderr);
37b94458 1987 }
37b94458 1988 }
fd6b7a7f 1989
da25898b
KZ
1990 colors_init(colormode, "sfdisk");
1991
8de07279
KZ
1992 sfdisk_init(sf);
1993 if (bytes)
1994 fdisk_set_size_unit(sf->cxt, FDISK_SIZEUNIT_BYTES);
1995
01f9286c
KZ
1996 if (outarg)
1997 init_fields(NULL, outarg, NULL);
22853e4a 1998
d2c47697
KZ
1999 if (sf->verify && !sf->act)
2000 sf->act = ACT_VERIFY; /* --verify make be used with --list too */
2001 else if (!sf->act)
2002 sf->act = ACT_FDISK; /* default */
2003
f42205d8
KZ
2004 if (sf->movedata && !(sf->act == ACT_FDISK && sf->partno >= 0))
2005 errx(EXIT_FAILURE, _("--movedata requires -N"));
2006
9c1f9dd3 2007 switch (sf->act) {
54b13b0c
KZ
2008 case ACT_ACTIVATE:
2009 rc = command_activate(sf, argc - optind, argv + optind);
2010 break;
2011
aab9be66
KZ
2012 case ACT_DELETE:
2013 rc = command_delete(sf, argc - optind, argv + optind);
2014 break;
2015
9c1f9dd3
KZ
2016 case ACT_LIST:
2017 rc = command_list_partitions(sf, argc - optind, argv + optind);
2018 break;
fd6b7a7f 2019
058dd97a
KZ
2020 case ACT_LIST_TYPES:
2021 rc = command_list_types(sf);
2022 break;
2023
8abdb912
KZ
2024 case ACT_LIST_FREE:
2025 rc = command_list_freespace(sf, argc - optind, argv + optind);
2026 break;
2027
9c1f9dd3 2028 case ACT_FDISK:
7324f1bf 2029 rc = command_fdisk(sf, argc - optind, argv + optind);
9c1f9dd3 2030 break;
8a8d204c
KZ
2031
2032 case ACT_DUMP:
2033 rc = command_dump(sf, argc - optind, argv + optind);
2034 break;
d2eb1457
KZ
2035
2036 case ACT_SHOW_SIZE:
2037 rc = command_show_size(sf, argc - optind, argv + optind);
2038 break;
d2c47697 2039
d420a7f9
KZ
2040 case ACT_SHOW_GEOM:
2041 rc = command_show_geometry(sf, argc - optind, argv + optind);
2042 break;
2043
d2c47697
KZ
2044 case ACT_VERIFY:
2045 rc = command_verify(sf, argc - optind, argv + optind);
2046 break;
8eab3194
KZ
2047
2048 case ACT_PARTTYPE:
2049 rc = command_parttype(sf, argc - optind, argv + optind);
2050 break;
3a5bdedf
KZ
2051
2052 case ACT_PARTUUID:
2053 rc = command_partuuid(sf, argc - optind, argv + optind);
2054 break;
2055
e36fb07a
KZ
2056 case ACT_PARTLABEL:
2057 rc = command_partlabel(sf, argc - optind, argv + optind);
351fad50
KZ
2058 break;
2059
bc9e8547
KZ
2060 case ACT_PARTATTRS:
2061 rc = command_partattrs(sf, argc - optind, argv + optind);
2062 break;
2063
9a17d946
KZ
2064 case ACT_REORDER:
2065 rc = command_reorder(sf, argc - optind, argv + optind);
2066 break;
9c1f9dd3 2067 }
fd6b7a7f 2068
9c1f9dd3 2069 sfdisk_deinit(sf);
fd6b7a7f 2070
1881390d
KZ
2071 DBG(MISC, ul_debug("bye! [rc=%d]", rc));
2072 return rc == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
4b1cc035
KZ
2073}
2074