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