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