]> git.ipfire.org Git - thirdparty/util-linux.git/blame - disk-utils/fdisk.c
blockdev: check return when read from sysfs [coverity scan]
[thirdparty/util-linux.git] / disk-utils / fdisk.c
CommitLineData
3f0ac587 1/*
6dbe3af9 2 * Copyright (C) 1992 A. V. Le Blanc (LeBlanc@mcc.ac.uk)
38b36353 3 * Copyright (C) 2012 Davidlohr Bueso <dave@gnu.org>
6dbe3af9 4 *
3f0ac587
KZ
5 * Copyright (C) 2007-2013 Karel Zak <kzak@redhat.com>
6 *
6dbe3af9
KZ
7 * This program is free software. You can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation: either version 1 or
10 * (at your option) any later version.
6dbe3af9 11 */
6dbe3af9
KZ
12#include <unistd.h>
13#include <stdio.h>
14#include <stdlib.h>
15#include <string.h>
16#include <fcntl.h>
17#include <ctype.h>
6dbe3af9 18#include <errno.h>
2b6fc908 19#include <getopt.h>
2b6fc908 20#include <sys/stat.h>
f26873dc 21#include <sys/time.h>
bb6aacfe 22#include <time.h>
ee5355e0 23#include <limits.h>
d44115f3 24#include <libsmartcols.h>
6dbe3af9 25
3f0ac587 26#include "c.h"
52b38677 27#include "xalloc.h"
e916600f 28#include "all-io.h"
22853e4a 29#include "nls.h"
e66ac5d3 30#include "rpmatch.h"
810f986b 31#include "blkdev.h"
b8d22034 32#include "mbsalign.h"
6bec8710
KZ
33#include "pathnames.h"
34#include "canonicalize.h"
20aa2570 35#include "strutils.h"
b2d28533 36#include "closestream.h"
a22c6eb2 37#include "sysfs.h"
5c36a0eb 38
fdb006e8
KZ
39#include "fdisk.h"
40
b4bfbadd 41#include "pt-sun.h" /* to toggle flags */
5c36a0eb 42
48d7b13a 43#ifdef HAVE_LINUX_COMPILER_H
3f0ac587 44# include <linux/compiler.h>
48d7b13a
KZ
45#endif
46#ifdef HAVE_LINUX_BLKPG_H
3f0ac587 47# include <linux/blkpg.h>
7eda085c 48#endif
6dbe3af9 49
e6d0c4c1
KZ
50/*
51 * fdisk debug stuff (see fdisk.h and include/debug.h)
52 */
53UL_DEBUG_DEFINE_MASK(fdisk);
819d9a29 54UL_DEBUG_DEFINE_MASKNAMES(fdisk) = UL_DEBUG_EMPTY_MASKNAMES;
d6b3ba41 55
e6d0c4c1
KZ
56static void fdiskprog_init_debug(void)
57{
58 __UL_INIT_DEBUG(fdisk, FDISKPROG_DEBUG_, 0, FDISK_DEBUG);
59}
d6b3ba41
KZ
60
61int get_user_reply(struct fdisk_context *cxt, const char *prompt,
62 char *buf, size_t bufsz)
63{
64 char *p;
65 size_t sz;
66
67 do {
68 fputs(prompt, stdout);
69 fflush(stdout);
70
71 if (!fgets(buf, bufsz, stdin)) {
8eccde20 72 if (fdisk_label_is_changed(fdisk_get_label(cxt, NULL))) {
d6b3ba41
KZ
73 fprintf(stderr, _("\nDo you really want to quit? "));
74
75 if (fgets(buf, bufsz, stdin) && !rpmatch(buf))
76 continue;
77 }
c7119037 78 fdisk_unref_context(cxt);
d6b3ba41
KZ
79 exit(EXIT_FAILURE);
80 } else
81 break;
82 } while (1);
83
84 for (p = buf; *p && !isgraph(*p); p++); /* get first non-blank */
85
86 if (p > buf)
87 memmove(buf, p, p - buf); /* remove blank space */
88 sz = strlen(buf);
89 if (sz && *(buf + sz - 1) == '\n')
90 *(buf + sz - 1) = '\0';
91
88141067 92 DBG(ASK, ul_debug("user's reply: >>>%s<<<", buf));
d6b3ba41
KZ
93 return 0;
94}
95
96static int ask_menu(struct fdisk_context *cxt, struct fdisk_ask *ask,
97 char *buf, size_t bufsz)
98
99{
100 const char *q = fdisk_ask_get_query(ask);
101 int dft = fdisk_ask_menu_get_default(ask);
102
103 if (q) {
104 fputs(q, stdout); /* print header */
105 fputc('\n', stdout);
106 }
107
108 do {
109 char prompt[128];
110 int key, c;
111 const char *name, *desc;
112 size_t i = 0;
113
114 /* print menu items */
115 while (fdisk_ask_menu_get_item(ask, i++, &key, &name, &desc) == 0)
116 fprintf(stdout, " %c %s (%s)\n", key, name, desc);
117
118 /* ask for key */
119 snprintf(prompt, sizeof(prompt), _("Select (default %c): "), dft);
120 get_user_reply(cxt, prompt, buf, bufsz);
121 if (!*buf) {
122 fdisk_info(cxt, _("Using default response %c."), dft);
123 c = dft;
124 } else
125 c = tolower(buf[0]);
126
127 /* check result */
128 i = 0;
129 while (fdisk_ask_menu_get_item(ask, i++, &key, NULL, NULL) == 0) {
130 if (c == key) {
131 fdisk_ask_menu_set_result(ask, c);
132 return 0; /* success */
133 }
134 }
135 fdisk_warnx(cxt, _("Value out of range."));
136 } while (1);
137
138 return -EINVAL;
139}
140
141
142#define tochar(num) ((int) ('a' + num - 1))
143static int ask_number(struct fdisk_context *cxt,
144 struct fdisk_ask *ask,
145 char *buf, size_t bufsz)
146{
147 char prompt[128] = { '\0' };
148 const char *q = fdisk_ask_get_query(ask);
149 const char *range = fdisk_ask_number_get_range(ask);
150
151 uint64_t dflt = fdisk_ask_number_get_default(ask),
152 low = fdisk_ask_number_get_low(ask),
153 high = fdisk_ask_number_get_high(ask);
154 int inchar = fdisk_ask_number_inchars(ask);
155
156 assert(q);
157
88141067 158 DBG(ASK, ul_debug("asking for number "
d6b3ba41
KZ
159 "['%s', <%ju,%ju>, default=%ju, range: %s]",
160 q, low, high, dflt, range));
161
162 if (range && dflt >= low && dflt <= high) {
163 if (inchar)
164 snprintf(prompt, sizeof(prompt), _("%s (%s, default %c): "),
165 q, range, tochar(dflt));
166 else
167 snprintf(prompt, sizeof(prompt), _("%s (%s, default %ju): "),
168 q, range, dflt);
169
170 } else if (dflt >= low && dflt <= high) {
171 if (inchar)
172 snprintf(prompt, sizeof(prompt), _("%s (%c-%c, default %c): "),
173 q, tochar(low), tochar(high), tochar(dflt));
174 else
175 snprintf(prompt, sizeof(prompt), _("%s (%ju-%ju, default %ju): "),
176 q, low, high, dflt);
177 } else if (inchar)
178 snprintf(prompt, sizeof(prompt), _("%s (%c-%c): "),
179 q, tochar(low), tochar(high));
180 else
181 snprintf(prompt, sizeof(prompt), _("%s (%ju-%ju): "),
182 q, low, high);
183
184 do {
185 int rc = get_user_reply(cxt, prompt, buf, bufsz);
186 uint64_t num;
187
188 if (rc)
189 return rc;
190 if (!*buf && dflt >= low && dflt <= high)
191 return fdisk_ask_number_set_result(ask, dflt);
192
193 if (isdigit_string(buf)) {
194 char *end;
195
196 errno = 0;
197 num = strtoumax(buf, &end, 10);
198 if (errno || buf == end || (end && *end))
199 continue;
200 } else if (inchar && isalpha(*buf)) {
201 num = tolower(*buf) - 'a' + 1;
202 } else
203 rc = -EINVAL;
204
205 if (rc == 0 && num >= low && num <= high)
206 return fdisk_ask_number_set_result(ask, num);
207
208 fdisk_warnx(cxt, _("Value out of range."));
209 } while (1);
210
211 return -1;
212}
213
214static int ask_offset(struct fdisk_context *cxt,
215 struct fdisk_ask *ask,
216 char *buf, size_t bufsz)
217{
218 char prompt[128] = { '\0' };
219 const char *q = fdisk_ask_get_query(ask);
220 const char *range = fdisk_ask_number_get_range(ask);
221
222 uint64_t dflt = fdisk_ask_number_get_default(ask),
223 low = fdisk_ask_number_get_low(ask),
224 high = fdisk_ask_number_get_high(ask),
225 base = fdisk_ask_number_get_base(ask);
226
227 assert(q);
228
88141067 229 DBG(ASK, ul_debug("asking for offset ['%s', <%ju,%ju>, base=%ju, default=%ju, range: %s]",
d6b3ba41
KZ
230 q, low, high, base, dflt, range));
231
232 if (range && dflt >= low && dflt <= high)
233 snprintf(prompt, sizeof(prompt), _("%s (%s, default %ju): "), q, range, dflt);
234 else if (dflt >= low && dflt <= high)
235 snprintf(prompt, sizeof(prompt), _("%s (%ju-%ju, default %ju): "), q, low, high, dflt);
236 else
237 snprintf(prompt, sizeof(prompt), _("%s (%ju-%ju): "), q, low, high);
238
239 do {
240 uint64_t num = 0;
241 char sig = 0, *p;
242 int pwr = 0;
243
244 int rc = get_user_reply(cxt, prompt, buf, bufsz);
245 if (rc)
246 return rc;
247 if (!*buf && dflt >= low && dflt <= high)
248 return fdisk_ask_number_set_result(ask, dflt);
249
250 p = buf;
251 if (*p == '+' || *p == '-') {
252 sig = *buf;
253 p++;
254 }
255
256 rc = parse_size(p, &num, &pwr);
257 if (rc)
258 continue;
88141067 259 DBG(ASK, ul_debug("parsed size: %ju", num));
d6b3ba41
KZ
260 if (sig && pwr) {
261 /* +{size}{K,M,...} specified, the "num" is in bytes */
262 uint64_t unit = fdisk_ask_number_get_unit(ask);
263 num += unit/2; /* round */
264 num /= unit;
265 }
266 if (sig == '+')
267 num += base;
268 else if (sig == '-')
269 num = base - num;
270
88141067 271 DBG(ASK, ul_debug("final offset: %ju [sig: %c, power: %d, %s]",
d6b3ba41
KZ
272 num, sig, pwr,
273 sig ? "relative" : "absolute"));
274 if (num >= low && num <= high) {
9b0b9fb1 275 if (sig && pwr)
d6b3ba41
KZ
276 fdisk_ask_number_set_relative(ask, 1);
277 return fdisk_ask_number_set_result(ask, num);
278 }
279 fdisk_warnx(cxt, _("Value out of range."));
280 } while (1);
281
282 return -1;
283}
284
285static unsigned int info_count;
286
412791a9 287static void fputs_info(struct fdisk_ask *ask, FILE *out)
d6b3ba41
KZ
288{
289 const char *msg;
d6b3ba41
KZ
290 assert(ask);
291
292 msg = fdisk_ask_print_get_mesg(ask);
d6b3ba41
KZ
293 if (!msg)
294 return;
295 if (info_count == 1)
296 fputc('\n', out);
412791a9
KZ
297
298 fputs(msg, out);
d6b3ba41
KZ
299 fputc('\n', out);
300}
301
302int ask_callback(struct fdisk_context *cxt, struct fdisk_ask *ask,
303 void *data __attribute__((__unused__)))
304{
305 int rc = 0;
306 char buf[BUFSIZ];
307
308 assert(cxt);
309 assert(ask);
310
311 if (fdisk_ask_get_type(ask) != FDISK_ASKTYPE_INFO)
312 info_count = 0;
313
314 switch(fdisk_ask_get_type(ask)) {
315 case FDISK_ASKTYPE_MENU:
316 return ask_menu(cxt, ask, buf, sizeof(buf));
317 case FDISK_ASKTYPE_NUMBER:
318 return ask_number(cxt, ask, buf, sizeof(buf));
319 case FDISK_ASKTYPE_OFFSET:
320 return ask_offset(cxt, ask, buf, sizeof(buf));
321 case FDISK_ASKTYPE_INFO:
152788aa
KZ
322 if (!fdisk_is_listonly(cxt))
323 info_count++;
412791a9 324 fputs_info(ask, stdout);
d6b3ba41
KZ
325 break;
326 case FDISK_ASKTYPE_WARNX:
496c979a 327 color_scheme_fenable("warn", UL_COLOR_RED, stderr);
d6b3ba41
KZ
328 fputs(fdisk_ask_print_get_mesg(ask), stderr);
329 color_fdisable(stderr);
330 fputc('\n', stderr);
331 break;
332 case FDISK_ASKTYPE_WARN:
496c979a 333 color_scheme_fenable("warn", UL_COLOR_RED, stderr);
d6b3ba41
KZ
334 fputs(fdisk_ask_print_get_mesg(ask), stderr);
335 errno = fdisk_ask_print_get_errno(ask);
336 fprintf(stderr, ": %m\n");
337 color_fdisable(stderr);
338 break;
339 case FDISK_ASKTYPE_YESNO:
340 fputc('\n', stdout);
2d129032
KZ
341 do {
342 int x;
343 fputs(fdisk_ask_get_query(ask), stdout);
344 rc = get_user_reply(cxt, _(" [Y]es/[N]o: "), buf, sizeof(buf));
345 if (rc)
346 break;
347 x = rpmatch(buf);
348 if (x == 1 || x == 0) {
349 fdisk_ask_yesno_set_result(ask, x);
350 break;
351 }
352 } while(1);
88141067 353 DBG(ASK, ul_debug("yes-no ask: reply '%s' [rc=%d]", buf, rc));
d6b3ba41
KZ
354 break;
355 case FDISK_ASKTYPE_STRING:
356 {
357 char prmt[BUFSIZ];
358 snprintf(prmt, sizeof(prmt), "%s: ", fdisk_ask_get_query(ask));
359 fputc('\n', stdout);
360 rc = get_user_reply(cxt, prmt, buf, sizeof(buf));
361 if (rc == 0)
362 fdisk_ask_string_set_result(ask, xstrdup(buf));
88141067 363 DBG(ASK, ul_debug("string ask: reply '%s' [rc=%d]", buf, rc));
d6b3ba41
KZ
364 break;
365 }
366 default:
367 warnx(_("internal error: unsupported dialog type %d"), fdisk_ask_get_type(ask));
368 return -EINVAL;
369 }
370 return rc;
371}
372
373struct fdisk_parttype *ask_partition_type(struct fdisk_context *cxt)
374{
375 const char *q;
a745611d
KZ
376 struct fdisk_label *lb;
377
378 assert(cxt);
379 lb = fdisk_get_label(cxt, NULL);
d6b3ba41 380
a745611d 381 if (!lb)
d6b3ba41
KZ
382 return NULL;
383
a745611d 384 q = fdisk_label_has_code_parttypes(lb) ?
d6b3ba41
KZ
385 _("Partition type (type L to list all types): ") :
386 _("Hex code (type L to list all codes): ");
387 do {
388 char buf[256];
389 int rc = get_user_reply(cxt, q, buf, sizeof(buf));
390
391 if (rc)
392 break;
393
394 if (buf[1] == '\0' && toupper(*buf) == 'L')
395 list_partition_types(cxt);
396 else if (*buf)
a745611d 397 return fdisk_label_parse_parttype(lb, buf);
d6b3ba41
KZ
398 } while (1);
399
400 return NULL;
401}
402
7b575fcc 403void list_partition_types(struct fdisk_context *cxt)
6dbe3af9 404{
76f17cf2 405 size_t ntypes = 0;
a745611d 406 struct fdisk_label *lb = fdisk_get_label(cxt, NULL);
6dbe3af9 407
a745611d
KZ
408 assert(cxt);
409 lb = fdisk_get_label(cxt, NULL);
410 if (!lb)
411 return;
412 ntypes = fdisk_label_get_nparttypes(lb);
413 if (!ntypes)
7b575fcc 414 return;
2b6fc908 415
a745611d 416 if (fdisk_label_has_code_parttypes(lb)) {
7b575fcc
KZ
417 /*
418 * Prints in 4 columns in format <hex> <name>
419 */
76f17cf2
KZ
420 size_t last[4], done = 0, next = 0, size;
421 int i;
b8d22034 422
76f17cf2 423 size = ntypes;
7b575fcc
KZ
424
425 for (i = 3; i >= 0; i--)
426 last[3 - i] = done += (size + i - done) / (i + 1);
427 i = done = 0;
428
429 do {
430 #define NAME_WIDTH 15
431 char name[NAME_WIDTH * MB_LEN_MAX];
432 size_t width = NAME_WIDTH;
a745611d 433 const struct fdisk_parttype *t = fdisk_label_get_parttype(lb, next);
7b575fcc
KZ
434 size_t ret;
435
e6d0c4c1 436 if (fdisk_parttype_get_name(t)) {
a745611d
KZ
437 printf("%c%2x ", i ? ' ' : '\n',
438 fdisk_parttype_get_code(t));
439 ret = mbsalign(_(fdisk_parttype_get_name(t)),
440 name, sizeof(name),
441 &width, MBS_ALIGN_LEFT, 0);
7b575fcc 442
76f17cf2 443 if (ret == (size_t)-1 || ret >= sizeof(name))
a745611d
KZ
444 printf("%-15.15s",
445 _(fdisk_parttype_get_name(t)));
76f17cf2
KZ
446 else
447 fputs(name, stdout);
448 }
7b575fcc
KZ
449
450 next = last[i++] + done;
451 if (i > 3 || next >= last[i]) {
452 i = 0;
453 next = ++done;
454 }
455 } while (done < last[0]);
456
457 } else {
458 /*
459 * Prints 1 column in format <idx> <name> <typestr>
460 */
76f17cf2 461 size_t i;
7b575fcc 462
a745611d
KZ
463 for (i = 0; i < ntypes; i++) {
464 const struct fdisk_parttype *t = fdisk_label_get_parttype(lb, i);
465 printf("%3zu %-30s %s\n", i + 1,
466 fdisk_parttype_get_name(t),
467 fdisk_parttype_get_string(t));
76f17cf2 468 }
7b575fcc 469 }
6dbe3af9
KZ
470 putchar('\n');
471}
472
f02fecd1 473void toggle_dos_compatibility_flag(struct fdisk_context *cxt)
852ce62b 474{
6a632136 475 struct fdisk_label *lb = fdisk_get_label(cxt, "dos");
852ce62b
KZ
476 int flag;
477
478 if (!lb)
479 return;
480
481 flag = !fdisk_dos_is_compatible(lb);
09f0c3d9
KZ
482 fdisk_info(cxt, flag ?
483 _("DOS Compatibility flag is set (DEPRECATED!)") :
484 _("DOS Compatibility flag is not set"));
edd7b958 485
852ce62b
KZ
486 fdisk_dos_enable_compatible(lb, flag);
487
aa36c2cf 488 if (fdisk_is_label(cxt, DOS))
09f0c3d9 489 fdisk_reset_alignment(cxt); /* reset the current label */
6dbe3af9
KZ
490}
491
27ddd4f1 492void change_partition_type(struct fdisk_context *cxt)
e53ced85 493{
641a75ca 494 size_t i;
85151521
KZ
495 struct fdisk_parttype *t = NULL;
496 struct fdisk_partition *pa = NULL;
497 const char *old = NULL;
6dbe3af9 498
e3661531 499 assert(cxt);
e3661531 500
641a75ca 501 if (fdisk_ask_partnum(cxt, &i, FALSE))
24f4bbff 502 return;
2b6fc908 503
85151521
KZ
504 if (fdisk_get_partition(cxt, i, &pa)) {
505 fdisk_warnx(cxt, _("Partition %zu does not exist yet!"), i + 1);
506 return;
507 }
508
509 t = (struct fdisk_parttype *) fdisk_partition_get_type(pa);
e6d0c4c1 510 old = t ? fdisk_parttype_get_name(t) : _("Unknown");
85151521
KZ
511
512 do {
513 t = ask_partition_type(cxt);
514 } while (!t);
515
85151521 516 if (fdisk_set_partition_type(cxt, i, t) == 0)
0477369a 517 fdisk_info(cxt,
85151521 518 _("Changed type of partition '%s' to '%s'."),
a745611d 519 old, t ? fdisk_parttype_get_name(t) : _("Unknown"));
85151521
KZ
520 else
521 fdisk_info(cxt,
522 _("Type of partition %zu is unchanged: %s."),
523 i + 1, old);
524
d6cfa8b3 525 fdisk_unref_partition(pa);
6dbe3af9
KZ
526}
527
e916600f
KZ
528static size_t skip_empty(const unsigned char *buf, size_t i, size_t sz)
529{
530 size_t next;
531 const unsigned char *p0 = buf + i;
532
533 for (next = i + 16; next < sz; next += 16) {
534 if (memcmp(p0, buf + next, 16) != 0)
535 break;
536 }
537
538 return next == i + 16 ? i : next;
539}
6dbe3af9 540
e916600f 541static void dump_buffer(off_t base, unsigned char *buf, size_t sz, int all)
09f0c3d9 542{
e916600f
KZ
543 size_t i, l, next = 0;
544
545 if (!buf)
546 return;
547 for (i = 0, l = 0; i < sz; i++, l++) {
548 if (l == 0) {
549 if (all == 0 && !next)
550 next = skip_empty(buf, i, sz);
551 printf("%08jx ", base + i);
552 }
553 printf(" %02x", buf[i]);
554 if (l == 7) /* words separator */
555 fputs(" ", stdout);
556 else if (l == 15) {
557 fputc('\n', stdout); /* next line */
6dbe3af9 558 l = -1;
e916600f
KZ
559 if (next > i) {
560 printf("*\n");
561 i = next - 1;
562 }
563 next = 0;
6dbe3af9
KZ
564 }
565 }
566 if (l > 0)
567 printf("\n");
6dbe3af9
KZ
568}
569
e916600f 570static void dump_blkdev(struct fdisk_context *cxt, const char *name,
9bbcf43f 571 uint64_t offset, size_t size, int all)
e53ced85 572{
8eccde20
KZ
573 int fd = fdisk_get_devfd(cxt);
574
412791a9 575 fdisk_info(cxt, _("\n%s: offset = %ju, size = %zu bytes."),
e916600f
KZ
576 name, offset, size);
577
8eccde20
KZ
578 assert(fd >= 0);
579
9bbcf43f 580 if (lseek(fd, (off_t) offset, SEEK_SET) == (off_t) -1)
e916600f 581 fdisk_warn(cxt, _("cannot seek"));
5afed187
KZ
582 else {
583 unsigned char *buf = xmalloc(size);
584
8eccde20 585 if (read_all(fd, (char *) buf, size) != (ssize_t) size)
5afed187
KZ
586 fdisk_warn(cxt, _("cannot read"));
587 else
588 dump_buffer(offset, buf, size, all);
589 free(buf);
590 }
e916600f
KZ
591}
592
593void dump_firstsector(struct fdisk_context *cxt)
594{
595 int all = !isatty(STDOUT_FILENO);
596
e3661531 597 assert(cxt);
6dbe3af9 598
8eccde20 599 dump_blkdev(cxt, _("First sector"), 0, fdisk_get_sector_size(cxt), all);
e916600f
KZ
600}
601
602void dump_disklabel(struct fdisk_context *cxt)
603{
604 int all = !isatty(STDOUT_FILENO);
605 int i = 0;
606 const char *name = NULL;
9bbcf43f 607 uint64_t offset = 0;
e916600f
KZ
608 size_t size = 0;
609
610 assert(cxt);
e3661531 611
e916600f
KZ
612 while (fdisk_locate_disklabel(cxt, i++, &name, &offset, &size) == 0 && size)
613 dump_blkdev(cxt, name, offset, size, all);
6dbe3af9
KZ
614}
615
0073a4cf 616static fdisk_sector_t get_dev_blocks(char *dev)
6da365de 617{
bbe67996 618 int fd, ret;
0073a4cf 619 fdisk_sector_t size;
6da365de
DB
620
621 if ((fd = open(dev, O_RDONLY)) < 0)
289dcc90 622 err(EXIT_FAILURE, _("cannot open %s"), dev);
0073a4cf 623 ret = blkdev_get_sectors(fd, (unsigned long long *) &size);
6da365de 624 close(fd);
bbe67996
SK
625 if (ret < 0)
626 err(EXIT_FAILURE, _("BLKGETSIZE ioctl failed on %s"), dev);
6da365de
DB
627 return size/2;
628}
629
e3a4aaa7
KZ
630static void __attribute__ ((__noreturn__)) usage(FILE *out)
631{
632 fputs(USAGE_HEADER, out);
633
634 fprintf(out,
635 _(" %1$s [options] <disk> change partition table\n"
636 " %1$s [options] -l [<disk>] list partition table(s)\n"),
637 program_invocation_short_name);
638
451dbcfa
BS
639 fputs(USAGE_SEPARATOR, out);
640 fputs(_("Display or manipulate a disk partition table.\n"), out);
641
e3a4aaa7
KZ
642 fputs(USAGE_OPTIONS, out);
643 fputs(_(" -b, --sector-size <size> physical and logical sector size\n"), out);
644 fputs(_(" -c, --compatibility[=<mode>] mode is 'dos' or 'nondos' (default)\n"), out);
645 fputs(_(" -L, --color[=<when>] colorize output (auto, always or never)\n"), out);
646 fputs(_(" -l, --list display partitions end exit\n"), out);
2d7dffeb 647 fputs(_(" -o, --output <list> output columns\n"), out);
e3a4aaa7
KZ
648 fputs(_(" -t, --type <type> recognize specified partition table type only\n"), out);
649 fputs(_(" -u, --units[=<unit>] display units: 'cylinders' or 'sectors' (default)\n"), out);
650 fputs(_(" -s, --getsz display device size in 512-byte sectors [DEPRECATED]\n"), out);
354f8cc8 651 fputs(_(" --bytes print SIZE in bytes rather than in human readable format\n"), out);
e3a4aaa7
KZ
652
653 fputs(USAGE_SEPARATOR, out);
4b4e391a
KZ
654 fputs(_(" -C, --cylinders <number> specify the number of cylinders\n"), out);
655 fputs(_(" -H, --heads <number> specify the number of heads\n"), out);
656 fputs(_(" -S, --sectors <number> specify the number of sectors per track\n"), out);
e3a4aaa7
KZ
657
658 fputs(USAGE_SEPARATOR, out);
659 fputs(USAGE_HELP, out);
660 fputs(USAGE_VERSION, out);
661
fff8ad58
KZ
662 list_available_columns(out);
663
e3a4aaa7
KZ
664 fprintf(out, USAGE_MAN_TAIL("fdisk(8)"));
665 exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
666}
667
668
5b72b3dd
KZ
669enum {
670 ACT_FDISK = 0, /* default */
671 ACT_LIST,
672 ACT_SHOWSIZE
673};
674
e1144767
DB
675int main(int argc, char **argv)
676{
e146ae4e 677 int rc, i, c, act = ACT_FDISK;
d0c9ddc3 678 int colormode = UL_COLORMODE_UNDEF;
4e0e8253 679 struct fdisk_context *cxt;
fff8ad58 680 char *outarg = NULL;
354f8cc8
KZ
681 enum {
682 OPT_BYTES = CHAR_MAX + 1
683 };
e3a4aaa7 684 static const struct option longopts[] = {
354f8cc8 685 { "bytes", no_argument, NULL, OPT_BYTES },
e3a4aaa7
KZ
686 { "color", optional_argument, NULL, 'L' },
687 { "compatibility", optional_argument, NULL, 'c' },
4b4e391a
KZ
688 { "cylinders", required_argument, NULL, 'C' },
689 { "heads", required_argument, NULL, 'H' },
690 { "sectors", required_argument, NULL, 'S' },
e3a4aaa7
KZ
691 { "getsz", no_argument, NULL, 's' },
692 { "help", no_argument, NULL, 'h' },
693 { "list", no_argument, NULL, 'l' },
694 { "sector-size", required_argument, NULL, 'b' },
695 { "type", required_argument, NULL, 't' },
696 { "units", optional_argument, NULL, 'u' },
697 { "version", no_argument, NULL, 'V' },
2d7dffeb 698 { "output", no_argument, NULL, 'o' },
e3a4aaa7
KZ
699 { NULL, 0, NULL, 0 }
700 };
701
7eda085c
KZ
702 setlocale(LC_ALL, "");
703 bindtextdomain(PACKAGE, LOCALEDIR);
704 textdomain(PACKAGE);
b2d28533 705 atexit(close_stdout);
2b6fc908 706
4e0e8253 707 fdisk_init_debug(0);
e6d0c4c1
KZ
708 fdiskprog_init_debug();
709
4e0e8253
KZ
710 cxt = fdisk_new_context();
711 if (!cxt)
712 err(EXIT_FAILURE, _("failed to allocate libfdisk context"));
713
6a632136 714 fdisk_set_ask(cxt, ask_callback, NULL);
416c43a9 715
fff8ad58 716 while ((c = getopt_long(argc, argv, "b:c::C:hH:lL::o:sS:t:u::vV",
e3a4aaa7 717 longopts, NULL)) != -1) {
2b6fc908
KZ
718 switch (c) {
719 case 'b':
6bcd192c
KZ
720 {
721 size_t sz = strtou32_or_err(optarg,
722 _("invalid sector size argument"));
723 if (sz != 512 && sz != 1024 && sz != 2048 && sz != 4096)
7c1db6b4 724 usage(stderr);
6bcd192c 725 fdisk_save_user_sector_size(cxt, sz, sz);
2b6fc908 726 break;
6bcd192c 727 }
0e6f4a20 728 case 'C':
1653f0b0
KZ
729 fdisk_save_user_geometry(cxt,
730 strtou32_or_err(optarg,
731 _("invalid cylinders argument")),
732 0, 0);
0e6f4a20 733 break;
78498b7b 734 case 'c':
852ce62b 735 if (optarg) {
2b0bc17b 736 /* this setting is independent on the current
e3a4aaa7
KZ
737 * actively used label
738 */
739 char *p = *optarg == '=' ? optarg + 1 : optarg;
6a632136 740 struct fdisk_label *lb = fdisk_get_label(cxt, "dos");
e3a4aaa7 741
852ce62b
KZ
742 if (!lb)
743 err(EXIT_FAILURE, _("not found DOS label driver"));
e3a4aaa7 744 if (strcmp(p, "dos") == 0)
852ce62b 745 fdisk_dos_enable_compatible(lb, TRUE);
e3a4aaa7 746 else if (strcmp(p, "nondos") == 0)
852ce62b 747 fdisk_dos_enable_compatible(lb, FALSE);
e3a4aaa7
KZ
748 else {
749 warnx(_("unknown compatibility mode '%s'"), p);
852ce62b 750 usage(stderr);
e3a4aaa7 751 }
852ce62b
KZ
752 }
753 /* use default if no optarg specified */
78498b7b 754 break;
0e6f4a20 755 case 'H':
1653f0b0
KZ
756 fdisk_save_user_geometry(cxt, 0,
757 strtou32_or_err(optarg,
758 _("invalid heads argument")),
759 0);
0e6f4a20
KZ
760 break;
761 case 'S':
1653f0b0
KZ
762 fdisk_save_user_geometry(cxt, 0, 0,
763 strtou32_or_err(optarg,
764 _("invalid sectors argument")));
0e6f4a20 765 break;
2b6fc908 766 case 'l':
5b72b3dd 767 act = ACT_LIST;
2b6fc908 768 break;
80a1712f
KZ
769 case 'L':
770 if (optarg)
771 colormode = colormode_or_err(optarg,
772 _("unsupported color mode"));
773 break;
fff8ad58
KZ
774 case 'o':
775 outarg = optarg;
776 break;
2b6fc908 777 case 's':
5b72b3dd 778 act = ACT_SHOWSIZE;
2b6fc908 779 break;
565b7da6
KZ
780 case 't':
781 {
782 struct fdisk_label *lb = NULL;
783
6a632136 784 while (fdisk_next_label(cxt, &lb) == 0)
565b7da6
KZ
785 fdisk_label_set_disabled(lb, 1);
786
6a632136 787 lb = fdisk_get_label(cxt, optarg);
565b7da6
KZ
788 if (!lb)
789 errx(EXIT_FAILURE, _("unsupported disklabel: %s"), optarg);
790 fdisk_label_set_disabled(lb, 0);
1ce1a112 791 break;
565b7da6 792 }
2b6fc908 793 case 'u':
ec10aa67
KZ
794 if (optarg && *optarg == '=')
795 optarg++;
6a632136 796 if (fdisk_set_unit(cxt, optarg) != 0)
7c1db6b4 797 usage(stderr);
2b6fc908 798 break;
e3a4aaa7
KZ
799 case 'V': /* preferred for util-linux */
800 case 'v': /* for backward compatibility only */
a2482eb3
DB
801 printf(UTIL_LINUX_VERSION);
802 return EXIT_SUCCESS;
e1144767
DB
803 case 'h':
804 usage(stdout);
354f8cc8
KZ
805 case OPT_BYTES:
806 fdisk_set_size_unit(cxt, FDISK_SIZEUNIT_BYTES);
807 break;
2b6fc908 808 default:
7c1db6b4 809 usage(stderr);
2b6fc908 810 }
6dbe3af9 811 }
2b6fc908 812
6bcd192c
KZ
813 if (argc-optind != 1 && fdisk_has_user_device_properties(cxt))
814 warnx(_("The device properties (sector size and geometry) should"
815 " be used with one specified device only."));
7eda085c 816
d0c9ddc3 817 colors_init(colormode, "fdisk");
ffcf0540 818
5b72b3dd
KZ
819 switch (act) {
820 case ACT_LIST:
6a632136 821 fdisk_enable_listonly(cxt, 1);
fff8ad58 822 init_fields(cxt, outarg, NULL);
ffcf0540 823
2b6fc908
KZ
824 if (argc > optind) {
825 int k;
c129767e 826 for (k = optind; k < argc; k++)
d2c47697 827 print_device_pt(cxt, argv[k], 1, 0);
ea4824f1 828 } else
d2c47697 829 print_all_devices_pt(cxt, 0);
5b72b3dd 830 break;
2b6fc908 831
5b72b3dd 832 case ACT_SHOWSIZE:
9564e46c 833 /* deprecated */
5b72b3dd 834 if (argc - optind <= 0)
7c1db6b4 835 usage(stderr);
2b6fc908 836
6da365de 837 for (i = optind; i < argc; i++) {
0073a4cf
KZ
838 uintmax_t blks = get_dev_blocks(argv[i]);
839
5b72b3dd 840 if (argc - optind == 1)
0073a4cf 841 printf("%ju\n", blks);
2b6fc908 842 else
0073a4cf 843 printf("%s: %ju\n", argv[i], blks);
6dbe3af9 844 }
5b72b3dd 845 break;
6dbe3af9 846
5b72b3dd
KZ
847 case ACT_FDISK:
848 if (argc-optind != 1)
849 usage(stderr);
7eda085c 850
5b72b3dd 851 /* Here starts interactive mode, use fdisk_{warn,info,..} functions */
496c979a 852 color_scheme_enable("welcome", UL_COLOR_GREEN);
09f0c3d9 853 fdisk_info(cxt, _("Welcome to fdisk (%s)."), PACKAGE_STRING);
80a1712f
KZ
854 color_disable();
855 fdisk_info(cxt, _("Changes will remain in memory only, until you decide to write them.\n"
856 "Be careful before using the write command.\n"));
2d8988bd 857
6a632136 858 rc = fdisk_assign_device(cxt, argv[optind], 0);
e146ae4e 859 if (rc == -EACCES) {
6a632136 860 rc = fdisk_assign_device(cxt, argv[optind], 1);
e146ae4e
KZ
861 if (rc == 0)
862 fdisk_warnx(cxt, _("Device open in read-only mode."));
863 }
864 if (rc)
2d8988bd
KZ
865 err(EXIT_FAILURE, _("cannot open %s"), argv[optind]);
866
5b72b3dd 867 fflush(stdout);
56c07b96 868
aa36c2cf 869 if (!fdisk_has_label(cxt)) {
2d8988bd 870 fdisk_info(cxt, _("Device does not contain a recognized partition table."));
5b72b3dd 871 fdisk_create_disklabel(cxt, NULL);
433d05ff 872
aa36c2cf 873 } else if (fdisk_is_label(cxt, GPT) && fdisk_gpt_is_hybrid(cxt))
433d05ff 874 fdisk_warnx(cxt, _(
09af3db4 875 "A hybrid GPT was detected. You have to sync "
433d05ff 876 "the hybrid MBR manually (expert command 'M')."));
6dbe3af9 877
fff8ad58
KZ
878 init_fields(cxt, outarg, NULL); /* -o <columns> */
879
5b72b3dd
KZ
880 while (1)
881 process_fdisk_menu(&cxt);
882 }
9777759a 883
c7119037 884 fdisk_unref_context(cxt);
5b72b3dd 885 return EXIT_SUCCESS;
6dbe3af9 886}