]> git.ipfire.org Git - thirdparty/util-linux.git/blame - fdisks/fdisk.c
fdisk: (sgi) remove printf from code
[thirdparty/util-linux.git] / fdisks / fdisk.c
CommitLineData
6dbe3af9
KZ
1/* fdisk.c -- Partition table manipulator for Linux.
2 *
3 * Copyright (C) 1992 A. V. Le Blanc (LeBlanc@mcc.ac.uk)
38b36353 4 * Copyright (C) 2012 Davidlohr Bueso <dave@gnu.org>
6dbe3af9
KZ
5 *
6 * This program is free software. You can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation: either version 1 or
9 * (at your option) any later version.
6dbe3af9
KZ
10 */
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
52b38677 25#include "xalloc.h"
22853e4a 26#include "nls.h"
e66ac5d3 27#include "rpmatch.h"
810f986b 28#include "blkdev.h"
7eda085c 29#include "common.h"
b8d22034 30#include "mbsalign.h"
726f69e2 31#include "fdisk.h"
929f243f 32#include "wholedisk.h"
6bec8710
KZ
33#include "pathnames.h"
34#include "canonicalize.h"
20aa2570 35#include "strutils.h"
b2d28533 36#include "closestream.h"
5c36a0eb 37
b4bfbadd 38#include "pt-sun.h" /* to toggle flags */
5c36a0eb 39#include "fdisksgilabel.h"
e7fa917a 40#include "fdiskmaclabel.h"
e2ee9178 41#include "fdiskdoslabel.h"
37eadc17 42#include "fdiskbsdlabel.h"
5c36a0eb 43
48d7b13a
KZ
44#ifdef HAVE_LINUX_COMPILER_H
45#include <linux/compiler.h>
46#endif
47#ifdef HAVE_LINUX_BLKPG_H
7eda085c
KZ
48#include <linux/blkpg.h>
49#endif
6dbe3af9 50
749af4b6 51
50dec1eb 52sector_t get_nr_sects(struct partition *p) {
2b6fc908
KZ
53 return read4_little_endian(p->size4);
54}
55
823f0fd1 56char *line_ptr, /* interactive input */
22853e4a 57 line_buffer[LINE_LENGTH];
6dbe3af9 58
e3661531 59int nowarn = 0; /* no warnings for fdisk -l/-s */
6dbe3af9 60
8e40a677
KZ
61/* when C/H/S specified on command line */
62static unsigned int user_cylinders, user_heads, user_sectors;
365acc97 63
ec10aa67
KZ
64void toggle_units(struct fdisk_context *cxt)
65{
66 fdisk_context_set_unit(cxt,
67 fdisk_context_use_cylinders(cxt) ? "sectors" :
68 "cylinders");
69 if (fdisk_context_use_cylinders(cxt))
70 fdisk_info(cxt, _("Changing display/entry units to cylinders (DEPRECATED!)."));
71 else
72 fdisk_info(cxt, _("Changing display/entry units to sectors."));
73}
74
75
7c1db6b4
FC
76static void __attribute__ ((__noreturn__)) usage(FILE *out)
77{
78 fprintf(out, _("Usage:\n"
79 " %1$s [options] <disk> change partition table\n"
80 " %1$s [options] -l <disk> list partition table(s)\n"
81 " %1$s -s <partition> give partition size(s) in blocks\n"
82 "\nOptions:\n"
83 " -b <size> sector size (512, 1024, 2048 or 4096)\n"
84 " -c[=<mode>] compatible mode: 'dos' or 'nondos' (default)\n"
85 " -h print this help text\n"
86 " -u[=<unit>] display units: 'cylinders' or 'sectors' (default)\n"
87 " -v print program version\n"
88 " -C <number> specify the number of cylinders\n"
89 " -H <number> specify the number of heads\n"
90 " -S <number> specify the number of sectors per track\n"
91 "\n"), program_invocation_short_name);
92 exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
93}
94
888a2e1c
SK
95void __attribute__((__noreturn__))
96fatal(struct fdisk_context *cxt, enum failure why)
9f6c866f 97{
823f0fd1 98 close(cxt->dev_fd);
6dbe3af9 99 switch (why) {
6dbe3af9 100 case unable_to_read:
823f0fd1 101 err(EXIT_FAILURE, _("unable to read %s"), cxt->dev_path);
c845f12c 102
6dbe3af9 103 case unable_to_seek:
823f0fd1 104 err(EXIT_FAILURE, _("unable to seek on %s"), cxt->dev_path);
c845f12c 105
6dbe3af9 106 case unable_to_write:
823f0fd1 107 err(EXIT_FAILURE, _("unable to write %s"), cxt->dev_path);
c845f12c 108
7eda085c 109 case ioctl_error:
823f0fd1 110 err(EXIT_FAILURE, _("BLKGETSIZE ioctl failed on %s"), cxt->dev_path);
c845f12c 111
c07ebfa1 112 default:
c845f12c 113 err(EXIT_FAILURE, _("fatal error"));
6dbe3af9 114 }
6dbe3af9
KZ
115}
116
22853e4a
KZ
117struct partition *
118get_part_table(int i) {
119 return ptes[i].part_table;
120}
121
7b575fcc 122void list_partition_types(struct fdisk_context *cxt)
6dbe3af9 123{
7b575fcc 124 struct fdisk_parttype *types;
76f17cf2 125 size_t ntypes = 0;
6dbe3af9 126
7b575fcc
KZ
127 if (!cxt || !cxt->label || !cxt->label->parttypes)
128 return;
2b6fc908 129
7b575fcc 130 types = cxt->label->parttypes;
76f17cf2 131 ntypes = cxt->label->nparttypes;
6dbe3af9 132
7b575fcc
KZ
133 if (types[0].typestr == NULL) {
134 /*
135 * Prints in 4 columns in format <hex> <name>
136 */
76f17cf2
KZ
137 size_t last[4], done = 0, next = 0, size;
138 int i;
b8d22034 139
76f17cf2
KZ
140 size = ntypes;
141 if (types[ntypes - 1].name == NULL)
142 size--;
7b575fcc
KZ
143
144 for (i = 3; i >= 0; i--)
145 last[3 - i] = done += (size + i - done) / (i + 1);
146 i = done = 0;
147
148 do {
149 #define NAME_WIDTH 15
150 char name[NAME_WIDTH * MB_LEN_MAX];
151 size_t width = NAME_WIDTH;
152 struct fdisk_parttype *t = &types[next];
153 size_t ret;
154
76f17cf2
KZ
155 if (t->name) {
156 printf("%c%2x ", i ? ' ' : '\n', t->type);
157 ret = mbsalign(_(t->name), name, sizeof(name),
158 &width, MBS_ALIGN_LEFT, 0);
7b575fcc 159
76f17cf2
KZ
160 if (ret == (size_t)-1 || ret >= sizeof(name))
161 printf("%-15.15s", _(t->name));
162 else
163 fputs(name, stdout);
164 }
7b575fcc
KZ
165
166 next = last[i++] + done;
167 if (i > 3 || next >= last[i]) {
168 i = 0;
169 next = ++done;
170 }
171 } while (done < last[0]);
172
173 } else {
174 /*
175 * Prints 1 column in format <idx> <name> <typestr>
176 */
177 struct fdisk_parttype *t;
76f17cf2 178 size_t i;
7b575fcc 179
76f17cf2
KZ
180 for (i = 0, t = types; t && i < ntypes; t++, i++) {
181 if (t->name)
182 printf("%3zu %-30s %s\n", i + 1,
183 t->name, t->typestr);
184 }
7b575fcc 185 }
6dbe3af9
KZ
186 putchar('\n');
187}
188
22853e4a
KZ
189static int
190test_c(char **m, char *mesg) {
6dbe3af9
KZ
191 int val = 0;
192 if (!*m)
7eda085c 193 fprintf(stderr, _("You must set"));
6dbe3af9
KZ
194 else {
195 fprintf(stderr, " %s", *m);
196 val = 1;
197 }
198 *m = mesg;
199 return val;
200}
201
24cd580b 202int warn_geometry(struct fdisk_context *cxt)
e2ee9178 203{
6dbe3af9
KZ
204 char *m = NULL;
205 int prev = 0;
a47f2e66 206
ff5775bd 207 if (fdisk_is_disklabel(cxt, SGI)) /* cannot set cylinders etc anyway */
a47f2e66 208 return 0;
24cd580b 209 if (!cxt->geom.heads)
7eda085c 210 prev = test_c(&m, _("heads"));
24cd580b 211 if (!cxt->geom.sectors)
7eda085c 212 prev = test_c(&m, _("sectors"));
24cd580b 213 if (!cxt->geom.cylinders)
7eda085c 214 prev = test_c(&m, _("cylinders"));
6dbe3af9
KZ
215 if (!m)
216 return 0;
217 fprintf(stderr,
7eda085c
KZ
218 _("%s%s.\nYou can do this from the extra functions menu.\n"),
219 prev ? _(" and ") : " ", m);
6dbe3af9
KZ
220 return 1;
221}
222
e53ced85 223void warn_limits(struct fdisk_context *cxt)
e2ee9178 224{
618882d6
DB
225 if (cxt->total_sectors > UINT_MAX && !nowarn) {
226 unsigned long long bytes = cxt->total_sectors * cxt->sector_size;
06023c2e 227 int giga = bytes / 1000000000;
32b40fec
KZ
228 int hectogiga = (giga + 50) / 100;
229
ee5355e0
KZ
230 fprintf(stderr, _("\n"
231"WARNING: The size of this disk is %d.%d TB (%llu bytes).\n"
32b40fec 232"DOS partition table format can not be used on drives for volumes\n"
e53ced85 233"larger than (%llu bytes) for %ld-byte sectors. Use parted(1) and GUID \n"
ee5355e0 234"partition table format (GPT).\n\n"),
32b40fec 235 hectogiga / 10, hectogiga % 10,
06023c2e 236 bytes,
e53ced85
DB
237 (sector_t ) UINT_MAX * cxt->sector_size,
238 cxt->sector_size);
ee5355e0 239 }
6dbe3af9
KZ
240}
241
bddd84e7 242static void maybe_exit(struct fdisk_context *cxt, int rc, int *asked)
aead9d13
FC
243{
244 char line[LINE_LENGTH];
245
bddd84e7
KZ
246 assert(cxt);
247 assert(cxt->label);
248
aead9d13 249 putchar('\n');
8feb31e5
KZ
250 if (asked)
251 *asked = 0;
aead9d13 252
bddd84e7 253 if (fdisk_label_is_changed(cxt->label)) {
aead9d13
FC
254 fprintf(stderr, _("Do you really want to quit? "));
255
256 if (!fgets(line, LINE_LENGTH, stdin) || rpmatch(line) == 1)
bddd84e7 257 goto leave;
8feb31e5
KZ
258 if (asked)
259 *asked = 1;
bddd84e7
KZ
260 return;
261 }
262leave:
263 fdisk_free_context(cxt);
264 exit(rc);
aead9d13
FC
265}
266
5c36a0eb 267/* read line; return 0 or first char */
bddd84e7 268int read_line(struct fdisk_context *cxt, int *asked)
6dbe3af9 269{
5c36a0eb 270 line_ptr = line_buffer;
7eda085c 271 if (!fgets(line_buffer, LINE_LENGTH, stdin)) {
bddd84e7 272 maybe_exit(cxt, 1, asked);
6dbe3af9 273 return 0;
7eda085c 274 }
8feb31e5
KZ
275 if (asked)
276 *asked = 0;
6dbe3af9
KZ
277 while (*line_ptr && !isgraph(*line_ptr))
278 line_ptr++;
279 return *line_ptr;
280}
281
bddd84e7 282char read_char(struct fdisk_context *cxt, char *mesg)
6dbe3af9 283{
2b6fc908 284 do {
6dbe3af9 285 fputs(mesg, stdout);
66ee8158 286 fflush (stdout); /* requested by niles@scyld.com */
bddd84e7
KZ
287
288 } while (!read_line(cxt, NULL));
289
6dbe3af9
KZ
290 return *line_ptr;
291}
292
bddd84e7 293char read_chars(struct fdisk_context *cxt, char *mesg)
2b6fc908 294{
8feb31e5
KZ
295 int rc, asked = 0;
296
297 do {
298 fputs(mesg, stdout);
299 fflush (stdout); /* niles@scyld.com */
bddd84e7 300 rc = read_line(cxt, &asked);
8feb31e5
KZ
301 } while (asked);
302
303 if (!rc) {
2b6fc908 304 *line_ptr = '\n';
5c36a0eb
KZ
305 line_ptr[1] = 0;
306 }
307 return *line_ptr;
2b6fc908
KZ
308}
309
559d921e 310struct fdisk_parttype *read_partition_type(struct fdisk_context *cxt)
6dbe3af9 311{
559d921e
KZ
312 if (!cxt || !cxt->label || !cxt->label->nparttypes)
313 return NULL;
314
315 do {
316 size_t sz;
317
318 if (cxt->label->parttypes[0].typestr)
bddd84e7 319 read_chars(cxt, _("Partition type (type L to list all types): "));
559d921e 320 else
bddd84e7 321 read_chars(cxt, _("Hex code (type L to list all codes): "));
559d921e
KZ
322
323 sz = strlen(line_ptr);
324 if (!sz || line_ptr[sz - 1] != '\n' || sz == 1)
325 continue;
326 line_ptr[sz - 1] = '\0';
327
328 if (tolower(*line_ptr) == 'l')
329 list_partition_types(cxt);
330 else
331 return fdisk_parse_parttype(cxt, line_ptr);
332 } while (1);
333
334 return NULL;
726f69e2
KZ
335}
336
74fcee98 337/* deprecated in favour of fdisk_ask_number() */
9dea2923 338unsigned int
e53ced85
DB
339read_int_with_suffix(struct fdisk_context *cxt,
340 unsigned int low, unsigned int dflt, unsigned int high,
2c911261 341 unsigned int base, char *mesg, int *is_suffix_used)
726f69e2 342{
2c911261 343 unsigned int res;
5c36a0eb 344 int default_ok = 1;
0c381880 345 int absolute = 0;
5c36a0eb 346 static char *ms = NULL;
e99da659 347 static size_t mslen = 0;
5c36a0eb 348
c07ebfa1
KZ
349 if (!ms || strlen(mesg)+100 > mslen) {
350 mslen = strlen(mesg)+200;
52b38677 351 ms = xrealloc(ms,mslen);
726f69e2 352 }
6dbe3af9 353
5c36a0eb
KZ
354 if (dflt < low || dflt > high)
355 default_ok = 0;
356
357 if (default_ok)
df1dddf9 358 snprintf(ms, mslen, _("%s (%u-%u, default %u): "),
c07ebfa1 359 mesg, low, high, dflt);
5c36a0eb 360 else
df1dddf9 361 snprintf(ms, mslen, "%s (%u-%u): ",
c07ebfa1 362 mesg, low, high);
5c36a0eb 363
6dbe3af9 364 while (1) {
5c36a0eb
KZ
365 int use_default = default_ok;
366
367 /* ask question and read answer */
bddd84e7 368 while (read_chars(cxt, ms) != '\n' && !isdigit(*line_ptr)
5c36a0eb
KZ
369 && *line_ptr != '-' && *line_ptr != '+')
370 continue;
371
726f69e2 372 if (*line_ptr == '+' || *line_ptr == '-') {
a5a16c68 373 int minus = (*line_ptr == '-');
b1edb510 374 int suflen;
a5a16c68 375
0c381880 376 absolute = 0;
2c911261 377 res = atoi(line_ptr + 1);
a5a16c68 378
b1edb510 379 while (isdigit(*++line_ptr))
726f69e2 380 use_default = 0;
a5a16c68 381
74396048
FC
382 while (isspace(*line_ptr))
383 line_ptr++;
384
b1edb510
KZ
385 suflen = strlen(line_ptr) - 1;
386
387 while(isspace(*(line_ptr + suflen)))
388 *(line_ptr + suflen--) = '\0';
389
390 if ((*line_ptr == 'C' || *line_ptr == 'c') &&
391 *(line_ptr + 1) == '\0') {
392 /*
393 * Cylinders
394 */
ec10aa67 395 if (fdisk_context_use_cylinders(cxt))
24cd580b 396 res *= cxt->geom.heads * cxt->geom.sectors;
5ea8931c
KZ
397 } else if (*line_ptr &&
398 *(line_ptr + 1) == 'B' &&
b1edb510
KZ
399 *(line_ptr + 2) == '\0') {
400 /*
401 * 10^N
402 */
403 if (*line_ptr == 'K')
a5a16c68 404 absolute = 1000;
b1edb510 405 else if (*line_ptr == 'M')
a5a16c68 406 absolute = 1000000;
b1edb510 407 else if (*line_ptr == 'G')
a5a16c68 408 absolute = 1000000000;
b1edb510
KZ
409 else
410 absolute = -1;
5ea8931c
KZ
411 } else if (*line_ptr &&
412 *(line_ptr + 1) == '\0') {
b1edb510
KZ
413 /*
414 * 2^N
415 */
416 if (*line_ptr == 'K')
417 absolute = 1 << 10;
418 else if (*line_ptr == 'M')
419 absolute = 1 << 20;
420 else if (*line_ptr == 'G')
421 absolute = 1 << 30;
422 else
423 absolute = -1;
424 } else if (*line_ptr != '\0')
425 absolute = -1;
426
427 if (absolute == -1) {
428 printf(_("Unsupported suffix: '%s'.\n"), line_ptr);
429 printf(_("Supported: 10^N: KB (KiloByte), MB (MegaByte), GB (GigaByte)\n"
430 " 2^N: K (KibiByte), M (MebiByte), G (GibiByte)\n"));
431 continue;
726f69e2 432 }
b1edb510 433
2c911261 434 if (absolute && res) {
a5a16c68
KZ
435 unsigned long long bytes;
436 unsigned long unit;
437
2c911261 438 bytes = (unsigned long long) res * absolute;
ec10aa67 439 unit = cxt->sector_size * fdisk_context_get_units_per_sector(cxt);
a5a16c68
KZ
440 bytes += unit/2; /* round */
441 bytes /= unit;
2c911261 442 res = bytes;
a5a16c68
KZ
443 }
444 if (minus)
2c911261
FC
445 res = -res;
446 res += base;
5c36a0eb 447 } else {
2c911261 448 res = atoi(line_ptr);
5c36a0eb 449 while (isdigit(*line_ptr)) {
726f69e2
KZ
450 line_ptr++;
451 use_default = 0;
452 }
453 }
0c381880
FC
454 if (use_default) {
455 printf(_("Using default value %u\n"), dflt);
456 return dflt;
457 }
2c911261 458 if (res >= low && res <= high)
6dbe3af9 459 break;
726f69e2 460 else
7eda085c 461 printf(_("Value out of range.\n"));
6dbe3af9 462 }
0c381880
FC
463 if (is_suffix_used)
464 *is_suffix_used = absolute > 0;
2c911261 465 return res;
6dbe3af9
KZ
466}
467
b7e76f8e
KZ
468/*
469 * Print the message MESG, then read an integer in LOW..HIGH.
470 * If the user hits Enter, DFLT is returned, provided that is in LOW..HIGH.
471 * Answers like +10 are interpreted as offsets from BASE.
472 *
473 * There is no default if DFLT is not between LOW and HIGH.
474 */
475unsigned int
e53ced85
DB
476read_int(struct fdisk_context *cxt,
477 unsigned int low, unsigned int dflt, unsigned int high,
b7e76f8e
KZ
478 unsigned int base, char *mesg)
479{
e53ced85 480 return read_int_with_suffix(cxt, low, dflt, high, base, mesg, NULL);
b7e76f8e
KZ
481}
482
852ce62b
KZ
483static void toggle_dos_compatibility_flag(struct fdisk_context *cxt)
484{
485 struct fdisk_label *lb = fdisk_context_get_label(cxt, "dos");
486 int flag;
487
488 if (!lb)
489 return;
490
491 flag = !fdisk_dos_is_compatible(lb);
492
493 if (flag)
278f63c0 494 printf(_("DOS Compatibility flag is set (DEPRECATED!)\n"));
edd7b958 495 else
7eda085c 496 printf(_("DOS Compatibility flag is not set\n"));
edd7b958 497
852ce62b
KZ
498 fdisk_dos_enable_compatible(lb, flag);
499
500 if (fdisk_is_disklabel(cxt, DOS))
501 fdisk_reset_alignment(cxt);
6dbe3af9
KZ
502}
503
61c4cb85 504static void delete_partition(struct fdisk_context *cxt, int partnum)
47104bae 505{
61c4cb85 506 if (partnum < 0 || warn_geometry(cxt))
4a96a62a
FC
507 return;
508
1f5eb51b
DB
509 if (fdisk_delete_partition(cxt, partnum) != 0)
510 printf(_("Could not delete partition %d\n"), partnum + 1);
511 else
512 printf(_("Partition %d is deleted\n"), partnum + 1);
6dbe3af9
KZ
513}
514
02460b8a 515static void change_partition_type(struct fdisk_context *cxt)
e53ced85 516{
641a75ca 517 size_t i;
559d921e 518 struct fdisk_parttype *t, *org_t;
6dbe3af9 519
e3661531
KZ
520 assert(cxt);
521 assert(cxt->label);
522
641a75ca 523 if (fdisk_ask_partnum(cxt, &i, FALSE))
24f4bbff 524 return;
2b6fc908 525
010186f2
KZ
526 org_t = t = fdisk_get_partition_type(cxt, i);
527 if (!t)
641a75ca 528 printf(_("Partition %zu does not exist yet!\n"), i + 1);
010186f2 529
02460b8a 530 else do {
559d921e 531 t = read_partition_type(cxt);
559d921e
KZ
532 if (!t)
533 continue;
534
02460b8a 535 if (fdisk_set_partition_type(cxt, i, t) == 0) {
02460b8a
KZ
536 printf (_("Changed type of partition '%s' to '%s'\n"),
537 org_t ? org_t->name : _("Unknown"),
538 t ? t->name : _("Unknown"));
539 } else {
641a75ca 540 printf (_("Type of partition %zu is unchanged: %s\n"),
02460b8a
KZ
541 i + 1,
542 org_t ? org_t->name : _("Unknown"));
6dbe3af9 543 }
02460b8a
KZ
544 break;
545 } while (1);
559d921e
KZ
546
547 fdisk_free_parttype(t);
548 fdisk_free_parttype(org_t);
6dbe3af9
KZ
549}
550
22853e4a 551static void
7737f698 552list_disk_geometry(struct fdisk_context *cxt) {
618882d6 553 unsigned long long bytes = cxt->total_sectors * cxt->sector_size;
24f4bbff
KZ
554 long megabytes = bytes/1000000;
555
556 if (megabytes < 10000)
f8527f4b 557 printf(_("\nDisk %s: %ld MB, %lld bytes"),
823f0fd1 558 cxt->dev_path, megabytes, bytes);
32b40fec
KZ
559 else {
560 long hectomega = (megabytes + 50) / 100;
f8527f4b 561 printf(_("\nDisk %s: %ld.%ld GB, %llu bytes"),
823f0fd1 562 cxt->dev_path, hectomega / 10, hectomega % 10, bytes);
32b40fec 563 }
f8527f4b 564 printf(_(", %llu sectors\n"), cxt->total_sectors);
b1b1a7b7
KZ
565
566 if (is_dos_compatible(cxt) || fdisk_is_disklabel(cxt, SUN))
567 printf(_("Geometry: %d heads, %llu sectors/track, %llu cylinders\n"),
a7a6f7d2 568 cxt->geom.heads, cxt->geom.sectors, cxt->geom.cylinders);
b1b1a7b7 569
e53ced85 570 printf(_("Units = %s of %d * %ld = %ld bytes\n"),
ec10aa67
KZ
571 fdisk_context_get_unit(cxt, PLURAL),
572 fdisk_context_get_units_per_sector(cxt),
573 cxt->sector_size,
574 fdisk_context_get_units_per_sector(cxt) * cxt->sector_size);
05dc9645 575
e53ced85
DB
576 printf(_("Sector size (logical/physical): %lu bytes / %lu bytes\n"),
577 cxt->sector_size, cxt->phy_sector_size);
a8a86a1c 578 printf(_("I/O size (minimum/optimal): %lu bytes / %lu bytes\n"),
e53ced85
DB
579 cxt->min_io_size, cxt->io_size);
580 if (cxt->alignment_offset)
581 printf(_("Alignment offset: %lu bytes\n"), cxt->alignment_offset);
b546d442
KZ
582 if (fdisk_dev_has_disklabel(cxt))
583 printf(_("Disk label type: %s\n"), cxt->label->name);
ff5775bd 584 if (fdisk_is_disklabel(cxt, DOS))
38b36353 585 dos_print_mbr_id(cxt);
bb6aacfe 586 printf("\n");
5c36a0eb
KZ
587}
588
766d5156
DB
589static void list_table(struct fdisk_context *cxt, int xtra)
590{
ff5775bd 591 if (fdisk_is_disklabel(cxt, SGI)) {
7737f698 592 sgi_list_table(cxt, xtra);
5c36a0eb
KZ
593 return;
594 }
2b6fc908 595
7737f698 596 list_disk_geometry(cxt);
22853e4a 597
3c5fb475 598 if (fdisk_is_disklabel(cxt, OSF))
7737f698 599 xbsd_print_disklabel(cxt, xtra);
22853e4a 600
3c5fb475 601 else if (fdisk_is_disklabel(cxt, DOS))
6d864a49 602 dos_list_table(cxt, xtra);
3c5fb475
KZ
603 else
604 fdisk_list_disklabel(cxt);
605
6dbe3af9
KZ
606}
607
2ca61a61
DB
608static void verify(struct fdisk_context *cxt)
609{
24cd580b 610 if (warn_geometry(cxt))
6dbe3af9
KZ
611 return;
612
2ca61a61 613 fdisk_verify_disklabel(cxt);
6dbe3af9
KZ
614}
615
e53ced85 616static void new_partition(struct fdisk_context *cxt)
9dea2923 617{
9fcd49d5
KZ
618 assert(cxt);
619 assert(cxt->label);
620
0f639e54 621 if (warn_geometry(cxt))
e8f26419 622 return;
e8f26419 623
416c43a9 624 fdisk_add_partition(cxt, NULL);
6dbe3af9
KZ
625}
626
fae7b1bc
DB
627static void write_table(struct fdisk_context *cxt)
628{
629 int rc;
6dbe3af9 630
fae7b1bc
DB
631 rc = fdisk_write_disklabel(cxt);
632 if (rc)
633 err(EXIT_FAILURE, _("cannot write disk label"));
6dbe3af9 634
7eda085c 635 printf(_("The partition table has been altered!\n\n"));
7737f698 636 reread_partition_table(cxt, 1);
eb63b9b8
KZ
637}
638
639void
7737f698 640reread_partition_table(struct fdisk_context *cxt, int leave) {
eb63b9b8 641 int i;
edd867fa 642 struct stat statbuf;
6dbe3af9 643
823f0fd1 644 i = fstat(cxt->dev_fd, &statbuf);
edd867fa 645 if (i == 0 && S_ISBLK(statbuf.st_mode)) {
edd867fa 646 sync();
6b0054a2
ST
647#ifdef BLKRRPART
648 printf(_("Calling ioctl() to re-read partition table.\n"));
823f0fd1 649 i = ioctl(cxt->dev_fd, BLKRRPART);
6b0054a2
ST
650#else
651 errno = ENOSYS;
652 i = 1;
653#endif
726f69e2
KZ
654 }
655
e8f26419 656 if (i) {
960cf573 657 printf(_("\nWARNING: Re-reading the partition table failed with error %d: %m.\n"
c64061c9
VD
658 "The kernel still uses the old table. The new table will be used at\n"
659 "the next reboot or after you run partprobe(8) or kpartx(8)\n"),
960cf573 660 errno);
e8f26419 661 }
6dbe3af9 662
eb63b9b8 663 if (leave) {
823f0fd1 664 if (fsync(cxt->dev_fd) || close(cxt->dev_fd)) {
a47f2e66
KZ
665 fprintf(stderr, _("\nError closing file\n"));
666 exit(1);
667 }
eb63b9b8
KZ
668
669 printf(_("Syncing disks.\n"));
670 sync();
eb63b9b8
KZ
671 exit(!!i);
672 }
6dbe3af9
KZ
673}
674
675#define MAX_PER_LINE 16
22853e4a 676static void
e53ced85 677print_buffer(struct fdisk_context *cxt, unsigned char pbuffer[]) {
e99da659 678 unsigned int i, l;
6dbe3af9 679
e53ced85 680 for (i = 0, l = 0; i < cxt->sector_size; i++, l++) {
6dbe3af9
KZ
681 if (l == 0)
682 printf("0x%03X:", i);
be97c5f3 683 printf(" %02X", pbuffer[i]);
6dbe3af9
KZ
684 if (l == MAX_PER_LINE - 1) {
685 printf("\n");
686 l = -1;
687 }
688 }
689 if (l > 0)
690 printf("\n");
691 printf("\n");
692}
693
e53ced85
DB
694static void print_raw(struct fdisk_context *cxt)
695{
e3661531
KZ
696 size_t i;
697
698 assert(cxt);
699 assert(cxt->label);
6dbe3af9 700
e53ced85 701 printf(_("Device: %s\n"), cxt->dev_path);
ff5775bd
DB
702 if (fdisk_is_disklabel(cxt, SUN) ||
703 fdisk_is_disklabel(cxt, SGI) ||
704 fdisk_is_disklabel(cxt, GPT))
67987b47 705 print_buffer(cxt, cxt->firstsector);
e3661531 706
76b86412
KZ
707 else if (fdisk_is_disklabel(cxt, DOS)) {
708 for (i = 3; i < cxt->label->nparts_max; i++)
e53ced85 709 print_buffer(cxt, ptes[i].sectorbuffer);
76b86412 710 }
6dbe3af9
KZ
711}
712
823f0fd1 713static void __attribute__ ((__noreturn__)) handle_quit(struct fdisk_context *cxt)
365f01fc 714{
823f0fd1 715 fdisk_free_context(cxt);
365f01fc
DB
716 printf("\n");
717 exit(EXIT_SUCCESS);
718}
719
22853e4a 720static void
7737f698 721expert_command_prompt(struct fdisk_context *cxt)
e97a991a 722{
22853e4a 723 char c;
641a75ca 724 size_t n;
22853e4a 725
e3661531
KZ
726 assert(cxt);
727
a5c1b0fa
KZ
728 fdisk_context_enable_details(cxt, 1);
729
6dbe3af9 730 while(1) {
e3661531
KZ
731 assert(cxt->label);
732
a410f8df
KZ
733 c = process_fdisk_menu(cxt);
734 if (c <= 0)
735 continue;
736
737 /* well, process_fdisk_menu() returns commands that
738 * are not yet implemented by menu callbacks. Let's
739 * perform the commands here */
22853e4a 740 switch (c) {
2b6fc908 741 case 'b':
641a75ca
KZ
742 if (fdisk_is_disklabel(cxt, DOS) &&
743 fdisk_ask_partnum(cxt, &n, FALSE) == 0)
744 dos_move_begin(cxt, n);
2b6fc908 745 break;
2b6fc908 746 case 'd':
e53ced85 747 print_raw(cxt);
2b6fc908
KZ
748 break;
749 case 'e':
ff5775bd 750 if (fdisk_is_disklabel(cxt, SGI))
5c36a0eb 751 sgi_set_xcyl();
9f280903 752 else if (fdisk_is_disklabel(cxt, DOS))
5dfca634 753 dos_list_table_expert(cxt, 1);
5c36a0eb 754 break;
22853e4a 755 case 'f':
ff5775bd 756 if (fdisk_is_disklabel(cxt, DOS))
e3661531 757 dos_fix_partition_table_order(cxt);
22853e4a 758 break;
5c36a0eb 759 case 'g':
287ce9ed
KZ
760 /* Deprecated, use 'G' in main menu, just for backward
761 * compatibility only. */
de3d6c93 762 fdisk_create_disklabel(cxt, "sgi");
2b6fc908 763 break;
2b6fc908 764 case 'i':
9f280903 765 if (fdisk_is_disklabel(cxt, DOS))
38b36353 766 dos_set_mbr_id(cxt);
2b6fc908 767 break;
2b6fc908 768 case 'p':
414b6b0f 769 list_table(cxt, 1);
2b6fc908
KZ
770 break;
771 case 'q':
823f0fd1 772 handle_quit(cxt);
2b6fc908 773 case 'r':
a5c1b0fa 774 fdisk_context_enable_details(cxt, 0);
2b6fc908 775 return;
2b6fc908 776 case 'v':
e53ced85 777 verify(cxt);
2b6fc908
KZ
778 break;
779 case 'w':
d8de0955 780 write_table(cxt);
2b6fc908 781 break;
6dbe3af9
KZ
782 }
783 }
784}
785
3b622ddd
DB
786static int is_ide_cdrom_or_tape(char *device)
787{
788 int fd, ret;
2b6fc908 789
1c6b3378 790 if ((fd = open(device, O_RDONLY)) < 0)
e8f26419 791 return 0;
3b622ddd 792 ret = blkdev_is_cdrom(fd);
2b6fc908 793
3b622ddd
DB
794 close(fd);
795 return ret;
2b6fc908
KZ
796}
797
ea4824f1 798/* Print disk geometry and partition table of a specified device (-l option) */
4e0e8253
KZ
799static void print_partition_table_from_option(struct fdisk_context *cxt,
800 char *device, unsigned long sector_size)
e27b42d5 801{
4e0e8253 802 if (fdisk_context_assign_device(cxt, device, 1) != 0) /* read-only */
289dcc90 803 err(EXIT_FAILURE, _("cannot open %s"), device);
823f0fd1 804
759d093f 805 if (sector_size) /* passed -b option, override autodiscovery */
aa42788d 806 fdisk_override_sector_size(cxt, sector_size);
759d093f 807
9a5e29e9 808 if (user_cylinders || user_heads || user_sectors)
aa42788d 809 fdisk_override_geometry(cxt, user_cylinders,
759d093f 810 user_heads, user_sectors);
84e18f76 811
b4fb2a61 812 if (fdisk_dev_has_disklabel(cxt))
7737f698 813 list_table(cxt, 0);
b4fb2a61
KZ
814 else
815 list_disk_geometry(cxt);
6dbe3af9
KZ
816}
817
c129767e
KZ
818/*
819 * for fdisk -l:
820 * try all things in /proc/partitions that look like a full disk
821 */
22853e4a 822static void
4e0e8253
KZ
823print_all_partition_table_from_option(struct fdisk_context *cxt,
824 unsigned long sector_size)
ea4824f1 825{
eb63b9b8 826 FILE *procpt;
657d9adb 827 char line[128 + 1], ptname[128 + 1], devname[256];
981b80b7
KZ
828 int ma, mi;
829 unsigned long long sz;
eb63b9b8 830
6bec8710 831 procpt = fopen(_PATH_PROC_PARTITIONS, "r");
eb63b9b8 832 if (procpt == NULL) {
6bec8710 833 fprintf(stderr, _("cannot open %s\n"), _PATH_PROC_PARTITIONS);
eb63b9b8
KZ
834 return;
835 }
836
837 while (fgets(line, sizeof(line), procpt)) {
bb662090 838 if (sscanf (line, " %d %d %llu %128[^\n ]",
eb63b9b8
KZ
839 &ma, &mi, &sz, ptname) != 4)
840 continue;
c07ebfa1 841 snprintf(devname, sizeof(devname), "/dev/%s", ptname);
6bec8710
KZ
842 if (is_whole_disk(devname)) {
843 char *cn = canonicalize_path(devname);
844 if (cn) {
0c48d371 845 if (!is_ide_cdrom_or_tape(cn))
4e0e8253 846 print_partition_table_from_option(cxt, cn, sector_size);
6bec8710
KZ
847 free(cn);
848 }
849 }
eb63b9b8 850 }
e8f26419 851 fclose(procpt);
eb63b9b8
KZ
852}
853
22853e4a
KZ
854static void
855unknown_command(int c) {
856 printf(_("%c: unknown command\n"), c);
7eda085c
KZ
857}
858
89fd812f
DB
859static void print_welcome(void)
860{
861 printf(_("Welcome to fdisk (%s).\n\n"
862 "Changes will remain in memory only, until you decide to write them.\n"
863 "Be careful before using the write command.\n\n"), PACKAGE_STRING);
864
865 fflush(stdout);
866}
867
7737f698 868static void command_prompt(struct fdisk_context *cxt)
56c07b96 869{
4a96a62a 870 int c;
641a75ca 871 size_t n;
5dbff4c0 872
e3661531
KZ
873 assert(cxt);
874
ff5775bd 875 if (fdisk_is_disklabel(cxt, OSF)) {
56c07b96
FC
876 putchar('\n');
877 /* OSF label, and no DOS label */
878 printf(_("Detected an OSF/1 disklabel on %s, entering "
879 "disklabel mode.\n"),
823f0fd1 880 cxt->dev_path);
7737f698 881 bsd_command_prompt(cxt);
53b422ab 882
56c07b96 883 /* If we return we may want to make an empty DOS label? */
53b422ab 884 fdisk_context_switch_label(cxt, "dos");
56c07b96
FC
885 }
886
887 while (1) {
e3661531
KZ
888 assert(cxt->label);
889
a410f8df
KZ
890 c = process_fdisk_menu(cxt);
891 if (c <= 0)
892 continue;
893
894 /* well, process_fdisk_menu() returns commands that
895 * are not yet implemented by menu callbacks. Let's
896 * perform the commands here */
56c07b96
FC
897 switch (c) {
898 case 'a':
641a75ca
KZ
899 if (fdisk_is_disklabel(cxt, DOS) &&
900 fdisk_ask_partnum(cxt, &n, FALSE) == 0)
901 fdisk_partition_toggle_flag(cxt, n, DOS_FLAG_ACTIVE);
902
641a75ca
KZ
903 else if (fdisk_is_disklabel(cxt, SGI) &&
904 fdisk_ask_partnum(cxt, &n, FALSE) == 0)
905 fdisk_partition_toggle_flag(cxt, n, SGI_FLAG_BOOT);
56c07b96
FC
906 else
907 unknown_command(c);
908 break;
909 case 'b':
ff5775bd 910 if (fdisk_is_disklabel(cxt, SGI))
38b36353 911 sgi_set_bootfile(cxt);
ff5775bd 912 else if (fdisk_is_disklabel(cxt, DOS)) {
e09435aa
KZ
913
914 struct fdisk_context *bsd;
915
916 bsd = fdisk_new_nested_context(cxt, "bsd");
917 if (bsd)
918 bsd_command_prompt(bsd);
919 fdisk_free_context(bsd);
c482303e
FC
920 } else
921 unknown_command(c);
56c07b96
FC
922 break;
923 case 'c':
ff5775bd 924 if (fdisk_is_disklabel(cxt, DOS))
e53ced85 925 toggle_dos_compatibility_flag(cxt);
641a75ca
KZ
926
927 else if (fdisk_is_disklabel(cxt, SGI) &&
928 fdisk_ask_partnum(cxt, &n, FALSE) == 0)
929 fdisk_partition_toggle_flag(cxt, n, SGI_FLAG_SWAP);
56c07b96
FC
930 else
931 unknown_command(c);
932 break;
933 case 'd':
641a75ca
KZ
934 if (fdisk_ask_partnum(cxt, &n, FALSE) == 0)
935 delete_partition(cxt, n);
56c07b96 936 break;
3f731001
DB
937 case 'g':
938 fdisk_create_disklabel(cxt, "gpt");
939 break;
287ce9ed
KZ
940 case 'G':
941 fdisk_create_disklabel(cxt, "sgi");
942 break;
56c07b96 943 case 'i':
ff5775bd 944 if (fdisk_is_disklabel(cxt, SGI))
38b36353 945 create_sgiinfo(cxt);
56c07b96
FC
946 else
947 unknown_command(c);
099c7a94 948 break;
56c07b96 949 case 'l':
7b575fcc 950 list_partition_types(cxt);
56c07b96 951 break;
56c07b96 952 case 'n':
e53ced85 953 new_partition(cxt);
56c07b96
FC
954 break;
955 case 'o':
de3d6c93 956 fdisk_create_disklabel(cxt, "dos");
56c07b96
FC
957 break;
958 case 'p':
7737f698 959 list_table(cxt, 0);
56c07b96
FC
960 break;
961 case 'q':
823f0fd1 962 handle_quit(cxt);
56c07b96 963 case 's':
de3d6c93 964 fdisk_create_disklabel(cxt, "sun");
56c07b96
FC
965 break;
966 case 't':
02460b8a 967 change_partition_type(cxt);
56c07b96
FC
968 break;
969 case 'u':
ec10aa67 970 toggle_units(cxt);
56c07b96
FC
971 break;
972 case 'v':
e53ced85 973 verify(cxt);
56c07b96
FC
974 break;
975 case 'w':
d8de0955 976 write_table(cxt);
56c07b96
FC
977 break;
978 case 'x':
7737f698 979 expert_command_prompt(cxt);
56c07b96
FC
980 break;
981 default:
982 unknown_command(c);
56c07b96
FC
983 }
984 }
985}
5dbff4c0 986
50dec1eb 987static sector_t get_dev_blocks(char *dev)
6da365de
DB
988{
989 int fd;
50dec1eb 990 sector_t size;
6da365de
DB
991
992 if ((fd = open(dev, O_RDONLY)) < 0)
289dcc90 993 err(EXIT_FAILURE, _("cannot open %s"), dev);
7737f698
DB
994 if (blkdev_get_sectors(fd, &size) == -1) {
995 close(fd);
996 err(EXIT_FAILURE, _("BLKGETSIZE ioctl failed on %s"), dev);
997 }
6da365de
DB
998 close(fd);
999 return size/2;
1000}
1001
e1144767
DB
1002int main(int argc, char **argv)
1003{
6da365de 1004 int c, optl = 0, opts = 0;
e53ced85 1005 unsigned long sector_size = 0;
4e0e8253 1006 struct fdisk_context *cxt;
852ce62b 1007 struct fdisk_label *lb;
2b6fc908 1008
7eda085c
KZ
1009 setlocale(LC_ALL, "");
1010 bindtextdomain(PACKAGE, LOCALEDIR);
1011 textdomain(PACKAGE);
b2d28533 1012 atexit(close_stdout);
2b6fc908 1013
4e0e8253
KZ
1014 fdisk_init_debug(0);
1015 cxt = fdisk_new_context();
1016 if (!cxt)
1017 err(EXIT_FAILURE, _("failed to allocate libfdisk context"));
1018
416c43a9
KZ
1019 fdisk_context_set_ask(cxt, ask_callback, NULL);
1020
278f63c0 1021 while ((c = getopt(argc, argv, "b:c::C:hH:lsS:u::vV")) != -1) {
2b6fc908
KZ
1022 switch (c) {
1023 case 'b':
0e6f4a20
KZ
1024 /* Ugly: this sector size is really per device,
1025 so cannot be combined with multiple disks,
1026 and te same goes for the C/H/S options.
1027 */
00695059 1028 sector_size = strtou32_or_err(optarg, _("invalid sector size argument"));
5c36a0eb 1029 if (sector_size != 512 && sector_size != 1024 &&
8905beda 1030 sector_size != 2048 && sector_size != 4096)
7c1db6b4 1031 usage(stderr);
2b6fc908 1032 break;
0e6f4a20 1033 case 'C':
00695059 1034 user_cylinders = strtou32_or_err(optarg, _("invalid cylinders argument"));
0e6f4a20 1035 break;
78498b7b 1036 case 'c':
852ce62b 1037 if (optarg) {
2b0bc17b
KZ
1038 /* this setting is independent on the current
1039 * actively used label */
852ce62b
KZ
1040 lb = fdisk_context_get_label(cxt, "dos");
1041 if (!lb)
1042 err(EXIT_FAILURE, _("not found DOS label driver"));
1043 if (strcmp(optarg, "=dos") == 0)
1044 fdisk_dos_enable_compatible(lb, TRUE);
1045 else if (strcmp(optarg, "=nondos") == 0)
1046 fdisk_dos_enable_compatible(lb, FALSE);
1047 else
1048 usage(stderr);
1049 }
1050 /* use default if no optarg specified */
78498b7b 1051 break;
0e6f4a20 1052 case 'H':
00695059
KZ
1053 user_heads = strtou32_or_err(optarg, _("invalid heads argument"));
1054 if (user_heads > 256)
0e6f4a20
KZ
1055 user_heads = 0;
1056 break;
1057 case 'S':
00695059
KZ
1058 user_sectors = strtou32_or_err(optarg, _("invalid sectors argument"));
1059 if (user_sectors >= 64)
0e6f4a20
KZ
1060 user_sectors = 0;
1061 break;
2b6fc908
KZ
1062 case 'l':
1063 optl = 1;
1064 break;
1065 case 's':
1066 opts = 1;
1067 break;
1068 case 'u':
ec10aa67
KZ
1069 if (optarg && *optarg == '=')
1070 optarg++;
1071 if (fdisk_context_set_unit(cxt, optarg) != 0)
7c1db6b4 1072 usage(stderr);
2b6fc908 1073 break;
22853e4a 1074 case 'V':
2b6fc908 1075 case 'v':
a2482eb3
DB
1076 printf(UTIL_LINUX_VERSION);
1077 return EXIT_SUCCESS;
e1144767
DB
1078 case 'h':
1079 usage(stdout);
2b6fc908 1080 default:
7c1db6b4 1081 usage(stderr);
2b6fc908 1082 }
6dbe3af9 1083 }
2b6fc908 1084
f7b1f75e 1085
14e93ff3 1086 if (sector_size && argc-optind != 1)
7eda085c
KZ
1087 printf(_("Warning: the -b (set sector size) option should"
1088 " be used with one specified device\n"));
7eda085c 1089
2b6fc908 1090 if (optl) {
2b6fc908 1091 nowarn = 1;
2b6fc908
KZ
1092 if (argc > optind) {
1093 int k;
c129767e 1094 for (k = optind; k < argc; k++)
4e0e8253 1095 print_partition_table_from_option(cxt, argv[k], sector_size);
ea4824f1 1096 } else
4e0e8253 1097 print_all_partition_table_from_option(cxt, sector_size);
3e3de41a 1098 exit(EXIT_SUCCESS);
2b6fc908
KZ
1099 }
1100
1101 if (opts) {
6da365de
DB
1102 /* print partition size for one or more devices */
1103 int i, ndevs = argc - optind;
1104 if (ndevs <= 0)
7c1db6b4 1105 usage(stderr);
2b6fc908 1106
6da365de
DB
1107 for (i = optind; i < argc; i++) {
1108 if (ndevs == 1)
1109 printf("%llu\n", get_dev_blocks(argv[i]));
2b6fc908 1110 else
6da365de 1111 printf("%s: %llu\n", argv[i], get_dev_blocks(argv[i]));
6dbe3af9 1112 }
6da365de 1113 exit(EXIT_SUCCESS);
6dbe3af9 1114 }
6dbe3af9 1115
7d2ba340 1116 if (argc-optind != 1)
7c1db6b4 1117 usage(stderr);
7eda085c 1118
4e0e8253 1119 if (fdisk_context_assign_device(cxt, argv[optind], 0) != 0)
289dcc90 1120 err(EXIT_FAILURE, _("cannot open %s"), argv[optind]);
759d093f 1121
7d2ba340 1122 if (sector_size) /* passed -b option, override autodiscovery */
aa42788d 1123 fdisk_override_sector_size(cxt, sector_size);
759d093f 1124
9a5e29e9 1125 if (user_cylinders || user_heads || user_sectors)
aa42788d 1126 fdisk_override_geometry(cxt, user_cylinders,
9a5e29e9 1127 user_heads, user_sectors);
7d2ba340 1128
89fd812f 1129 print_welcome();
56c07b96 1130
a71601af
KZ
1131 if (!fdisk_dev_has_disklabel(cxt)) {
1132 fprintf(stderr,
1133 _("Device does not contain a recognized partition table\n"));
639f1d56 1134 fdisk_create_disklabel(cxt, NULL);
a71601af 1135 }
6dbe3af9 1136
7737f698 1137 command_prompt(cxt);
9777759a 1138
4e0e8253 1139 fdisk_free_context(cxt);
5c36a0eb 1140 return 0;
6dbe3af9 1141}