]> git.ipfire.org Git - thirdparty/util-linux.git/blame - disk-utils/fdisk.c
mkfs.cramfs: use defined failure name rather than magic value
[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>
6dbe3af9 24
3f0ac587 25#include "c.h"
52b38677 26#include "xalloc.h"
e916600f 27#include "all-io.h"
22853e4a 28#include "nls.h"
e66ac5d3 29#include "rpmatch.h"
810f986b 30#include "blkdev.h"
b8d22034 31#include "mbsalign.h"
726f69e2 32#include "fdisk.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
b4bfbadd 39#include "pt-sun.h" /* to toggle flags */
5c36a0eb 40
48d7b13a 41#ifdef HAVE_LINUX_COMPILER_H
3f0ac587 42# include <linux/compiler.h>
48d7b13a
KZ
43#endif
44#ifdef HAVE_LINUX_BLKPG_H
3f0ac587 45# include <linux/blkpg.h>
7eda085c 46#endif
6dbe3af9 47
d6b3ba41
KZ
48
49
50int get_user_reply(struct fdisk_context *cxt, const char *prompt,
51 char *buf, size_t bufsz)
52{
53 char *p;
54 size_t sz;
55
56 do {
57 fputs(prompt, stdout);
58 fflush(stdout);
59
60 if (!fgets(buf, bufsz, stdin)) {
61 if (fdisk_label_is_changed(cxt->label)) {
62 fprintf(stderr, _("\nDo you really want to quit? "));
63
64 if (fgets(buf, bufsz, stdin) && !rpmatch(buf))
65 continue;
66 }
67 fdisk_free_context(cxt);
68 exit(EXIT_FAILURE);
69 } else
70 break;
71 } while (1);
72
73 for (p = buf; *p && !isgraph(*p); p++); /* get first non-blank */
74
75 if (p > buf)
76 memmove(buf, p, p - buf); /* remove blank space */
77 sz = strlen(buf);
78 if (sz && *(buf + sz - 1) == '\n')
79 *(buf + sz - 1) = '\0';
80
88141067 81 DBG(ASK, ul_debug("user's reply: >>>%s<<<", buf));
d6b3ba41
KZ
82 return 0;
83}
84
85static int ask_menu(struct fdisk_context *cxt, struct fdisk_ask *ask,
86 char *buf, size_t bufsz)
87
88{
89 const char *q = fdisk_ask_get_query(ask);
90 int dft = fdisk_ask_menu_get_default(ask);
91
92 if (q) {
93 fputs(q, stdout); /* print header */
94 fputc('\n', stdout);
95 }
96
97 do {
98 char prompt[128];
99 int key, c;
100 const char *name, *desc;
101 size_t i = 0;
102
103 /* print menu items */
104 while (fdisk_ask_menu_get_item(ask, i++, &key, &name, &desc) == 0)
105 fprintf(stdout, " %c %s (%s)\n", key, name, desc);
106
107 /* ask for key */
108 snprintf(prompt, sizeof(prompt), _("Select (default %c): "), dft);
109 get_user_reply(cxt, prompt, buf, bufsz);
110 if (!*buf) {
111 fdisk_info(cxt, _("Using default response %c."), dft);
112 c = dft;
113 } else
114 c = tolower(buf[0]);
115
116 /* check result */
117 i = 0;
118 while (fdisk_ask_menu_get_item(ask, i++, &key, NULL, NULL) == 0) {
119 if (c == key) {
120 fdisk_ask_menu_set_result(ask, c);
121 return 0; /* success */
122 }
123 }
124 fdisk_warnx(cxt, _("Value out of range."));
125 } while (1);
126
127 return -EINVAL;
128}
129
130
131#define tochar(num) ((int) ('a' + num - 1))
132static int ask_number(struct fdisk_context *cxt,
133 struct fdisk_ask *ask,
134 char *buf, size_t bufsz)
135{
136 char prompt[128] = { '\0' };
137 const char *q = fdisk_ask_get_query(ask);
138 const char *range = fdisk_ask_number_get_range(ask);
139
140 uint64_t dflt = fdisk_ask_number_get_default(ask),
141 low = fdisk_ask_number_get_low(ask),
142 high = fdisk_ask_number_get_high(ask);
143 int inchar = fdisk_ask_number_inchars(ask);
144
145 assert(q);
146
88141067 147 DBG(ASK, ul_debug("asking for number "
d6b3ba41
KZ
148 "['%s', <%ju,%ju>, default=%ju, range: %s]",
149 q, low, high, dflt, range));
150
151 if (range && dflt >= low && dflt <= high) {
152 if (inchar)
153 snprintf(prompt, sizeof(prompt), _("%s (%s, default %c): "),
154 q, range, tochar(dflt));
155 else
156 snprintf(prompt, sizeof(prompt), _("%s (%s, default %ju): "),
157 q, range, dflt);
158
159 } else if (dflt >= low && dflt <= high) {
160 if (inchar)
161 snprintf(prompt, sizeof(prompt), _("%s (%c-%c, default %c): "),
162 q, tochar(low), tochar(high), tochar(dflt));
163 else
164 snprintf(prompt, sizeof(prompt), _("%s (%ju-%ju, default %ju): "),
165 q, low, high, dflt);
166 } else if (inchar)
167 snprintf(prompt, sizeof(prompt), _("%s (%c-%c): "),
168 q, tochar(low), tochar(high));
169 else
170 snprintf(prompt, sizeof(prompt), _("%s (%ju-%ju): "),
171 q, low, high);
172
173 do {
174 int rc = get_user_reply(cxt, prompt, buf, bufsz);
175 uint64_t num;
176
177 if (rc)
178 return rc;
179 if (!*buf && dflt >= low && dflt <= high)
180 return fdisk_ask_number_set_result(ask, dflt);
181
182 if (isdigit_string(buf)) {
183 char *end;
184
185 errno = 0;
186 num = strtoumax(buf, &end, 10);
187 if (errno || buf == end || (end && *end))
188 continue;
189 } else if (inchar && isalpha(*buf)) {
190 num = tolower(*buf) - 'a' + 1;
191 } else
192 rc = -EINVAL;
193
194 if (rc == 0 && num >= low && num <= high)
195 return fdisk_ask_number_set_result(ask, num);
196
197 fdisk_warnx(cxt, _("Value out of range."));
198 } while (1);
199
200 return -1;
201}
202
203static int ask_offset(struct fdisk_context *cxt,
204 struct fdisk_ask *ask,
205 char *buf, size_t bufsz)
206{
207 char prompt[128] = { '\0' };
208 const char *q = fdisk_ask_get_query(ask);
209 const char *range = fdisk_ask_number_get_range(ask);
210
211 uint64_t dflt = fdisk_ask_number_get_default(ask),
212 low = fdisk_ask_number_get_low(ask),
213 high = fdisk_ask_number_get_high(ask),
214 base = fdisk_ask_number_get_base(ask);
215
216 assert(q);
217
88141067 218 DBG(ASK, ul_debug("asking for offset ['%s', <%ju,%ju>, base=%ju, default=%ju, range: %s]",
d6b3ba41
KZ
219 q, low, high, base, dflt, range));
220
221 if (range && dflt >= low && dflt <= high)
222 snprintf(prompt, sizeof(prompt), _("%s (%s, default %ju): "), q, range, dflt);
223 else if (dflt >= low && dflt <= high)
224 snprintf(prompt, sizeof(prompt), _("%s (%ju-%ju, default %ju): "), q, low, high, dflt);
225 else
226 snprintf(prompt, sizeof(prompt), _("%s (%ju-%ju): "), q, low, high);
227
228 do {
229 uint64_t num = 0;
230 char sig = 0, *p;
231 int pwr = 0;
232
233 int rc = get_user_reply(cxt, prompt, buf, bufsz);
234 if (rc)
235 return rc;
236 if (!*buf && dflt >= low && dflt <= high)
237 return fdisk_ask_number_set_result(ask, dflt);
238
239 p = buf;
240 if (*p == '+' || *p == '-') {
241 sig = *buf;
242 p++;
243 }
244
245 rc = parse_size(p, &num, &pwr);
246 if (rc)
247 continue;
88141067 248 DBG(ASK, ul_debug("parsed size: %ju", num));
d6b3ba41
KZ
249 if (sig && pwr) {
250 /* +{size}{K,M,...} specified, the "num" is in bytes */
251 uint64_t unit = fdisk_ask_number_get_unit(ask);
252 num += unit/2; /* round */
253 num /= unit;
254 }
255 if (sig == '+')
256 num += base;
257 else if (sig == '-')
258 num = base - num;
259
88141067 260 DBG(ASK, ul_debug("final offset: %ju [sig: %c, power: %d, %s]",
d6b3ba41
KZ
261 num, sig, pwr,
262 sig ? "relative" : "absolute"));
263 if (num >= low && num <= high) {
264 if (sig)
265 fdisk_ask_number_set_relative(ask, 1);
266 return fdisk_ask_number_set_result(ask, num);
267 }
268 fdisk_warnx(cxt, _("Value out of range."));
269 } while (1);
270
271 return -1;
272}
273
274static unsigned int info_count;
275
412791a9 276static void fputs_info(struct fdisk_ask *ask, FILE *out)
d6b3ba41
KZ
277{
278 const char *msg;
d6b3ba41
KZ
279 assert(ask);
280
281 msg = fdisk_ask_print_get_mesg(ask);
d6b3ba41
KZ
282 if (!msg)
283 return;
284 if (info_count == 1)
285 fputc('\n', out);
412791a9
KZ
286
287 fputs(msg, out);
d6b3ba41
KZ
288 fputc('\n', out);
289}
290
291int ask_callback(struct fdisk_context *cxt, struct fdisk_ask *ask,
292 void *data __attribute__((__unused__)))
293{
294 int rc = 0;
295 char buf[BUFSIZ];
296
297 assert(cxt);
298 assert(ask);
299
300 if (fdisk_ask_get_type(ask) != FDISK_ASKTYPE_INFO)
301 info_count = 0;
302
303 switch(fdisk_ask_get_type(ask)) {
304 case FDISK_ASKTYPE_MENU:
305 return ask_menu(cxt, ask, buf, sizeof(buf));
306 case FDISK_ASKTYPE_NUMBER:
307 return ask_number(cxt, ask, buf, sizeof(buf));
308 case FDISK_ASKTYPE_OFFSET:
309 return ask_offset(cxt, ask, buf, sizeof(buf));
310 case FDISK_ASKTYPE_INFO:
311 info_count++;
412791a9 312 fputs_info(ask, stdout);
d6b3ba41
KZ
313 break;
314 case FDISK_ASKTYPE_WARNX:
496c979a 315 color_scheme_fenable("warn", UL_COLOR_RED, stderr);
d6b3ba41
KZ
316 fputs(fdisk_ask_print_get_mesg(ask), stderr);
317 color_fdisable(stderr);
318 fputc('\n', stderr);
319 break;
320 case FDISK_ASKTYPE_WARN:
496c979a 321 color_scheme_fenable("warn", UL_COLOR_RED, stderr);
d6b3ba41
KZ
322 fputs(fdisk_ask_print_get_mesg(ask), stderr);
323 errno = fdisk_ask_print_get_errno(ask);
324 fprintf(stderr, ": %m\n");
325 color_fdisable(stderr);
326 break;
327 case FDISK_ASKTYPE_YESNO:
328 fputc('\n', stdout);
329 fputs(fdisk_ask_get_query(ask), stdout);
330 rc = get_user_reply(cxt, _(" [Y]es/[N]o: "), buf, sizeof(buf));
331 if (rc == 0)
332 fdisk_ask_yesno_set_result(ask, rpmatch(buf));
88141067 333 DBG(ASK, ul_debug("yes-no ask: reply '%s' [rc=%d]", buf, rc));
d6b3ba41
KZ
334 break;
335 case FDISK_ASKTYPE_STRING:
336 {
337 char prmt[BUFSIZ];
338 snprintf(prmt, sizeof(prmt), "%s: ", fdisk_ask_get_query(ask));
339 fputc('\n', stdout);
340 rc = get_user_reply(cxt, prmt, buf, sizeof(buf));
341 if (rc == 0)
342 fdisk_ask_string_set_result(ask, xstrdup(buf));
88141067 343 DBG(ASK, ul_debug("string ask: reply '%s' [rc=%d]", buf, rc));
d6b3ba41
KZ
344 break;
345 }
346 default:
347 warnx(_("internal error: unsupported dialog type %d"), fdisk_ask_get_type(ask));
348 return -EINVAL;
349 }
350 return rc;
351}
352
353struct fdisk_parttype *ask_partition_type(struct fdisk_context *cxt)
354{
355 const char *q;
356
357 if (!cxt || !cxt->label || !cxt->label->nparttypes)
358 return NULL;
359
360 q = fdisk_is_parttype_string(cxt) ?
361 _("Partition type (type L to list all types): ") :
362 _("Hex code (type L to list all codes): ");
363 do {
364 char buf[256];
365 int rc = get_user_reply(cxt, q, buf, sizeof(buf));
366
367 if (rc)
368 break;
369
370 if (buf[1] == '\0' && toupper(*buf) == 'L')
371 list_partition_types(cxt);
372 else if (*buf)
373 return fdisk_parse_parttype(cxt, buf);
374 } while (1);
375
376 return NULL;
377}
378
7b575fcc 379void list_partition_types(struct fdisk_context *cxt)
6dbe3af9 380{
7b575fcc 381 struct fdisk_parttype *types;
76f17cf2 382 size_t ntypes = 0;
6dbe3af9 383
7b575fcc
KZ
384 if (!cxt || !cxt->label || !cxt->label->parttypes)
385 return;
2b6fc908 386
7b575fcc 387 types = cxt->label->parttypes;
76f17cf2 388 ntypes = cxt->label->nparttypes;
6dbe3af9 389
7b575fcc
KZ
390 if (types[0].typestr == NULL) {
391 /*
392 * Prints in 4 columns in format <hex> <name>
393 */
76f17cf2
KZ
394 size_t last[4], done = 0, next = 0, size;
395 int i;
b8d22034 396
76f17cf2
KZ
397 size = ntypes;
398 if (types[ntypes - 1].name == NULL)
399 size--;
7b575fcc
KZ
400
401 for (i = 3; i >= 0; i--)
402 last[3 - i] = done += (size + i - done) / (i + 1);
403 i = done = 0;
404
405 do {
406 #define NAME_WIDTH 15
407 char name[NAME_WIDTH * MB_LEN_MAX];
408 size_t width = NAME_WIDTH;
409 struct fdisk_parttype *t = &types[next];
410 size_t ret;
411
76f17cf2
KZ
412 if (t->name) {
413 printf("%c%2x ", i ? ' ' : '\n', t->type);
414 ret = mbsalign(_(t->name), name, sizeof(name),
415 &width, MBS_ALIGN_LEFT, 0);
7b575fcc 416
76f17cf2
KZ
417 if (ret == (size_t)-1 || ret >= sizeof(name))
418 printf("%-15.15s", _(t->name));
419 else
420 fputs(name, stdout);
421 }
7b575fcc
KZ
422
423 next = last[i++] + done;
424 if (i > 3 || next >= last[i]) {
425 i = 0;
426 next = ++done;
427 }
428 } while (done < last[0]);
429
430 } else {
431 /*
432 * Prints 1 column in format <idx> <name> <typestr>
433 */
434 struct fdisk_parttype *t;
76f17cf2 435 size_t i;
7b575fcc 436
76f17cf2
KZ
437 for (i = 0, t = types; t && i < ntypes; t++, i++) {
438 if (t->name)
439 printf("%3zu %-30s %s\n", i + 1,
440 t->name, t->typestr);
441 }
7b575fcc 442 }
6dbe3af9
KZ
443 putchar('\n');
444}
445
f02fecd1 446void toggle_dos_compatibility_flag(struct fdisk_context *cxt)
852ce62b
KZ
447{
448 struct fdisk_label *lb = fdisk_context_get_label(cxt, "dos");
449 int flag;
450
451 if (!lb)
452 return;
453
454 flag = !fdisk_dos_is_compatible(lb);
09f0c3d9
KZ
455 fdisk_info(cxt, flag ?
456 _("DOS Compatibility flag is set (DEPRECATED!)") :
457 _("DOS Compatibility flag is not set"));
edd7b958 458
852ce62b
KZ
459 fdisk_dos_enable_compatible(lb, flag);
460
461 if (fdisk_is_disklabel(cxt, DOS))
09f0c3d9 462 fdisk_reset_alignment(cxt); /* reset the current label */
6dbe3af9
KZ
463}
464
27ddd4f1 465void change_partition_type(struct fdisk_context *cxt)
e53ced85 466{
641a75ca 467 size_t i;
85151521
KZ
468 struct fdisk_parttype *t = NULL;
469 struct fdisk_partition *pa = NULL;
470 const char *old = NULL;
6dbe3af9 471
e3661531
KZ
472 assert(cxt);
473 assert(cxt->label);
474
641a75ca 475 if (fdisk_ask_partnum(cxt, &i, FALSE))
24f4bbff 476 return;
2b6fc908 477
85151521
KZ
478 if (fdisk_get_partition(cxt, i, &pa)) {
479 fdisk_warnx(cxt, _("Partition %zu does not exist yet!"), i + 1);
480 return;
481 }
482
483 t = (struct fdisk_parttype *) fdisk_partition_get_type(pa);
484 old = t ? t->name : _("Unknown");
485
486 do {
487 t = ask_partition_type(cxt);
488 } while (!t);
489
85151521
KZ
490 if (fdisk_set_partition_type(cxt, i, t) == 0)
491 fdisk_sinfo(cxt, FDISK_INFO_SUCCESS,
492 _("Changed type of partition '%s' to '%s'."),
493 old, t ? t->name : _("Unknown"));
494 else
495 fdisk_info(cxt,
496 _("Type of partition %zu is unchanged: %s."),
497 i + 1, old);
498
d6cfa8b3 499 fdisk_unref_partition(pa);
6dbe3af9
KZ
500}
501
89309968 502void list_disk_geometry(struct fdisk_context *cxt)
21fe3dde
KZ
503{
504 char *id = NULL;
9af73f84
KZ
505 uint64_t bytes = cxt->total_sectors * cxt->sector_size;
506 char *strsz = size_to_human_string(SIZE_SUFFIX_SPACE
507 | SIZE_SUFFIX_3LETTER, bytes);
508
412791a9 509 fdisk_info(cxt, _("Disk %s: %s, %ju bytes, %ju sectors"),
e39966c6 510 cxt->dev_path, strsz,
48d4d931 511 bytes, (uintmax_t) cxt->total_sectors);
9af73f84 512 free(strsz);
b1b1a7b7 513
96dc2798 514 if (fdisk_require_geometry(cxt) || fdisk_context_use_cylinders(cxt))
412791a9 515 fdisk_info(cxt, _("Geometry: %d heads, %llu sectors/track, %llu cylinders"),
9af73f84 516 cxt->geom.heads, cxt->geom.sectors, cxt->geom.cylinders);
b1b1a7b7 517
412791a9 518 fdisk_info(cxt, _("Units: %s of %d * %ld = %ld bytes"),
ec10aa67
KZ
519 fdisk_context_get_unit(cxt, PLURAL),
520 fdisk_context_get_units_per_sector(cxt),
521 cxt->sector_size,
522 fdisk_context_get_units_per_sector(cxt) * cxt->sector_size);
05dc9645 523
412791a9 524 fdisk_info(cxt, _("Sector size (logical/physical): %lu bytes / %lu bytes"),
e53ced85 525 cxt->sector_size, cxt->phy_sector_size);
412791a9 526 fdisk_info(cxt, _("I/O size (minimum/optimal): %lu bytes / %lu bytes"),
e53ced85
DB
527 cxt->min_io_size, cxt->io_size);
528 if (cxt->alignment_offset)
412791a9 529 fdisk_info(cxt, _("Alignment offset: %lu bytes"),
9af73f84 530 cxt->alignment_offset);
b546d442 531 if (fdisk_dev_has_disklabel(cxt))
412791a9 532 fdisk_info(cxt, _("Disklabel type: %s"), cxt->label->name);
21fe3dde
KZ
533
534 if (fdisk_get_disklabel_id(cxt, &id) == 0 && id)
412791a9 535 fdisk_info(cxt, _("Disk identifier: %s"), id);
5c36a0eb
KZ
536}
537
9f670072
KZ
538void list_disklabel(struct fdisk_context *cxt)
539{
540 struct fdisk_table *tb = NULL;
541 char *str;
542
543 /* print label specific stuff by libfdisk FDISK_ASK_INFO API */
544 fdisk_list_disklabel(cxt);
545
546 /* print partitions */
2cec7949 547 if (fdisk_get_partitions(cxt, &tb))
9f670072
KZ
548 return;
549 if (fdisk_table_to_string(tb, cxt, NULL, 0, &str) == 0) {
550 fputc('\n', stdout);
7fa74cb0
KZ
551 if (str) {
552 char *p = str;
553 char *next = strchr(str, '\n');
554 if (next && colors_wanted()) {
555 *next = '\0';
496c979a 556 color_scheme_enable("header", UL_COLOR_BOLD);
7fa74cb0
KZ
557 fputs(p, stdout);
558 color_disable();
559 fputc('\n', stdout);
560 p = ++next;
561 }
562 fputs(p, stdout);
563 free(str);
564 }
9f670072 565 }
8b60872e
KZ
566
567 if (fdisk_table_wrong_order(tb)) {
568 fputc('\n', stdout);
569 fdisk_info(cxt, _("Partition table entries are not in disk order."));
570 }
571
9f670072
KZ
572 fdisk_unref_table(tb);
573}
574
e916600f
KZ
575static size_t skip_empty(const unsigned char *buf, size_t i, size_t sz)
576{
577 size_t next;
578 const unsigned char *p0 = buf + i;
579
580 for (next = i + 16; next < sz; next += 16) {
581 if (memcmp(p0, buf + next, 16) != 0)
582 break;
583 }
584
585 return next == i + 16 ? i : next;
586}
6dbe3af9 587
e916600f 588static void dump_buffer(off_t base, unsigned char *buf, size_t sz, int all)
09f0c3d9 589{
e916600f
KZ
590 size_t i, l, next = 0;
591
592 if (!buf)
593 return;
594 for (i = 0, l = 0; i < sz; i++, l++) {
595 if (l == 0) {
596 if (all == 0 && !next)
597 next = skip_empty(buf, i, sz);
598 printf("%08jx ", base + i);
599 }
600 printf(" %02x", buf[i]);
601 if (l == 7) /* words separator */
602 fputs(" ", stdout);
603 else if (l == 15) {
604 fputc('\n', stdout); /* next line */
6dbe3af9 605 l = -1;
e916600f
KZ
606 if (next > i) {
607 printf("*\n");
608 i = next - 1;
609 }
610 next = 0;
6dbe3af9
KZ
611 }
612 }
613 if (l > 0)
614 printf("\n");
6dbe3af9
KZ
615}
616
e916600f
KZ
617static void dump_blkdev(struct fdisk_context *cxt, const char *name,
618 off_t offset, size_t size, int all)
e53ced85 619{
412791a9 620 fdisk_info(cxt, _("\n%s: offset = %ju, size = %zu bytes."),
e916600f
KZ
621 name, offset, size);
622
623 if (lseek(cxt->dev_fd, offset, SEEK_SET) == (off_t) -1)
624 fdisk_warn(cxt, _("cannot seek"));
5afed187
KZ
625 else {
626 unsigned char *buf = xmalloc(size);
627
628 if (read_all(cxt->dev_fd, (char *) buf, size) != (ssize_t) size)
629 fdisk_warn(cxt, _("cannot read"));
630 else
631 dump_buffer(offset, buf, size, all);
632 free(buf);
633 }
e916600f
KZ
634}
635
636void dump_firstsector(struct fdisk_context *cxt)
637{
638 int all = !isatty(STDOUT_FILENO);
639
e3661531
KZ
640 assert(cxt);
641 assert(cxt->label);
6dbe3af9 642
e916600f
KZ
643 dump_blkdev(cxt, _("First sector"), 0, cxt->sector_size, all);
644}
645
646void dump_disklabel(struct fdisk_context *cxt)
647{
648 int all = !isatty(STDOUT_FILENO);
649 int i = 0;
650 const char *name = NULL;
651 off_t offset = 0;
652 size_t size = 0;
653
654 assert(cxt);
655 assert(cxt->label);
e3661531 656
e916600f
KZ
657 while (fdisk_locate_disklabel(cxt, i++, &name, &offset, &size) == 0 && size)
658 dump_blkdev(cxt, name, offset, size, all);
6dbe3af9
KZ
659}
660
3b622ddd
DB
661static int is_ide_cdrom_or_tape(char *device)
662{
663 int fd, ret;
2b6fc908 664
1c6b3378 665 if ((fd = open(device, O_RDONLY)) < 0)
e8f26419 666 return 0;
3b622ddd 667 ret = blkdev_is_cdrom(fd);
2b6fc908 668
3b622ddd
DB
669 close(fd);
670 return ret;
2b6fc908
KZ
671}
672
6aa2ed3b 673static void print_device_pt(struct fdisk_context *cxt, char *device)
e27b42d5 674{
4e0e8253 675 if (fdisk_context_assign_device(cxt, device, 1) != 0) /* read-only */
289dcc90 676 err(EXIT_FAILURE, _("cannot open %s"), device);
823f0fd1 677
5e860870
KZ
678 list_disk_geometry(cxt);
679
b4fb2a61 680 if (fdisk_dev_has_disklabel(cxt))
9f670072 681 list_disklabel(cxt);
4ec31f10 682 fputc('\n', stdout);
6dbe3af9
KZ
683}
684
6aa2ed3b 685static void print_all_devices_pt(struct fdisk_context *cxt)
ea4824f1 686{
6aa2ed3b
KZ
687 FILE *f;
688 char line[128 + 1];
689
690 f = fopen(_PATH_PROC_PARTITIONS, "r");
691 if (!f) {
692 warn(_("cannot open %s"), _PATH_PROC_PARTITIONS);
eb63b9b8
KZ
693 return;
694 }
695
88141067 696 DBG(FRONTEND, ul_debug("reading "_PATH_PROC_PARTITIONS));
d31d3fc7 697
6aa2ed3b 698 while (fgets(line, sizeof(line), f)) {
a22c6eb2
KZ
699 char buf[PATH_MAX], *cn;
700 dev_t devno;
6aa2ed3b 701
a22c6eb2 702 if (sscanf(line, " %*d %*d %*d %128[^\n ]", buf) != 1)
eb63b9b8 703 continue;
6aa2ed3b 704
a22c6eb2
KZ
705 devno = sysfs_devname_to_devno(buf, NULL);
706 if (devno <= 0)
707 continue;
d31d3fc7 708
a22c6eb2
KZ
709 if (sysfs_devno_is_lvm_private(devno) ||
710 sysfs_devno_is_wholedisk(devno) <= 0)
711 continue;
d31d3fc7 712
a22c6eb2
KZ
713 if (!sysfs_devno_to_devpath(devno, buf, sizeof(buf)))
714 continue;
715
716 cn = canonicalize_path(buf);
717 if (!cn)
718 continue;
719 if (!is_ide_cdrom_or_tape(cn))
720 print_device_pt(cxt, cn);
721 free(cn);
eb63b9b8 722 }
6aa2ed3b 723 fclose(f);
eb63b9b8
KZ
724}
725
50dec1eb 726static sector_t get_dev_blocks(char *dev)
6da365de
DB
727{
728 int fd;
50dec1eb 729 sector_t size;
6da365de
DB
730
731 if ((fd = open(dev, O_RDONLY)) < 0)
289dcc90 732 err(EXIT_FAILURE, _("cannot open %s"), dev);
7737f698
DB
733 if (blkdev_get_sectors(fd, &size) == -1) {
734 close(fd);
735 err(EXIT_FAILURE, _("BLKGETSIZE ioctl failed on %s"), dev);
736 }
6da365de
DB
737 close(fd);
738 return size/2;
739}
740
e3a4aaa7
KZ
741static void __attribute__ ((__noreturn__)) usage(FILE *out)
742{
743 fputs(USAGE_HEADER, out);
744
745 fprintf(out,
746 _(" %1$s [options] <disk> change partition table\n"
747 " %1$s [options] -l [<disk>] list partition table(s)\n"),
748 program_invocation_short_name);
749
750 fputs(USAGE_OPTIONS, out);
751 fputs(_(" -b, --sector-size <size> physical and logical sector size\n"), out);
752 fputs(_(" -c, --compatibility[=<mode>] mode is 'dos' or 'nondos' (default)\n"), out);
753 fputs(_(" -L, --color[=<when>] colorize output (auto, always or never)\n"), out);
754 fputs(_(" -l, --list display partitions end exit\n"), out);
755 fputs(_(" -t, --type <type> recognize specified partition table type only\n"), out);
756 fputs(_(" -u, --units[=<unit>] display units: 'cylinders' or 'sectors' (default)\n"), out);
757 fputs(_(" -s, --getsz display device size in 512-byte sectors [DEPRECATED]\n"), out);
758
759 fputs(USAGE_SEPARATOR, out);
4b4e391a
KZ
760 fputs(_(" -C, --cylinders <number> specify the number of cylinders\n"), out);
761 fputs(_(" -H, --heads <number> specify the number of heads\n"), out);
762 fputs(_(" -S, --sectors <number> specify the number of sectors per track\n"), out);
e3a4aaa7
KZ
763
764 fputs(USAGE_SEPARATOR, out);
765 fputs(USAGE_HELP, out);
766 fputs(USAGE_VERSION, out);
767
768 fprintf(out, USAGE_MAN_TAIL("fdisk(8)"));
769 exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
770}
771
772
5b72b3dd
KZ
773enum {
774 ACT_FDISK = 0, /* default */
775 ACT_LIST,
776 ACT_SHOWSIZE
777};
778
e1144767
DB
779int main(int argc, char **argv)
780{
e146ae4e 781 int rc, i, c, act = ACT_FDISK;
d0c9ddc3 782 int colormode = UL_COLORMODE_UNDEF;
4e0e8253 783 struct fdisk_context *cxt;
2b6fc908 784
e3a4aaa7
KZ
785 static const struct option longopts[] = {
786 { "color", optional_argument, NULL, 'L' },
787 { "compatibility", optional_argument, NULL, 'c' },
4b4e391a
KZ
788 { "cylinders", required_argument, NULL, 'C' },
789 { "heads", required_argument, NULL, 'H' },
790 { "sectors", required_argument, NULL, 'S' },
e3a4aaa7
KZ
791 { "getsz", no_argument, NULL, 's' },
792 { "help", no_argument, NULL, 'h' },
793 { "list", no_argument, NULL, 'l' },
794 { "sector-size", required_argument, NULL, 'b' },
795 { "type", required_argument, NULL, 't' },
796 { "units", optional_argument, NULL, 'u' },
797 { "version", no_argument, NULL, 'V' },
798 { NULL, 0, NULL, 0 }
799 };
800
7eda085c
KZ
801 setlocale(LC_ALL, "");
802 bindtextdomain(PACKAGE, LOCALEDIR);
803 textdomain(PACKAGE);
b2d28533 804 atexit(close_stdout);
2b6fc908 805
4e0e8253
KZ
806 fdisk_init_debug(0);
807 cxt = fdisk_new_context();
808 if (!cxt)
809 err(EXIT_FAILURE, _("failed to allocate libfdisk context"));
810
416c43a9
KZ
811 fdisk_context_set_ask(cxt, ask_callback, NULL);
812
e3a4aaa7
KZ
813 while ((c = getopt_long(argc, argv, "b:c::C:hH:lL::sS:t:u::vV",
814 longopts, NULL)) != -1) {
2b6fc908
KZ
815 switch (c) {
816 case 'b':
6bcd192c
KZ
817 {
818 size_t sz = strtou32_or_err(optarg,
819 _("invalid sector size argument"));
820 if (sz != 512 && sz != 1024 && sz != 2048 && sz != 4096)
7c1db6b4 821 usage(stderr);
6bcd192c 822 fdisk_save_user_sector_size(cxt, sz, sz);
2b6fc908 823 break;
6bcd192c 824 }
0e6f4a20 825 case 'C':
1653f0b0
KZ
826 fdisk_save_user_geometry(cxt,
827 strtou32_or_err(optarg,
828 _("invalid cylinders argument")),
829 0, 0);
0e6f4a20 830 break;
78498b7b 831 case 'c':
852ce62b 832 if (optarg) {
2b0bc17b 833 /* this setting is independent on the current
e3a4aaa7
KZ
834 * actively used label
835 */
836 char *p = *optarg == '=' ? optarg + 1 : optarg;
5b72b3dd 837 struct fdisk_label *lb = fdisk_context_get_label(cxt, "dos");
e3a4aaa7 838
852ce62b
KZ
839 if (!lb)
840 err(EXIT_FAILURE, _("not found DOS label driver"));
e3a4aaa7 841 if (strcmp(p, "dos") == 0)
852ce62b 842 fdisk_dos_enable_compatible(lb, TRUE);
e3a4aaa7 843 else if (strcmp(p, "nondos") == 0)
852ce62b 844 fdisk_dos_enable_compatible(lb, FALSE);
e3a4aaa7
KZ
845 else {
846 warnx(_("unknown compatibility mode '%s'"), p);
852ce62b 847 usage(stderr);
e3a4aaa7 848 }
852ce62b
KZ
849 }
850 /* use default if no optarg specified */
78498b7b 851 break;
0e6f4a20 852 case 'H':
1653f0b0
KZ
853 fdisk_save_user_geometry(cxt, 0,
854 strtou32_or_err(optarg,
855 _("invalid heads argument")),
856 0);
0e6f4a20
KZ
857 break;
858 case 'S':
1653f0b0
KZ
859 fdisk_save_user_geometry(cxt, 0, 0,
860 strtou32_or_err(optarg,
861 _("invalid sectors argument")));
0e6f4a20 862 break;
2b6fc908 863 case 'l':
5b72b3dd 864 act = ACT_LIST;
2b6fc908 865 break;
80a1712f
KZ
866 case 'L':
867 if (optarg)
868 colormode = colormode_or_err(optarg,
869 _("unsupported color mode"));
870 break;
2b6fc908 871 case 's':
5b72b3dd 872 act = ACT_SHOWSIZE;
2b6fc908 873 break;
565b7da6
KZ
874 case 't':
875 {
876 struct fdisk_label *lb = NULL;
877
878 while (fdisk_context_next_label(cxt, &lb) == 0)
879 fdisk_label_set_disabled(lb, 1);
880
881 lb = fdisk_context_get_label(cxt, optarg);
882 if (!lb)
883 errx(EXIT_FAILURE, _("unsupported disklabel: %s"), optarg);
884 fdisk_label_set_disabled(lb, 0);
885 }
2b6fc908 886 case 'u':
ec10aa67
KZ
887 if (optarg && *optarg == '=')
888 optarg++;
889 if (fdisk_context_set_unit(cxt, optarg) != 0)
7c1db6b4 890 usage(stderr);
2b6fc908 891 break;
e3a4aaa7
KZ
892 case 'V': /* preferred for util-linux */
893 case 'v': /* for backward compatibility only */
a2482eb3
DB
894 printf(UTIL_LINUX_VERSION);
895 return EXIT_SUCCESS;
e1144767
DB
896 case 'h':
897 usage(stdout);
2b6fc908 898 default:
7c1db6b4 899 usage(stderr);
2b6fc908 900 }
6dbe3af9 901 }
2b6fc908 902
6bcd192c
KZ
903 if (argc-optind != 1 && fdisk_has_user_device_properties(cxt))
904 warnx(_("The device properties (sector size and geometry) should"
905 " be used with one specified device only."));
7eda085c 906
d0c9ddc3 907 colors_init(colormode, "fdisk");
ffcf0540 908
5b72b3dd
KZ
909 switch (act) {
910 case ACT_LIST:
c10937dc 911 fdisk_context_enable_listonly(cxt, 1);
ffcf0540 912
2b6fc908
KZ
913 if (argc > optind) {
914 int k;
c129767e 915 for (k = optind; k < argc; k++)
6aa2ed3b 916 print_device_pt(cxt, argv[k]);
ea4824f1 917 } else
6aa2ed3b 918 print_all_devices_pt(cxt);
5b72b3dd 919 break;
2b6fc908 920
5b72b3dd 921 case ACT_SHOWSIZE:
9564e46c 922 /* deprecated */
5b72b3dd 923 if (argc - optind <= 0)
7c1db6b4 924 usage(stderr);
2b6fc908 925
6da365de 926 for (i = optind; i < argc; i++) {
5b72b3dd 927 if (argc - optind == 1)
6da365de 928 printf("%llu\n", get_dev_blocks(argv[i]));
2b6fc908 929 else
6da365de 930 printf("%s: %llu\n", argv[i], get_dev_blocks(argv[i]));
6dbe3af9 931 }
5b72b3dd 932 break;
6dbe3af9 933
5b72b3dd
KZ
934 case ACT_FDISK:
935 if (argc-optind != 1)
936 usage(stderr);
7eda085c 937
5b72b3dd 938 /* Here starts interactive mode, use fdisk_{warn,info,..} functions */
496c979a 939 color_scheme_enable("welcome", UL_COLOR_GREEN);
09f0c3d9 940 fdisk_info(cxt, _("Welcome to fdisk (%s)."), PACKAGE_STRING);
80a1712f
KZ
941 color_disable();
942 fdisk_info(cxt, _("Changes will remain in memory only, until you decide to write them.\n"
943 "Be careful before using the write command.\n"));
2d8988bd 944
e146ae4e
KZ
945 rc = fdisk_context_assign_device(cxt, argv[optind], 0);
946 if (rc == -EACCES) {
947 rc = fdisk_context_assign_device(cxt, argv[optind], 1);
948 if (rc == 0)
949 fdisk_warnx(cxt, _("Device open in read-only mode."));
950 }
951 if (rc)
2d8988bd
KZ
952 err(EXIT_FAILURE, _("cannot open %s"), argv[optind]);
953
5b72b3dd 954 fflush(stdout);
56c07b96 955
5b72b3dd 956 if (!fdisk_dev_has_disklabel(cxt)) {
2d8988bd 957 fdisk_info(cxt, _("Device does not contain a recognized partition table."));
5b72b3dd 958 fdisk_create_disklabel(cxt, NULL);
433d05ff
KZ
959
960 } else if (fdisk_is_disklabel(cxt, GPT) && fdisk_gpt_is_hybrid(cxt))
961 fdisk_warnx(cxt, _(
962 "The hybrid GPT detected. You have to sync "
963 "the hybrid MBR manually (expert command 'M')."));
6dbe3af9 964
5b72b3dd
KZ
965 while (1)
966 process_fdisk_menu(&cxt);
967 }
9777759a 968
4e0e8253 969 fdisk_free_context(cxt);
5b72b3dd 970 return EXIT_SUCCESS;
6dbe3af9 971}