]> git.ipfire.org Git - thirdparty/util-linux.git/blame - fdisks/fdisk.c
libfdisk: (gpt) more robust PMBR partition size check
[thirdparty/util-linux.git] / fdisks / 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"
22853e4a 27#include "nls.h"
e66ac5d3 28#include "rpmatch.h"
810f986b 29#include "blkdev.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
48d7b13a 40#ifdef HAVE_LINUX_COMPILER_H
3f0ac587 41# include <linux/compiler.h>
48d7b13a
KZ
42#endif
43#ifdef HAVE_LINUX_BLKPG_H
3f0ac587 44# include <linux/blkpg.h>
7eda085c 45#endif
6dbe3af9 46
fcd9a2a4
KZ
47#include "fdisk.h"
48
3f0ac587
KZ
49static void __attribute__ ((__noreturn__)) usage(FILE *out)
50{
51 fputs(USAGE_HEADER, out);
52
53 fprintf(out,
54 _(" %1$s [options] <disk> change partition table\n"
55 " %1$s [options] -l <disk> list partition table(s)\n"
9564e46c 56 " %1$s -s <partition> give partition size(s) in blocks (deprecated)\n"),
3f0ac587
KZ
57 program_invocation_short_name);
58
59 fputs(USAGE_OPTIONS, out);
60 fputs(_(" -b <size> sector size (512, 1024, 2048 or 4096)\n"), out);
61 fputs(_(" -c[=<mode>] compatible mode: 'dos' or 'nondos' (default)\n"), out);
62 fputs(_(" -h print this help text\n"), out);
80a1712f
KZ
63 fputs(_(" -c[=<mode>] compatible mode: 'dos' or 'nondos' (default)\n"), out);
64 fputs(_(" -L[=<when>] colorize output (auto, always or never)\n"), out);
3f0ac587
KZ
65 fputs(_(" -u[=<unit>] display units: 'cylinders' or 'sectors' (default)\n"), out);
66 fputs(_(" -v print program version\n"), out);
67 fputs(_(" -C <number> specify the number of cylinders\n"), out);
68 fputs(_(" -H <number> specify the number of heads\n"), out);
69 fputs(_(" -S <number> specify the number of sectors per track\n"), out);
70
71 fprintf(out, USAGE_MAN_TAIL("fdisk(8)"));
72 exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
73}
74
7b575fcc 75void list_partition_types(struct fdisk_context *cxt)
6dbe3af9 76{
7b575fcc 77 struct fdisk_parttype *types;
76f17cf2 78 size_t ntypes = 0;
6dbe3af9 79
7b575fcc
KZ
80 if (!cxt || !cxt->label || !cxt->label->parttypes)
81 return;
2b6fc908 82
7b575fcc 83 types = cxt->label->parttypes;
76f17cf2 84 ntypes = cxt->label->nparttypes;
6dbe3af9 85
7b575fcc
KZ
86 if (types[0].typestr == NULL) {
87 /*
88 * Prints in 4 columns in format <hex> <name>
89 */
76f17cf2
KZ
90 size_t last[4], done = 0, next = 0, size;
91 int i;
b8d22034 92
76f17cf2
KZ
93 size = ntypes;
94 if (types[ntypes - 1].name == NULL)
95 size--;
7b575fcc
KZ
96
97 for (i = 3; i >= 0; i--)
98 last[3 - i] = done += (size + i - done) / (i + 1);
99 i = done = 0;
100
101 do {
102 #define NAME_WIDTH 15
103 char name[NAME_WIDTH * MB_LEN_MAX];
104 size_t width = NAME_WIDTH;
105 struct fdisk_parttype *t = &types[next];
106 size_t ret;
107
76f17cf2
KZ
108 if (t->name) {
109 printf("%c%2x ", i ? ' ' : '\n', t->type);
110 ret = mbsalign(_(t->name), name, sizeof(name),
111 &width, MBS_ALIGN_LEFT, 0);
7b575fcc 112
76f17cf2
KZ
113 if (ret == (size_t)-1 || ret >= sizeof(name))
114 printf("%-15.15s", _(t->name));
115 else
116 fputs(name, stdout);
117 }
7b575fcc
KZ
118
119 next = last[i++] + done;
120 if (i > 3 || next >= last[i]) {
121 i = 0;
122 next = ++done;
123 }
124 } while (done < last[0]);
125
126 } else {
127 /*
128 * Prints 1 column in format <idx> <name> <typestr>
129 */
130 struct fdisk_parttype *t;
76f17cf2 131 size_t i;
7b575fcc 132
76f17cf2
KZ
133 for (i = 0, t = types; t && i < ntypes; t++, i++) {
134 if (t->name)
135 printf("%3zu %-30s %s\n", i + 1,
136 t->name, t->typestr);
137 }
7b575fcc 138 }
6dbe3af9
KZ
139 putchar('\n');
140}
141
f02fecd1 142void toggle_dos_compatibility_flag(struct fdisk_context *cxt)
852ce62b
KZ
143{
144 struct fdisk_label *lb = fdisk_context_get_label(cxt, "dos");
145 int flag;
146
147 if (!lb)
148 return;
149
150 flag = !fdisk_dos_is_compatible(lb);
151
152 if (flag)
278f63c0 153 printf(_("DOS Compatibility flag is set (DEPRECATED!)\n"));
edd7b958 154 else
7eda085c 155 printf(_("DOS Compatibility flag is not set\n"));
edd7b958 156
852ce62b
KZ
157 fdisk_dos_enable_compatible(lb, flag);
158
159 if (fdisk_is_disklabel(cxt, DOS))
160 fdisk_reset_alignment(cxt);
6dbe3af9
KZ
161}
162
27ddd4f1 163void change_partition_type(struct fdisk_context *cxt)
e53ced85 164{
641a75ca 165 size_t i;
559d921e 166 struct fdisk_parttype *t, *org_t;
6dbe3af9 167
e3661531
KZ
168 assert(cxt);
169 assert(cxt->label);
170
641a75ca 171 if (fdisk_ask_partnum(cxt, &i, FALSE))
24f4bbff 172 return;
2b6fc908 173
010186f2
KZ
174 org_t = t = fdisk_get_partition_type(cxt, i);
175 if (!t)
641a75ca 176 printf(_("Partition %zu does not exist yet!\n"), i + 1);
010186f2 177
02460b8a 178 else do {
950edd1a 179 t = ask_partition_type(cxt);
559d921e
KZ
180 if (!t)
181 continue;
182
02460b8a 183 if (fdisk_set_partition_type(cxt, i, t) == 0) {
02460b8a
KZ
184 printf (_("Changed type of partition '%s' to '%s'\n"),
185 org_t ? org_t->name : _("Unknown"),
186 t ? t->name : _("Unknown"));
187 } else {
641a75ca 188 printf (_("Type of partition %zu is unchanged: %s\n"),
02460b8a
KZ
189 i + 1,
190 org_t ? org_t->name : _("Unknown"));
6dbe3af9 191 }
02460b8a
KZ
192 break;
193 } while (1);
559d921e
KZ
194
195 fdisk_free_parttype(t);
196 fdisk_free_parttype(org_t);
6dbe3af9
KZ
197}
198
89309968 199void list_disk_geometry(struct fdisk_context *cxt)
21fe3dde
KZ
200{
201 char *id = NULL;
9af73f84
KZ
202 uint64_t bytes = cxt->total_sectors * cxt->sector_size;
203 char *strsz = size_to_human_string(SIZE_SUFFIX_SPACE
204 | SIZE_SUFFIX_3LETTER, bytes);
205
a41309c2 206 fdisk_info(cxt, _("Disk %s: %s, %llu bytes, %llu sectors"),
9af73f84
KZ
207 cxt->dev_path, strsz, bytes, cxt->total_sectors);
208 free(strsz);
b1b1a7b7 209
0b52b94c 210 if (fdisk_require_geometry(cxt))
9af73f84
KZ
211 fdisk_info(cxt, _("Geometry: %d heads, %llu sectors/track, %llu cylinders"),
212 cxt->geom.heads, cxt->geom.sectors, cxt->geom.cylinders);
b1b1a7b7 213
9af73f84 214 fdisk_info(cxt, _("Units: %s of %d * %ld = %ld bytes"),
ec10aa67
KZ
215 fdisk_context_get_unit(cxt, PLURAL),
216 fdisk_context_get_units_per_sector(cxt),
217 cxt->sector_size,
218 fdisk_context_get_units_per_sector(cxt) * cxt->sector_size);
05dc9645 219
9af73f84 220 fdisk_info(cxt, _("Sector size (logical/physical): %lu bytes / %lu bytes"),
e53ced85 221 cxt->sector_size, cxt->phy_sector_size);
9af73f84 222 fdisk_info(cxt, _("I/O size (minimum/optimal): %lu bytes / %lu bytes"),
e53ced85
DB
223 cxt->min_io_size, cxt->io_size);
224 if (cxt->alignment_offset)
9af73f84
KZ
225 fdisk_info(cxt, _("Alignment offset: %lu bytes"),
226 cxt->alignment_offset);
b546d442 227 if (fdisk_dev_has_disklabel(cxt))
9af73f84 228 fdisk_info(cxt, _("Disk label type: %s"), cxt->label->name);
21fe3dde
KZ
229
230 if (fdisk_get_disklabel_id(cxt, &id) == 0 && id)
9af73f84 231 fdisk_info(cxt, _("Disk identifier: %s"), id);
5c36a0eb
KZ
232}
233
6dbe3af9
KZ
234
235#define MAX_PER_LINE 16
22853e4a 236static void
e53ced85 237print_buffer(struct fdisk_context *cxt, unsigned char pbuffer[]) {
e99da659 238 unsigned int i, l;
6dbe3af9 239
e53ced85 240 for (i = 0, l = 0; i < cxt->sector_size; i++, l++) {
6dbe3af9
KZ
241 if (l == 0)
242 printf("0x%03X:", i);
be97c5f3 243 printf(" %02X", pbuffer[i]);
6dbe3af9
KZ
244 if (l == MAX_PER_LINE - 1) {
245 printf("\n");
246 l = -1;
247 }
248 }
249 if (l > 0)
250 printf("\n");
251 printf("\n");
252}
253
89309968 254void print_raw(struct fdisk_context *cxt)
e53ced85 255{
e3661531
KZ
256 assert(cxt);
257 assert(cxt->label);
6dbe3af9 258
e53ced85 259 printf(_("Device: %s\n"), cxt->dev_path);
ff5775bd
DB
260 if (fdisk_is_disklabel(cxt, SUN) ||
261 fdisk_is_disklabel(cxt, SGI) ||
af0df606
KZ
262 fdisk_is_disklabel(cxt, GPT) ||
263 fdisk_is_disklabel(cxt, DOS))
67987b47 264 print_buffer(cxt, cxt->firstsector);
e3661531 265
af0df606 266 /* TODO: print also EBR (extended partition) buffer */
6dbe3af9
KZ
267}
268
3b622ddd
DB
269static int is_ide_cdrom_or_tape(char *device)
270{
271 int fd, ret;
2b6fc908 272
1c6b3378 273 if ((fd = open(device, O_RDONLY)) < 0)
e8f26419 274 return 0;
3b622ddd 275 ret = blkdev_is_cdrom(fd);
2b6fc908 276
3b622ddd
DB
277 close(fd);
278 return ret;
2b6fc908
KZ
279}
280
6aa2ed3b 281static void print_device_pt(struct fdisk_context *cxt, char *device)
e27b42d5 282{
4e0e8253 283 if (fdisk_context_assign_device(cxt, device, 1) != 0) /* read-only */
289dcc90 284 err(EXIT_FAILURE, _("cannot open %s"), device);
823f0fd1 285
5e860870
KZ
286 list_disk_geometry(cxt);
287
b4fb2a61 288 if (fdisk_dev_has_disklabel(cxt))
5e860870 289 fdisk_list_disklabel(cxt);
6dbe3af9
KZ
290}
291
6aa2ed3b 292static void print_all_devices_pt(struct fdisk_context *cxt)
ea4824f1 293{
6aa2ed3b
KZ
294 FILE *f;
295 char line[128 + 1];
296
297 f = fopen(_PATH_PROC_PARTITIONS, "r");
298 if (!f) {
299 warn(_("cannot open %s"), _PATH_PROC_PARTITIONS);
eb63b9b8
KZ
300 return;
301 }
302
6aa2ed3b
KZ
303 while (fgets(line, sizeof(line), f)) {
304 char ptname[128 + 1], devname[256];
305
306 if (sscanf(line, " %*d %*d %*d %128[^\n ]", ptname) != 4)
eb63b9b8 307 continue;
6aa2ed3b 308
c07ebfa1 309 snprintf(devname, sizeof(devname), "/dev/%s", ptname);
6bec8710
KZ
310 if (is_whole_disk(devname)) {
311 char *cn = canonicalize_path(devname);
312 if (cn) {
0c48d371 313 if (!is_ide_cdrom_or_tape(cn))
6aa2ed3b 314 print_device_pt(cxt, cn);
6bec8710
KZ
315 free(cn);
316 }
317 }
eb63b9b8 318 }
6aa2ed3b 319 fclose(f);
eb63b9b8
KZ
320}
321
50dec1eb 322static sector_t get_dev_blocks(char *dev)
6da365de
DB
323{
324 int fd;
50dec1eb 325 sector_t size;
6da365de
DB
326
327 if ((fd = open(dev, O_RDONLY)) < 0)
289dcc90 328 err(EXIT_FAILURE, _("cannot open %s"), dev);
7737f698
DB
329 if (blkdev_get_sectors(fd, &size) == -1) {
330 close(fd);
331 err(EXIT_FAILURE, _("BLKGETSIZE ioctl failed on %s"), dev);
332 }
6da365de
DB
333 close(fd);
334 return size/2;
335}
336
5b72b3dd
KZ
337enum {
338 ACT_FDISK = 0, /* default */
339 ACT_LIST,
340 ACT_SHOWSIZE
341};
342
e1144767
DB
343int main(int argc, char **argv)
344{
5b72b3dd 345 int i, c, act = ACT_FDISK;
80a1712f 346 int colormode = UL_COLORMODE_AUTO;
4e0e8253 347 struct fdisk_context *cxt;
2b6fc908 348
7eda085c
KZ
349 setlocale(LC_ALL, "");
350 bindtextdomain(PACKAGE, LOCALEDIR);
351 textdomain(PACKAGE);
b2d28533 352 atexit(close_stdout);
2b6fc908 353
4e0e8253
KZ
354 fdisk_init_debug(0);
355 cxt = fdisk_new_context();
356 if (!cxt)
357 err(EXIT_FAILURE, _("failed to allocate libfdisk context"));
358
416c43a9
KZ
359 fdisk_context_set_ask(cxt, ask_callback, NULL);
360
80a1712f 361 while ((c = getopt(argc, argv, "b:c::C:hH:lL::sS:u::vV")) != -1) {
2b6fc908
KZ
362 switch (c) {
363 case 'b':
6bcd192c
KZ
364 {
365 size_t sz = strtou32_or_err(optarg,
366 _("invalid sector size argument"));
367 if (sz != 512 && sz != 1024 && sz != 2048 && sz != 4096)
7c1db6b4 368 usage(stderr);
6bcd192c 369 fdisk_save_user_sector_size(cxt, sz, sz);
2b6fc908 370 break;
6bcd192c 371 }
0e6f4a20 372 case 'C':
1653f0b0
KZ
373 fdisk_save_user_geometry(cxt,
374 strtou32_or_err(optarg,
375 _("invalid cylinders argument")),
376 0, 0);
0e6f4a20 377 break;
78498b7b 378 case 'c':
852ce62b 379 if (optarg) {
2b0bc17b
KZ
380 /* this setting is independent on the current
381 * actively used label */
5b72b3dd 382 struct fdisk_label *lb = fdisk_context_get_label(cxt, "dos");
852ce62b
KZ
383 if (!lb)
384 err(EXIT_FAILURE, _("not found DOS label driver"));
385 if (strcmp(optarg, "=dos") == 0)
386 fdisk_dos_enable_compatible(lb, TRUE);
387 else if (strcmp(optarg, "=nondos") == 0)
388 fdisk_dos_enable_compatible(lb, FALSE);
389 else
390 usage(stderr);
391 }
392 /* use default if no optarg specified */
78498b7b 393 break;
0e6f4a20 394 case 'H':
1653f0b0
KZ
395 fdisk_save_user_geometry(cxt, 0,
396 strtou32_or_err(optarg,
397 _("invalid heads argument")),
398 0);
0e6f4a20
KZ
399 break;
400 case 'S':
1653f0b0
KZ
401 fdisk_save_user_geometry(cxt, 0, 0,
402 strtou32_or_err(optarg,
403 _("invalid sectors argument")));
0e6f4a20 404 break;
2b6fc908 405 case 'l':
5b72b3dd 406 act = ACT_LIST;
2b6fc908 407 break;
80a1712f
KZ
408 case 'L':
409 if (optarg)
410 colormode = colormode_or_err(optarg,
411 _("unsupported color mode"));
412 break;
2b6fc908 413 case 's':
5b72b3dd 414 act = ACT_SHOWSIZE;
2b6fc908
KZ
415 break;
416 case 'u':
ec10aa67
KZ
417 if (optarg && *optarg == '=')
418 optarg++;
419 if (fdisk_context_set_unit(cxt, optarg) != 0)
7c1db6b4 420 usage(stderr);
2b6fc908 421 break;
22853e4a 422 case 'V':
2b6fc908 423 case 'v':
a2482eb3
DB
424 printf(UTIL_LINUX_VERSION);
425 return EXIT_SUCCESS;
e1144767
DB
426 case 'h':
427 usage(stdout);
2b6fc908 428 default:
7c1db6b4 429 usage(stderr);
2b6fc908 430 }
6dbe3af9 431 }
2b6fc908 432
6bcd192c
KZ
433 if (argc-optind != 1 && fdisk_has_user_device_properties(cxt))
434 warnx(_("The device properties (sector size and geometry) should"
435 " be used with one specified device only."));
7eda085c 436
5b72b3dd
KZ
437 switch (act) {
438 case ACT_LIST:
c10937dc 439 fdisk_context_enable_listonly(cxt, 1);
2b6fc908
KZ
440 if (argc > optind) {
441 int k;
c129767e 442 for (k = optind; k < argc; k++)
6aa2ed3b 443 print_device_pt(cxt, argv[k]);
ea4824f1 444 } else
6aa2ed3b 445 print_all_devices_pt(cxt);
5b72b3dd 446 break;
2b6fc908 447
5b72b3dd 448 case ACT_SHOWSIZE:
9564e46c 449 /* deprecated */
5b72b3dd 450 if (argc - optind <= 0)
7c1db6b4 451 usage(stderr);
2b6fc908 452
6da365de 453 for (i = optind; i < argc; i++) {
5b72b3dd 454 if (argc - optind == 1)
6da365de 455 printf("%llu\n", get_dev_blocks(argv[i]));
2b6fc908 456 else
6da365de 457 printf("%s: %llu\n", argv[i], get_dev_blocks(argv[i]));
6dbe3af9 458 }
5b72b3dd 459 break;
6dbe3af9 460
5b72b3dd
KZ
461 case ACT_FDISK:
462 if (argc-optind != 1)
463 usage(stderr);
7eda085c 464
80a1712f
KZ
465 colors_init(colormode);
466
5b72b3dd
KZ
467 if (fdisk_context_assign_device(cxt, argv[optind], 0) != 0)
468 err(EXIT_FAILURE, _("cannot open %s"), argv[optind]);
759d093f 469
5b72b3dd 470 /* Here starts interactive mode, use fdisk_{warn,info,..} functions */
80a1712f
KZ
471 color_enable(UL_COLOR_GREEN);
472 fdisk_info(cxt, _("Welcome to fdisk (%s).\n"), PACKAGE_STRING);
473 color_disable();
474 fdisk_info(cxt, _("Changes will remain in memory only, until you decide to write them.\n"
475 "Be careful before using the write command.\n"));
5b72b3dd 476 fflush(stdout);
56c07b96 477
5b72b3dd
KZ
478 if (!fdisk_dev_has_disklabel(cxt)) {
479 fdisk_warnx(cxt, _("Device does not contain a recognized partition table\n"));
480 fdisk_create_disklabel(cxt, NULL);
481 }
6dbe3af9 482
5b72b3dd
KZ
483 while (1)
484 process_fdisk_menu(&cxt);
485 }
9777759a 486
4e0e8253 487 fdisk_free_context(cxt);
5b72b3dd 488 return EXIT_SUCCESS;
6dbe3af9 489}