]>
Commit | Line | Data |
---|---|---|
3f0ac587 | 1 | /* |
9e95aa12 KZ |
2 | * SPDX-License-Identifier: GPL-1.0-or-later |
3 | * | |
4 | * This program is free software; you can redistribute it and/or modify | |
5 | * it under the terms of the GNU General Public License as published by | |
6 | * the Free Software Foundation; either version 1 of the License, or | |
7 | * (at your option) any later version. | |
8 | * | |
6dbe3af9 | 9 | * Copyright (C) 1992 A. V. Le Blanc (LeBlanc@mcc.ac.uk) |
38b36353 | 10 | * Copyright (C) 2012 Davidlohr Bueso <dave@gnu.org> |
6dbe3af9 | 11 | * |
3f0ac587 | 12 | * Copyright (C) 2007-2013 Karel Zak <kzak@redhat.com> |
6dbe3af9 | 13 | */ |
6dbe3af9 KZ |
14 | #include <unistd.h> |
15 | #include <stdio.h> | |
16 | #include <stdlib.h> | |
17 | #include <string.h> | |
18 | #include <fcntl.h> | |
19 | #include <ctype.h> | |
6dbe3af9 | 20 | #include <errno.h> |
2b6fc908 | 21 | #include <getopt.h> |
2b6fc908 | 22 | #include <sys/stat.h> |
f26873dc | 23 | #include <sys/time.h> |
bb6aacfe | 24 | #include <time.h> |
ee5355e0 | 25 | #include <limits.h> |
6c8c429d | 26 | #include <signal.h> |
c1154128 | 27 | #include <poll.h> |
d44115f3 | 28 | #include <libsmartcols.h> |
740c36f6 | 29 | #ifdef HAVE_LIBREADLINE |
57ebfde2 | 30 | # define _FUNCTION_DEF |
740c36f6 KZ |
31 | # include <readline/readline.h> |
32 | #endif | |
6dbe3af9 | 33 | |
3f0ac587 | 34 | #include "c.h" |
52b38677 | 35 | #include "xalloc.h" |
e916600f | 36 | #include "all-io.h" |
22853e4a | 37 | #include "nls.h" |
e66ac5d3 | 38 | #include "rpmatch.h" |
810f986b | 39 | #include "blkdev.h" |
b8d22034 | 40 | #include "mbsalign.h" |
6bec8710 KZ |
41 | #include "pathnames.h" |
42 | #include "canonicalize.h" | |
20aa2570 | 43 | #include "strutils.h" |
b2d28533 | 44 | #include "closestream.h" |
8d2f4498 | 45 | #include "pager.h" |
5c36a0eb | 46 | |
fdb006e8 KZ |
47 | #include "fdisk.h" |
48 | ||
b4bfbadd | 49 | #include "pt-sun.h" /* to toggle flags */ |
5c36a0eb | 50 | |
48d7b13a | 51 | #ifdef HAVE_LINUX_COMPILER_H |
3f0ac587 | 52 | # include <linux/compiler.h> |
48d7b13a KZ |
53 | #endif |
54 | #ifdef HAVE_LINUX_BLKPG_H | |
3f0ac587 | 55 | # include <linux/blkpg.h> |
7eda085c | 56 | #endif |
6dbe3af9 | 57 | |
a4c0dce8 KZ |
58 | #ifdef __linux__ |
59 | # ifdef HAVE_LINUX_FS_H | |
60 | # include <linux/fs.h> | |
61 | # endif | |
62 | # ifndef BLKDISCARD | |
63 | # define BLKDISCARD _IO(0x12,119) | |
64 | # endif | |
65 | #endif | |
66 | ||
ba465623 | 67 | int pwipemode = WIPEMODE_AUTO; |
fadd8e08 | 68 | int device_is_used; |
c1154128 | 69 | int is_interactive; |
fadd8e08 KZ |
70 | struct fdisk_table *original_layout; |
71 | ||
5635d195 | 72 | static int wipemode = WIPEMODE_AUTO; |
ba465623 | 73 | |
e6d0c4c1 KZ |
74 | /* |
75 | * fdisk debug stuff (see fdisk.h and include/debug.h) | |
76 | */ | |
77 | UL_DEBUG_DEFINE_MASK(fdisk); | |
819d9a29 | 78 | UL_DEBUG_DEFINE_MASKNAMES(fdisk) = UL_DEBUG_EMPTY_MASKNAMES; |
d6b3ba41 | 79 | |
e6d0c4c1 KZ |
80 | static void fdiskprog_init_debug(void) |
81 | { | |
a15dca2f | 82 | __UL_INIT_DEBUG_FROM_ENV(fdisk, FDISKPROG_DEBUG_, 0, FDISK_DEBUG); |
e6d0c4c1 | 83 | } |
d6b3ba41 | 84 | |
c1154128 | 85 | static void reply_sighandler(int sig __attribute__((unused))) |
6c8c429d | 86 | { |
c1154128 | 87 | DBG(ASK, ul_debug("got signal")); |
6c8c429d VD |
88 | } |
89 | ||
c1154128 | 90 | static int reply_running; |
740c36f6 | 91 | |
c1154128 KZ |
92 | #ifdef HAVE_LIBREADLINE |
93 | static char *reply_line; | |
740c36f6 | 94 | |
c1154128 | 95 | static void reply_linehandler(char *line) |
55cf3716 | 96 | { |
c1154128 KZ |
97 | reply_line = line; |
98 | reply_running = 0; | |
99 | rl_callback_handler_remove(); /* avoid duplicate prompt */ | |
55cf3716 | 100 | } |
c1154128 | 101 | #endif |
55cf3716 | 102 | |
c1154128 | 103 | int get_user_reply(const char *prompt, char *buf, size_t bufsz) |
d6b3ba41 | 104 | { |
c1154128 KZ |
105 | struct sigaction oldact, act = { |
106 | .sa_handler = reply_sighandler | |
107 | }; | |
108 | struct pollfd fds[] = { | |
109 | { .fd = fileno(stdin), .events = POLLIN } | |
110 | }; | |
d6b3ba41 | 111 | size_t sz; |
6c8c429d | 112 | int ret = 0; |
6c8c429d | 113 | |
36787f7a | 114 | DBG(ASK, ul_debug("asking for user reply %s", is_interactive ? "[interactive]" : "")); |
6c8c429d | 115 | |
c1154128 | 116 | sigemptyset(&act.sa_mask); |
6c8c429d | 117 | sigaction(SIGINT, &act, &oldact); |
d6b3ba41 | 118 | |
c1154128 KZ |
119 | #ifdef HAVE_LIBREADLINE |
120 | if (is_interactive) | |
121 | rl_callback_handler_install(prompt, reply_linehandler); | |
122 | #endif | |
40af0db4 | 123 | errno = 0; |
c1154128 | 124 | reply_running = 1; |
d6b3ba41 | 125 | do { |
c1154128 | 126 | int rc; |
6c8c429d | 127 | |
c1154128 KZ |
128 | *buf = '\0'; |
129 | #ifdef HAVE_LIBREADLINE | |
130 | if (!is_interactive) | |
131 | #endif | |
132 | { | |
133 | fputs(prompt, stdout); | |
134 | fflush(stdout); | |
6c8c429d VD |
135 | } |
136 | ||
c1154128 KZ |
137 | rc = poll(fds, 1, -1); |
138 | if (rc == -1 && errno == EINTR) { /* interrupted by signal */ | |
139 | DBG(ASK, ul_debug("cancel by CTRL+C")); | |
140 | ret = -ECANCELED; | |
141 | goto done; | |
142 | } | |
143 | if (rc == -1 && errno != EAGAIN) { /* error */ | |
144 | ret = -errno; | |
145 | goto done; | |
146 | } | |
147 | #ifdef HAVE_LIBREADLINE | |
148 | if (is_interactive) { | |
149 | /* read input and copy to buf[] */ | |
150 | rl_callback_read_char(); | |
151 | if (!reply_running && reply_line) { | |
152 | sz = strlen(reply_line); | |
30636704 | 153 | if (sz == 0) |
1d775aa2 | 154 | buf[sz++] = '\n'; |
30636704 VD |
155 | else |
156 | memcpy(buf, reply_line, min(sz, bufsz)); | |
1d775aa2 | 157 | buf[min(sz, bufsz - 1)] = '\0'; |
c1154128 KZ |
158 | free(reply_line); |
159 | reply_line = NULL; | |
55cf3716 | 160 | } |
55cf3716 | 161 | } else |
c1154128 KZ |
162 | #endif |
163 | { | |
164 | if (!fgets(buf, bufsz, stdin)) | |
165 | *buf = '\0'; | |
55cf3716 | 166 | break; |
c1154128 KZ |
167 | } |
168 | } while (reply_running); | |
169 | ||
170 | if (!*buf) { | |
171 | DBG(ASK, ul_debug("cancel by CTRL+D")); | |
172 | ret = -ECANCELED; | |
40af0db4 | 173 | clearerr(stdin); |
c1154128 KZ |
174 | goto done; |
175 | } | |
d6b3ba41 | 176 | |
c1154128 KZ |
177 | /* |
178 | * cleanup the reply | |
179 | */ | |
6c183c28 | 180 | sz = ltrim_whitespace((unsigned char *) buf); |
d6b3ba41 KZ |
181 | if (sz && *(buf + sz - 1) == '\n') |
182 | *(buf + sz - 1) = '\0'; | |
183 | ||
c1154128 KZ |
184 | done: |
185 | #ifdef HAVE_LIBREADLINE | |
186 | if (is_interactive) | |
187 | rl_callback_handler_remove(); | |
188 | #endif | |
6c8c429d | 189 | sigaction(SIGINT, &oldact, NULL); |
40af0db4 | 190 | DBG(ASK, ul_debug("user's reply: >>>%s<<< [rc=%d]", buf, ret)); |
6c8c429d | 191 | return ret; |
d6b3ba41 KZ |
192 | } |
193 | ||
194 | static int ask_menu(struct fdisk_context *cxt, struct fdisk_ask *ask, | |
195 | char *buf, size_t bufsz) | |
196 | ||
197 | { | |
198 | const char *q = fdisk_ask_get_query(ask); | |
199 | int dft = fdisk_ask_menu_get_default(ask); | |
200 | ||
201 | if (q) { | |
202 | fputs(q, stdout); /* print header */ | |
203 | fputc('\n', stdout); | |
204 | } | |
205 | ||
206 | do { | |
207 | char prompt[128]; | |
68ddb136 | 208 | int key, c, rc; |
d6b3ba41 KZ |
209 | const char *name, *desc; |
210 | size_t i = 0; | |
211 | ||
212 | /* print menu items */ | |
a4c0dce8 KZ |
213 | while (fdisk_ask_menu_get_item(ask, i++, &key, &name, &desc) == 0) { |
214 | if (desc) | |
215 | fprintf(stdout, " %c %s (%s)\n", key, name, desc); | |
216 | else | |
217 | fprintf(stdout, " %c %s\n", key, name); | |
218 | } | |
d6b3ba41 KZ |
219 | |
220 | /* ask for key */ | |
221 | snprintf(prompt, sizeof(prompt), _("Select (default %c): "), dft); | |
c1154128 | 222 | rc = get_user_reply(prompt, buf, bufsz); |
68ddb136 KZ |
223 | if (rc) |
224 | return rc; | |
d6b3ba41 KZ |
225 | if (!*buf) { |
226 | fdisk_info(cxt, _("Using default response %c."), dft); | |
227 | c = dft; | |
228 | } else | |
229 | c = tolower(buf[0]); | |
230 | ||
231 | /* check result */ | |
232 | i = 0; | |
233 | while (fdisk_ask_menu_get_item(ask, i++, &key, NULL, NULL) == 0) { | |
234 | if (c == key) { | |
235 | fdisk_ask_menu_set_result(ask, c); | |
236 | return 0; /* success */ | |
237 | } | |
238 | } | |
239 | fdisk_warnx(cxt, _("Value out of range.")); | |
240 | } while (1); | |
241 | ||
242 | return -EINVAL; | |
243 | } | |
244 | ||
245 | ||
246 | #define tochar(num) ((int) ('a' + num - 1)) | |
247 | static int ask_number(struct fdisk_context *cxt, | |
248 | struct fdisk_ask *ask, | |
249 | char *buf, size_t bufsz) | |
250 | { | |
251 | char prompt[128] = { '\0' }; | |
252 | const char *q = fdisk_ask_get_query(ask); | |
253 | const char *range = fdisk_ask_number_get_range(ask); | |
254 | ||
255 | uint64_t dflt = fdisk_ask_number_get_default(ask), | |
256 | low = fdisk_ask_number_get_low(ask), | |
257 | high = fdisk_ask_number_get_high(ask); | |
258 | int inchar = fdisk_ask_number_inchars(ask); | |
259 | ||
260 | assert(q); | |
261 | ||
88141067 | 262 | DBG(ASK, ul_debug("asking for number " |
fdbd7bb9 | 263 | "['%s', <%"PRIu64",%"PRIu64">, default=%"PRIu64", range: %s]", |
d6b3ba41 KZ |
264 | q, low, high, dflt, range)); |
265 | ||
266 | if (range && dflt >= low && dflt <= high) { | |
267 | if (inchar) | |
268 | snprintf(prompt, sizeof(prompt), _("%s (%s, default %c): "), | |
269 | q, range, tochar(dflt)); | |
270 | else | |
fdbd7bb9 | 271 | snprintf(prompt, sizeof(prompt), _("%s (%s, default %"PRIu64"): "), |
d6b3ba41 KZ |
272 | q, range, dflt); |
273 | ||
274 | } else if (dflt >= low && dflt <= high) { | |
275 | if (inchar) | |
276 | snprintf(prompt, sizeof(prompt), _("%s (%c-%c, default %c): "), | |
277 | q, tochar(low), tochar(high), tochar(dflt)); | |
278 | else | |
fdbd7bb9 RM |
279 | snprintf(prompt, sizeof(prompt), |
280 | _("%s (%"PRIu64"-%"PRIu64", default %"PRIu64"): "), | |
d6b3ba41 KZ |
281 | q, low, high, dflt); |
282 | } else if (inchar) | |
283 | snprintf(prompt, sizeof(prompt), _("%s (%c-%c): "), | |
284 | q, tochar(low), tochar(high)); | |
285 | else | |
fdbd7bb9 | 286 | snprintf(prompt, sizeof(prompt), _("%s (%"PRIu64"-%"PRIu64"): "), |
d6b3ba41 KZ |
287 | q, low, high); |
288 | ||
289 | do { | |
c1154128 | 290 | int rc = get_user_reply(prompt, buf, bufsz); |
5653c982 | 291 | uint64_t num = 0; |
d6b3ba41 KZ |
292 | |
293 | if (rc) | |
294 | return rc; | |
295 | if (!*buf && dflt >= low && dflt <= high) | |
296 | return fdisk_ask_number_set_result(ask, dflt); | |
297 | ||
298 | if (isdigit_string(buf)) { | |
299 | char *end; | |
300 | ||
301 | errno = 0; | |
302 | num = strtoumax(buf, &end, 10); | |
303 | if (errno || buf == end || (end && *end)) | |
304 | continue; | |
305 | } else if (inchar && isalpha(*buf)) { | |
306 | num = tolower(*buf) - 'a' + 1; | |
307 | } else | |
308 | rc = -EINVAL; | |
309 | ||
310 | if (rc == 0 && num >= low && num <= high) | |
311 | return fdisk_ask_number_set_result(ask, num); | |
312 | ||
313 | fdisk_warnx(cxt, _("Value out of range.")); | |
314 | } while (1); | |
315 | ||
316 | return -1; | |
317 | } | |
318 | ||
319 | static int ask_offset(struct fdisk_context *cxt, | |
320 | struct fdisk_ask *ask, | |
321 | char *buf, size_t bufsz) | |
322 | { | |
323 | char prompt[128] = { '\0' }; | |
324 | const char *q = fdisk_ask_get_query(ask); | |
325 | const char *range = fdisk_ask_number_get_range(ask); | |
326 | ||
327 | uint64_t dflt = fdisk_ask_number_get_default(ask), | |
328 | low = fdisk_ask_number_get_low(ask), | |
329 | high = fdisk_ask_number_get_high(ask), | |
330 | base = fdisk_ask_number_get_base(ask); | |
331 | ||
332 | assert(q); | |
333 | ||
fdbd7bb9 | 334 | DBG(ASK, ul_debug("asking for offset ['%s', <%"PRIu64",%"PRIu64">, base=%"PRIu64", default=%"PRIu64", range: %s]", |
d6b3ba41 KZ |
335 | q, low, high, base, dflt, range)); |
336 | ||
337 | if (range && dflt >= low && dflt <= high) | |
fdbd7bb9 RM |
338 | snprintf(prompt, sizeof(prompt), _("%s (%s, default %"PRIu64"): "), |
339 | q, range, dflt); | |
d6b3ba41 | 340 | else if (dflt >= low && dflt <= high) |
fdbd7bb9 RM |
341 | snprintf(prompt, sizeof(prompt), |
342 | _("%s (%"PRIu64"-%"PRIu64", default %"PRIu64"): "), | |
343 | q, low, high, dflt); | |
d6b3ba41 | 344 | else |
fdbd7bb9 RM |
345 | snprintf(prompt, sizeof(prompt), _("%s (%"PRIu64"-%"PRIu64"): "), |
346 | q, low, high); | |
d6b3ba41 KZ |
347 | |
348 | do { | |
262c94c2 | 349 | uintmax_t num = 0; |
d6b3ba41 KZ |
350 | char sig = 0, *p; |
351 | int pwr = 0; | |
352 | ||
c1154128 | 353 | int rc = get_user_reply(prompt, buf, bufsz); |
d6b3ba41 KZ |
354 | if (rc) |
355 | return rc; | |
356 | if (!*buf && dflt >= low && dflt <= high) | |
357 | return fdisk_ask_number_set_result(ask, dflt); | |
358 | ||
359 | p = buf; | |
360 | if (*p == '+' || *p == '-') { | |
361 | sig = *buf; | |
362 | p++; | |
363 | } | |
364 | ||
365 | rc = parse_size(p, &num, &pwr); | |
366 | if (rc) | |
367 | continue; | |
88141067 | 368 | DBG(ASK, ul_debug("parsed size: %ju", num)); |
d6b3ba41 KZ |
369 | if (sig && pwr) { |
370 | /* +{size}{K,M,...} specified, the "num" is in bytes */ | |
371 | uint64_t unit = fdisk_ask_number_get_unit(ask); | |
372 | num += unit/2; /* round */ | |
373 | num /= unit; | |
374 | } | |
375 | if (sig == '+') | |
376 | num += base; | |
757cefbb AG |
377 | else if (sig == '-' && fdisk_ask_number_is_wrap_negative(ask)) |
378 | num = high - num; | |
d6b3ba41 KZ |
379 | else if (sig == '-') |
380 | num = base - num; | |
381 | ||
88141067 | 382 | DBG(ASK, ul_debug("final offset: %ju [sig: %c, power: %d, %s]", |
d6b3ba41 KZ |
383 | num, sig, pwr, |
384 | sig ? "relative" : "absolute")); | |
385 | if (num >= low && num <= high) { | |
8c73e509 | 386 | if (sig && pwr) |
d6b3ba41 | 387 | fdisk_ask_number_set_relative(ask, 1); |
262c94c2 | 388 | return fdisk_ask_number_set_result(ask, (uint64_t)num); |
d6b3ba41 KZ |
389 | } |
390 | fdisk_warnx(cxt, _("Value out of range.")); | |
391 | } while (1); | |
392 | ||
393 | return -1; | |
394 | } | |
395 | ||
396 | static unsigned int info_count; | |
397 | ||
412791a9 | 398 | static void fputs_info(struct fdisk_ask *ask, FILE *out) |
d6b3ba41 KZ |
399 | { |
400 | const char *msg; | |
d6b3ba41 KZ |
401 | assert(ask); |
402 | ||
403 | msg = fdisk_ask_print_get_mesg(ask); | |
d6b3ba41 KZ |
404 | if (!msg) |
405 | return; | |
406 | if (info_count == 1) | |
407 | fputc('\n', out); | |
412791a9 KZ |
408 | |
409 | fputs(msg, out); | |
d6b3ba41 KZ |
410 | fputc('\n', out); |
411 | } | |
412 | ||
413 | int ask_callback(struct fdisk_context *cxt, struct fdisk_ask *ask, | |
414 | void *data __attribute__((__unused__))) | |
415 | { | |
416 | int rc = 0; | |
89770db4 | 417 | char buf[BUFSIZ] = { '\0' }; |
d6b3ba41 KZ |
418 | |
419 | assert(cxt); | |
420 | assert(ask); | |
421 | ||
422 | if (fdisk_ask_get_type(ask) != FDISK_ASKTYPE_INFO) | |
423 | info_count = 0; | |
424 | ||
425 | switch(fdisk_ask_get_type(ask)) { | |
426 | case FDISK_ASKTYPE_MENU: | |
427 | return ask_menu(cxt, ask, buf, sizeof(buf)); | |
428 | case FDISK_ASKTYPE_NUMBER: | |
429 | return ask_number(cxt, ask, buf, sizeof(buf)); | |
430 | case FDISK_ASKTYPE_OFFSET: | |
431 | return ask_offset(cxt, ask, buf, sizeof(buf)); | |
432 | case FDISK_ASKTYPE_INFO: | |
152788aa KZ |
433 | if (!fdisk_is_listonly(cxt)) |
434 | info_count++; | |
412791a9 | 435 | fputs_info(ask, stdout); |
d6b3ba41 KZ |
436 | break; |
437 | case FDISK_ASKTYPE_WARNX: | |
95aae4fc | 438 | fflush(stdout); |
496c979a | 439 | color_scheme_fenable("warn", UL_COLOR_RED, stderr); |
d6b3ba41 KZ |
440 | fputs(fdisk_ask_print_get_mesg(ask), stderr); |
441 | color_fdisable(stderr); | |
442 | fputc('\n', stderr); | |
443 | break; | |
444 | case FDISK_ASKTYPE_WARN: | |
95aae4fc | 445 | fflush(stdout); |
496c979a | 446 | color_scheme_fenable("warn", UL_COLOR_RED, stderr); |
d6b3ba41 KZ |
447 | fputs(fdisk_ask_print_get_mesg(ask), stderr); |
448 | errno = fdisk_ask_print_get_errno(ask); | |
449 | fprintf(stderr, ": %m\n"); | |
450 | color_fdisable(stderr); | |
451 | break; | |
452 | case FDISK_ASKTYPE_YESNO: | |
453 | fputc('\n', stdout); | |
2d129032 KZ |
454 | do { |
455 | int x; | |
456 | fputs(fdisk_ask_get_query(ask), stdout); | |
c1154128 | 457 | rc = get_user_reply(_(" [Y]es/[N]o: "), buf, sizeof(buf)); |
2d129032 KZ |
458 | if (rc) |
459 | break; | |
460 | x = rpmatch(buf); | |
cd2a6f1c | 461 | if (x == RPMATCH_YES || x == RPMATCH_NO) { |
2d129032 KZ |
462 | fdisk_ask_yesno_set_result(ask, x); |
463 | break; | |
464 | } | |
465 | } while(1); | |
88141067 | 466 | DBG(ASK, ul_debug("yes-no ask: reply '%s' [rc=%d]", buf, rc)); |
d6b3ba41 KZ |
467 | break; |
468 | case FDISK_ASKTYPE_STRING: | |
469 | { | |
470 | char prmt[BUFSIZ]; | |
471 | snprintf(prmt, sizeof(prmt), "%s: ", fdisk_ask_get_query(ask)); | |
472 | fputc('\n', stdout); | |
c1154128 | 473 | rc = get_user_reply(prmt, buf, sizeof(buf)); |
d6b3ba41 KZ |
474 | if (rc == 0) |
475 | fdisk_ask_string_set_result(ask, xstrdup(buf)); | |
88141067 | 476 | DBG(ASK, ul_debug("string ask: reply '%s' [rc=%d]", buf, rc)); |
d6b3ba41 KZ |
477 | break; |
478 | } | |
479 | default: | |
480 | warnx(_("internal error: unsupported dialog type %d"), fdisk_ask_get_type(ask)); | |
481 | return -EINVAL; | |
482 | } | |
483 | return rc; | |
484 | } | |
485 | ||
19e4cfef | 486 | static struct fdisk_parttype *ask_partition_type(struct fdisk_context *cxt, int *canceled) |
d6b3ba41 KZ |
487 | { |
488 | const char *q; | |
a745611d KZ |
489 | struct fdisk_label *lb; |
490 | ||
491 | assert(cxt); | |
492 | lb = fdisk_get_label(cxt, NULL); | |
d6b3ba41 | 493 | |
a745611d | 494 | if (!lb) |
d6b3ba41 KZ |
495 | return NULL; |
496 | ||
19e4cfef | 497 | *canceled = 0; |
006607ab KZ |
498 | |
499 | if (fdisk_label_has_parttypes_shortcuts(lb)) | |
500 | q = fdisk_label_has_code_parttypes(lb) ? | |
501 | _("Hex code or alias (type L to list all): ") : | |
502 | _("Partition type or alias (type L to list all): "); | |
503 | else | |
504 | q = fdisk_label_has_code_parttypes(lb) ? | |
505 | _("Hex code (type L to list all codes): ") : | |
506 | _("Partition type (type L to list all types): "); | |
d6b3ba41 | 507 | do { |
89770db4 | 508 | char buf[256] = { '\0' }; |
c1154128 | 509 | int rc = get_user_reply(q, buf, sizeof(buf)); |
d6b3ba41 | 510 | |
19e4cfef KZ |
511 | if (rc) { |
512 | if (rc == -ECANCELED) | |
513 | *canceled = 1; | |
d6b3ba41 | 514 | break; |
19e4cfef | 515 | } |
d6b3ba41 KZ |
516 | |
517 | if (buf[1] == '\0' && toupper(*buf) == 'L') | |
518 | list_partition_types(cxt); | |
e6effcac | 519 | else if (*buf) { |
006607ab KZ |
520 | struct fdisk_parttype *t = fdisk_label_advparse_parttype(lb, buf, |
521 | FDISK_PARTTYPE_PARSE_DATA | |
522 | | FDISK_PARTTYPE_PARSE_ALIAS | |
8d720dbe | 523 | | FDISK_PARTTYPE_PARSE_NAME |
006607ab | 524 | | FDISK_PARTTYPE_PARSE_SEQNUM); |
e6effcac KZ |
525 | if (!t) |
526 | fdisk_info(cxt, _("Failed to parse '%s' partition type."), buf); | |
527 | return t; | |
528 | } | |
d6b3ba41 KZ |
529 | } while (1); |
530 | ||
531 | return NULL; | |
532 | } | |
533 | ||
8d2f4498 | 534 | |
7b575fcc | 535 | void list_partition_types(struct fdisk_context *cxt) |
6dbe3af9 | 536 | { |
006607ab | 537 | size_t ntypes = 0, next = 0; |
f45f5c83 | 538 | struct fdisk_label *lb; |
006607ab | 539 | int pager = 0; |
6dbe3af9 | 540 | |
a745611d KZ |
541 | assert(cxt); |
542 | lb = fdisk_get_label(cxt, NULL); | |
543 | if (!lb) | |
544 | return; | |
545 | ntypes = fdisk_label_get_nparttypes(lb); | |
546 | if (!ntypes) | |
7b575fcc | 547 | return; |
2b6fc908 | 548 | |
a745611d | 549 | if (fdisk_label_has_code_parttypes(lb)) { |
7b575fcc KZ |
550 | /* |
551 | * Prints in 4 columns in format <hex> <name> | |
552 | */ | |
006607ab | 553 | size_t last[4], done = 0, size; |
76f17cf2 | 554 | int i; |
b8d22034 | 555 | |
76f17cf2 | 556 | size = ntypes; |
7b575fcc KZ |
557 | |
558 | for (i = 3; i >= 0; i--) | |
559 | last[3 - i] = done += (size + i - done) / (i + 1); | |
560 | i = done = 0; | |
561 | ||
562 | do { | |
563 | #define NAME_WIDTH 15 | |
564 | char name[NAME_WIDTH * MB_LEN_MAX]; | |
565 | size_t width = NAME_WIDTH; | |
a745611d | 566 | const struct fdisk_parttype *t = fdisk_label_get_parttype(lb, next); |
7b575fcc KZ |
567 | size_t ret; |
568 | ||
e6d0c4c1 | 569 | if (fdisk_parttype_get_name(t)) { |
5d271cef | 570 | printf("%s%02x ", i ? " " : "\n", |
a745611d KZ |
571 | fdisk_parttype_get_code(t)); |
572 | ret = mbsalign(_(fdisk_parttype_get_name(t)), | |
573 | name, sizeof(name), | |
574 | &width, MBS_ALIGN_LEFT, 0); | |
7b575fcc | 575 | |
76f17cf2 | 576 | if (ret == (size_t)-1 || ret >= sizeof(name)) |
a745611d KZ |
577 | printf("%-15.15s", |
578 | _(fdisk_parttype_get_name(t))); | |
76f17cf2 KZ |
579 | else |
580 | fputs(name, stdout); | |
581 | } | |
7b575fcc KZ |
582 | |
583 | next = last[i++] + done; | |
584 | if (i > 3 || next >= last[i]) { | |
585 | i = 0; | |
586 | next = ++done; | |
587 | } | |
588 | } while (done < last[0]); | |
589 | ||
006607ab | 590 | putchar('\n'); |
7b575fcc KZ |
591 | } else { |
592 | /* | |
593 | * Prints 1 column in format <idx> <name> <typestr> | |
594 | */ | |
76f17cf2 | 595 | size_t i; |
7b575fcc | 596 | |
8d2f4498 | 597 | pager_open(); |
006607ab | 598 | pager = 1; |
8d2f4498 | 599 | |
a745611d KZ |
600 | for (i = 0; i < ntypes; i++) { |
601 | const struct fdisk_parttype *t = fdisk_label_get_parttype(lb, i); | |
602 | printf("%3zu %-30s %s\n", i + 1, | |
603 | fdisk_parttype_get_name(t), | |
604 | fdisk_parttype_get_string(t)); | |
76f17cf2 | 605 | } |
8d2f4498 | 606 | |
7b575fcc | 607 | } |
006607ab KZ |
608 | |
609 | ||
610 | /* | |
611 | * Aliases | |
612 | */ | |
613 | if (fdisk_label_has_parttypes_shortcuts(lb)) { | |
614 | const char *alias = NULL, *typestr = NULL; | |
615 | int rc = 0; | |
616 | ||
617 | fputs(_("\nAliases:\n"), stdout); | |
618 | ||
619 | for (next = 0; rc == 0 || rc == 2; next++) { | |
620 | /* rc: <0 error, 0 success, 1 end, 2 deprecated */ | |
621 | rc = fdisk_label_get_parttype_shortcut(lb, | |
622 | next, &typestr, NULL, &alias); | |
623 | if (rc == 0) | |
624 | printf(" %-14s - %s\n", alias, typestr); | |
625 | } | |
626 | } | |
627 | ||
628 | if (pager) | |
629 | pager_close(); | |
630 | ||
6dbe3af9 KZ |
631 | } |
632 | ||
f02fecd1 | 633 | void toggle_dos_compatibility_flag(struct fdisk_context *cxt) |
852ce62b | 634 | { |
6a632136 | 635 | struct fdisk_label *lb = fdisk_get_label(cxt, "dos"); |
852ce62b KZ |
636 | int flag; |
637 | ||
638 | if (!lb) | |
639 | return; | |
640 | ||
641 | flag = !fdisk_dos_is_compatible(lb); | |
09f0c3d9 KZ |
642 | fdisk_info(cxt, flag ? |
643 | _("DOS Compatibility flag is set (DEPRECATED!)") : | |
644 | _("DOS Compatibility flag is not set")); | |
edd7b958 | 645 | |
852ce62b KZ |
646 | fdisk_dos_enable_compatible(lb, flag); |
647 | ||
aa36c2cf | 648 | if (fdisk_is_label(cxt, DOS)) |
09f0c3d9 | 649 | fdisk_reset_alignment(cxt); /* reset the current label */ |
6dbe3af9 KZ |
650 | } |
651 | ||
d45820df TW |
652 | static int strtosize_sectors(const char *str, unsigned long sector_size, |
653 | uintmax_t *res) | |
654 | { | |
655 | size_t len = strlen(str); | |
656 | int insec = 0; | |
657 | int rc; | |
658 | ||
659 | if (!len) | |
660 | return 0; | |
661 | ||
662 | if (str[len - 1] == 'S' || str[len - 1] == 's') { | |
663 | insec = 1; | |
664 | str = strndup(str, len - 1); /* strip trailing 's' */ | |
665 | if (!str) | |
666 | return -errno; | |
667 | } | |
668 | ||
669 | rc = strtosize(str, res); | |
670 | if (rc) | |
671 | return rc; | |
672 | ||
673 | if (insec) { | |
674 | *res *= sector_size; | |
675 | free((void *)str); | |
676 | } | |
677 | ||
678 | return 0; | |
679 | } | |
680 | ||
681 | void resize_partition(struct fdisk_context *cxt) | |
682 | { | |
683 | struct fdisk_partition *pa = NULL, *npa = NULL, *next = NULL; | |
684 | char *query = NULL, *response = NULL, *default_size; | |
685 | struct fdisk_table *tb = NULL; | |
686 | uint64_t max_size, size, secs; | |
687 | size_t i; | |
688 | int rc; | |
689 | ||
690 | assert(cxt); | |
691 | ||
692 | rc = fdisk_ask_partnum(cxt, &i, FALSE); | |
693 | if (rc) | |
694 | goto err; | |
695 | ||
696 | rc = fdisk_partition_get_max_size(cxt, i, &max_size); | |
697 | if (rc) | |
698 | goto err; | |
699 | ||
700 | max_size *= fdisk_get_sector_size(cxt); | |
701 | ||
702 | default_size = size_to_human_string(0, max_size); | |
703 | xasprintf(&query, _("New <size>{K,M,G,T,P} in bytes or <size>S in sectors (default %s)"), | |
704 | default_size); | |
705 | free(default_size); | |
706 | ||
707 | rc = fdisk_ask_string(cxt, query, &response); | |
708 | if (rc) | |
709 | goto err; | |
710 | ||
711 | size = max_size; | |
712 | rc = strtosize_sectors(response, fdisk_get_sector_size(cxt), &size); | |
713 | if (rc || size > max_size) { | |
714 | fdisk_warnx(cxt, _("Invalid size")); | |
715 | goto err; | |
716 | } | |
717 | ||
718 | npa = fdisk_new_partition(); | |
719 | if (!npa) | |
720 | goto err; | |
721 | ||
722 | secs = size / fdisk_get_sector_size(cxt); | |
723 | fdisk_partition_size_explicit(npa, 1); | |
724 | fdisk_partition_set_size(npa, secs); | |
725 | ||
726 | rc = fdisk_set_partition(cxt, i, npa); | |
727 | if (rc) | |
728 | goto err; | |
729 | ||
730 | fdisk_info(cxt, _("Partition %zu has been resized."), i + 1); | |
731 | ||
732 | out: | |
733 | free(query); | |
734 | free(response); | |
735 | fdisk_unref_partition(next); | |
736 | fdisk_unref_partition(pa); | |
737 | fdisk_unref_partition(npa); | |
738 | fdisk_unref_table(tb); | |
739 | return; | |
740 | ||
741 | err: | |
742 | fdisk_warnx(cxt, _("Could not resize partition %zu: %s"), | |
743 | i + 1, strerror(-rc)); | |
744 | goto out; | |
745 | } | |
746 | ||
27ddd4f1 | 747 | void change_partition_type(struct fdisk_context *cxt) |
e53ced85 | 748 | { |
641a75ca | 749 | size_t i; |
85151521 KZ |
750 | struct fdisk_parttype *t = NULL; |
751 | struct fdisk_partition *pa = NULL; | |
752 | const char *old = NULL; | |
19e4cfef | 753 | int canceled = 0; |
6dbe3af9 | 754 | |
e3661531 | 755 | assert(cxt); |
e3661531 | 756 | |
641a75ca | 757 | if (fdisk_ask_partnum(cxt, &i, FALSE)) |
24f4bbff | 758 | return; |
2b6fc908 | 759 | |
85151521 KZ |
760 | if (fdisk_get_partition(cxt, i, &pa)) { |
761 | fdisk_warnx(cxt, _("Partition %zu does not exist yet!"), i + 1); | |
762 | return; | |
763 | } | |
764 | ||
765 | t = (struct fdisk_parttype *) fdisk_partition_get_type(pa); | |
e6d0c4c1 | 766 | old = t ? fdisk_parttype_get_name(t) : _("Unknown"); |
85151521 KZ |
767 | |
768 | do { | |
19e4cfef KZ |
769 | t = ask_partition_type(cxt, &canceled); |
770 | if (canceled) | |
771 | break; | |
85151521 KZ |
772 | } while (!t); |
773 | ||
e6effcac | 774 | if (canceled == 0 && t && fdisk_set_partition_type(cxt, i, t) == 0) |
0477369a | 775 | fdisk_info(cxt, |
85151521 | 776 | _("Changed type of partition '%s' to '%s'."), |
a745611d | 777 | old, t ? fdisk_parttype_get_name(t) : _("Unknown")); |
85151521 KZ |
778 | else |
779 | fdisk_info(cxt, | |
780 | _("Type of partition %zu is unchanged: %s."), | |
781 | i + 1, old); | |
782 | ||
d6cfa8b3 | 783 | fdisk_unref_partition(pa); |
4bd02cdf | 784 | fdisk_unref_parttype(t); |
6dbe3af9 KZ |
785 | } |
786 | ||
a4c0dce8 KZ |
787 | #ifdef BLKDISCARD |
788 | ||
789 | static int do_discard(struct fdisk_context *cxt, struct fdisk_partition *pa) | |
790 | { | |
791 | char buf[512]; | |
792 | unsigned long ss; | |
793 | uint64_t range[2]; | |
794 | int yes = 0; | |
795 | ||
796 | ss = fdisk_get_sector_size(cxt); | |
797 | ||
798 | range[0] = (uint64_t) fdisk_partition_get_start(pa); | |
799 | range[1] = (uint64_t) fdisk_partition_get_size(pa); | |
800 | ||
801 | snprintf(buf, sizeof(buf), _("All data in the region (%"PRIu64 | |
802 | "-%"PRIu64") will be lost! Continue?"), | |
803 | range[0], range[0] + range[1] - 1); | |
804 | ||
805 | range[0] *= (uint64_t) ss; | |
806 | range[1] *= (uint64_t) ss; | |
807 | ||
808 | fdisk_ask_yesno(cxt, buf, &yes); | |
809 | if (!yes) | |
810 | return 1; | |
811 | ||
812 | errno = 0; | |
813 | if (ioctl(fdisk_get_devfd(cxt), BLKDISCARD, &range)) { | |
814 | fdisk_warn(cxt, _("BLKDISCARD ioctl failed")); | |
815 | return -errno; | |
816 | } | |
817 | return 0; | |
818 | } | |
819 | ||
820 | static void discard_partition(struct fdisk_context *cxt) | |
821 | { | |
822 | struct fdisk_partition *pa = NULL; | |
823 | size_t n = 0; | |
824 | ||
825 | fdisk_info(cxt, _("\nThe partition sectors will be immediately discarded.\n" | |
826 | "You can exit this dialog by pressing CTRL+C.\n")); | |
827 | ||
828 | if (fdisk_ask_partnum(cxt, &n, FALSE)) | |
829 | goto done; | |
830 | if (fdisk_get_partition(cxt, n, &pa)) { | |
831 | fdisk_warnx(cxt, _("Partition %zu does not exist yet!"), n + 1); | |
832 | goto done; | |
833 | } | |
834 | ||
835 | if (!fdisk_partition_has_size(pa) || !fdisk_partition_has_start(pa)) { | |
836 | fdisk_warnx(cxt, _("Partition %zu has unspeficied range"), n + 1); | |
837 | goto done; | |
838 | } | |
839 | ||
840 | if (do_discard(cxt, pa) == 0) | |
841 | fdisk_info(cxt, _("Discarded sectors on partition %zu."), n + 1); | |
842 | done: | |
843 | fdisk_unref_partition(pa); | |
844 | } | |
845 | ||
846 | static void discard_freespace(struct fdisk_context *cxt) | |
847 | { | |
848 | struct fdisk_partition *pa = NULL; | |
849 | struct fdisk_table *tb = NULL; | |
850 | size_t best = 0; | |
851 | uintmax_t n = 0; | |
852 | int ct; | |
853 | ||
854 | ct = list_freespace_get_table(cxt, &tb, &best); | |
855 | if (ct <= 0) { | |
856 | fdisk_info(cxt, _("No free space.")); | |
857 | goto done; | |
858 | } | |
859 | fdisk_info(cxt, _("\nThe unused sectors will be immediately discarded.\n" | |
860 | "You can exit this dialog by pressing CTRL+C.\n")); | |
861 | ||
862 | if (fdisk_ask_number(cxt, 1, best + 1, (uintmax_t) ct, | |
863 | _("Free space number"), &n) != 0) | |
864 | goto done; | |
865 | ||
866 | pa = fdisk_table_get_partition(tb, n - 1); | |
867 | if (!pa) | |
868 | goto done; | |
869 | ||
870 | if (!fdisk_partition_has_size(pa) || !fdisk_partition_has_start(pa)) { | |
871 | fdisk_warnx(cxt, _("Free space %"PRIu64 "has unspeficied range"), n); | |
872 | goto done; | |
873 | } | |
874 | ||
875 | if (do_discard(cxt, pa) == 0) | |
876 | fdisk_info(cxt, _("Discarded sectors on free space.")); | |
877 | done: | |
878 | fdisk_unref_table(tb); | |
879 | } | |
880 | ||
881 | void discard_sectors(struct fdisk_context *cxt) | |
882 | { | |
883 | int c; | |
884 | ||
885 | if (fdisk_is_readonly(cxt)) { | |
886 | fdisk_warnx(cxt, _("Discarding sectors is not possible in read-only mode.")); | |
887 | return; | |
888 | } | |
889 | ||
890 | if (fdisk_ask_menu(cxt, _("Type of area to be discarded"), | |
891 | &c, 'p', _("partition sectors"), 'p', | |
892 | _("free space sectros"), 'f', NULL) != 0) | |
893 | return; | |
894 | ||
895 | switch (c) { | |
896 | case 'p': | |
897 | discard_partition(cxt); | |
898 | break; | |
899 | case 'f': | |
900 | discard_freespace(cxt); | |
901 | break; | |
902 | } | |
903 | } | |
904 | ||
905 | #else /* !BLKDISCARD */ | |
906 | void discard_sectors(struct fdisk_context *cxt) | |
907 | { | |
908 | fdisk_warnx(cxt, _("Discard unsupported on your system.")); | |
909 | } | |
910 | #endif /* BLKDISCARD */ | |
911 | ||
3e3b51b3 JLB |
912 | int print_partition_info(struct fdisk_context *cxt) |
913 | { | |
914 | struct fdisk_partition *pa = NULL; | |
6360bcca | 915 | int rc = 0; |
3e3b51b3 JLB |
916 | size_t i, nfields; |
917 | int *fields = NULL; | |
918 | struct fdisk_label *lb = fdisk_get_label(cxt, NULL); | |
919 | ||
920 | if ((rc = fdisk_ask_partnum(cxt, &i, FALSE))) | |
921 | return rc; | |
922 | ||
923 | if ((rc = fdisk_get_partition(cxt, i, &pa))) { | |
924 | fdisk_warnx(cxt, _("Partition %zu does not exist yet!"), i + 1); | |
925 | return rc; | |
926 | } | |
927 | ||
6360bcca | 928 | if ((rc = fdisk_label_get_fields_ids_all(lb, cxt, &fields, &nfields))) |
3e3b51b3 | 929 | goto clean_data; |
3e3b51b3 JLB |
930 | |
931 | for (i = 0; i < nfields; ++i) { | |
932 | int id = fields[i]; | |
933 | char *data = NULL; | |
934 | const struct fdisk_field *fd = fdisk_label_get_field(lb, id); | |
935 | ||
936 | if (!fd) | |
937 | continue; | |
938 | ||
939 | rc = fdisk_partition_to_string(pa, cxt, id, &data); | |
940 | if (rc < 0) | |
941 | goto clean_data; | |
6360bcca KZ |
942 | if (!data || !*data) |
943 | continue; | |
14056588 | 944 | fdisk_info(cxt, "%15s: %s", fdisk_field_get_name(fd), data); |
3e3b51b3 JLB |
945 | free(data); |
946 | } | |
947 | ||
948 | clean_data: | |
949 | fdisk_unref_partition(pa); | |
950 | free(fields); | |
951 | return rc; | |
952 | } | |
953 | ||
e916600f KZ |
954 | static size_t skip_empty(const unsigned char *buf, size_t i, size_t sz) |
955 | { | |
956 | size_t next; | |
957 | const unsigned char *p0 = buf + i; | |
958 | ||
959 | for (next = i + 16; next < sz; next += 16) { | |
960 | if (memcmp(p0, buf + next, 16) != 0) | |
961 | break; | |
962 | } | |
963 | ||
964 | return next == i + 16 ? i : next; | |
965 | } | |
6dbe3af9 | 966 | |
a970c2dd | 967 | static void dump_buffer(off_t base, unsigned char *buf, size_t sz) |
09f0c3d9 | 968 | { |
e916600f KZ |
969 | size_t i, l, next = 0; |
970 | ||
971 | if (!buf) | |
972 | return; | |
973 | for (i = 0, l = 0; i < sz; i++, l++) { | |
974 | if (l == 0) { | |
a970c2dd | 975 | if (!next) |
e916600f | 976 | next = skip_empty(buf, i, sz); |
fdbd7bb9 | 977 | printf("%08jx ", (intmax_t)base + i); |
e916600f KZ |
978 | } |
979 | printf(" %02x", buf[i]); | |
980 | if (l == 7) /* words separator */ | |
981 | fputs(" ", stdout); | |
982 | else if (l == 15) { | |
983 | fputc('\n', stdout); /* next line */ | |
6dbe3af9 | 984 | l = -1; |
e916600f KZ |
985 | if (next > i) { |
986 | printf("*\n"); | |
987 | i = next - 1; | |
988 | } | |
989 | next = 0; | |
6dbe3af9 KZ |
990 | } |
991 | } | |
992 | if (l > 0) | |
993 | printf("\n"); | |
6dbe3af9 KZ |
994 | } |
995 | ||
e916600f | 996 | static void dump_blkdev(struct fdisk_context *cxt, const char *name, |
a970c2dd | 997 | uint64_t offset, size_t size) |
e53ced85 | 998 | { |
8eccde20 KZ |
999 | int fd = fdisk_get_devfd(cxt); |
1000 | ||
fdbd7bb9 | 1001 | fdisk_info(cxt, _("\n%s: offset = %"PRIu64", size = %zu bytes."), |
e916600f KZ |
1002 | name, offset, size); |
1003 | ||
8eccde20 KZ |
1004 | assert(fd >= 0); |
1005 | ||
9bbcf43f | 1006 | if (lseek(fd, (off_t) offset, SEEK_SET) == (off_t) -1) |
e916600f | 1007 | fdisk_warn(cxt, _("cannot seek")); |
5afed187 KZ |
1008 | else { |
1009 | unsigned char *buf = xmalloc(size); | |
1010 | ||
8eccde20 | 1011 | if (read_all(fd, (char *) buf, size) != (ssize_t) size) |
5afed187 KZ |
1012 | fdisk_warn(cxt, _("cannot read")); |
1013 | else | |
a970c2dd | 1014 | dump_buffer(offset, buf, size); |
5afed187 KZ |
1015 | free(buf); |
1016 | } | |
e916600f KZ |
1017 | } |
1018 | ||
1019 | void dump_firstsector(struct fdisk_context *cxt) | |
1020 | { | |
e3661531 | 1021 | assert(cxt); |
6dbe3af9 | 1022 | |
a970c2dd | 1023 | dump_blkdev(cxt, _("First sector"), 0, fdisk_get_sector_size(cxt)); |
e916600f KZ |
1024 | } |
1025 | ||
1026 | void dump_disklabel(struct fdisk_context *cxt) | |
1027 | { | |
e916600f KZ |
1028 | int i = 0; |
1029 | const char *name = NULL; | |
9bbcf43f | 1030 | uint64_t offset = 0; |
e916600f KZ |
1031 | size_t size = 0; |
1032 | ||
1033 | assert(cxt); | |
e3661531 | 1034 | |
e916600f | 1035 | while (fdisk_locate_disklabel(cxt, i++, &name, &offset, &size) == 0 && size) |
a970c2dd | 1036 | dump_blkdev(cxt, name, offset, size); |
6dbe3af9 KZ |
1037 | } |
1038 | ||
0073a4cf | 1039 | static fdisk_sector_t get_dev_blocks(char *dev) |
6da365de | 1040 | { |
bbe67996 | 1041 | int fd, ret; |
0073a4cf | 1042 | fdisk_sector_t size; |
6da365de | 1043 | |
74c9dbae | 1044 | if ((fd = open(dev, O_RDONLY|O_NONBLOCK)) < 0) |
289dcc90 | 1045 | err(EXIT_FAILURE, _("cannot open %s"), dev); |
0073a4cf | 1046 | ret = blkdev_get_sectors(fd, (unsigned long long *) &size); |
6da365de | 1047 | close(fd); |
bbe67996 SK |
1048 | if (ret < 0) |
1049 | err(EXIT_FAILURE, _("BLKGETSIZE ioctl failed on %s"), dev); | |
6da365de DB |
1050 | return size/2; |
1051 | } | |
1052 | ||
5635d195 KZ |
1053 | |
1054 | void follow_wipe_mode(struct fdisk_context *cxt) | |
1055 | { | |
1056 | int dowipe = wipemode == WIPEMODE_ALWAYS ? 1 : 0; | |
1057 | ||
1058 | if (isatty(STDIN_FILENO) && wipemode == WIPEMODE_AUTO) | |
1059 | dowipe = 1; /* do it in interactive mode */ | |
1060 | ||
1061 | if (fdisk_is_ptcollision(cxt) && wipemode != WIPEMODE_NEVER) | |
1062 | dowipe = 1; /* always remove old PT */ | |
1063 | ||
1064 | fdisk_enable_wipe(cxt, dowipe); | |
1065 | if (dowipe) | |
1066 | fdisk_warnx(cxt, _( | |
6cd671d4 | 1067 | "The device contains '%s' signature and it will be removed by a write command. " |
ce16f04e | 1068 | "See fdisk(8) man page and --wipe option for more details."), |
5635d195 KZ |
1069 | fdisk_get_collision(cxt)); |
1070 | else | |
1071 | fdisk_warnx(cxt, _( | |
6cd671d4 | 1072 | "The device contains '%s' signature and it may remain on the device. " |
5635d195 KZ |
1073 | "It is recommended to wipe the device with wipefs(8) or " |
1074 | "fdisk --wipe, in order to avoid possible collisions."), | |
1075 | fdisk_get_collision(cxt)); | |
1076 | } | |
1077 | ||
6e1eda6f | 1078 | static void __attribute__((__noreturn__)) usage(void) |
e3a4aaa7 | 1079 | { |
6e1eda6f RM |
1080 | FILE *out = stdout; |
1081 | ||
e3a4aaa7 KZ |
1082 | fputs(USAGE_HEADER, out); |
1083 | ||
1084 | fprintf(out, | |
7eeb2c82 WS |
1085 | _(" %1$s [options] <disk> change partition table\n" |
1086 | " %1$s [options] -l [<disk>...] list partition table(s)\n"), | |
e3a4aaa7 KZ |
1087 | program_invocation_short_name); |
1088 | ||
451dbcfa BS |
1089 | fputs(USAGE_SEPARATOR, out); |
1090 | fputs(_("Display or manipulate a disk partition table.\n"), out); | |
1091 | ||
e3a4aaa7 KZ |
1092 | fputs(USAGE_OPTIONS, out); |
1093 | fputs(_(" -b, --sector-size <size> physical and logical sector size\n"), out); | |
718b6f0c | 1094 | fputs(_(" -B, --protect-boot don't erase bootbits when creating a new label\n"), out); |
e3a4aaa7 | 1095 | fputs(_(" -c, --compatibility[=<mode>] mode is 'dos' or 'nondos' (default)\n"), out); |
a7466bdc SK |
1096 | fprintf(out, |
1097 | _(" -L, --color[=<when>] colorize output (%s, %s or %s)\n"), "auto", "always", "never"); | |
5d51dc2a KZ |
1098 | fprintf(out, |
1099 | " %s\n", USAGE_COLORS_DEFAULT); | |
9e930041 | 1100 | fputs(_(" -l, --list display partitions and exit\n"), out); |
99d78b2f KZ |
1101 | fputs(_(" -x, --list-details like --list but with more details\n"), out); |
1102 | ||
f2229320 | 1103 | fputs(_(" -n, --noauto-pt don't create default partition table on empty devices\n"), out); |
2d7dffeb | 1104 | fputs(_(" -o, --output <list> output columns\n"), out); |
e3a4aaa7 KZ |
1105 | fputs(_(" -t, --type <type> recognize specified partition table type only\n"), out); |
1106 | fputs(_(" -u, --units[=<unit>] display units: 'cylinders' or 'sectors' (default)\n"), out); | |
1107 | fputs(_(" -s, --getsz display device size in 512-byte sectors [DEPRECATED]\n"), out); | |
354f8cc8 | 1108 | fputs(_(" --bytes print SIZE in bytes rather than in human readable format\n"), out); |
9cd88771 KZ |
1109 | fprintf(out, |
1110 | _(" --lock[=<mode>] use exclusive device lock (%s, %s or %s)\n"), "yes", "no", "nonblock"); | |
a7466bdc SK |
1111 | fprintf(out, |
1112 | _(" -w, --wipe <mode> wipe signatures (%s, %s or %s)\n"), "auto", "always", "never"); | |
1113 | fprintf(out, | |
1114 | _(" -W, --wipe-partitions <mode> wipe signatures from new partitions (%s, %s or %s)\n"), "auto", "always", "never"); | |
e3a4aaa7 KZ |
1115 | |
1116 | fputs(USAGE_SEPARATOR, out); | |
4b4e391a KZ |
1117 | fputs(_(" -C, --cylinders <number> specify the number of cylinders\n"), out); |
1118 | fputs(_(" -H, --heads <number> specify the number of heads\n"), out); | |
1119 | fputs(_(" -S, --sectors <number> specify the number of sectors per track\n"), out); | |
e3a4aaa7 KZ |
1120 | |
1121 | fputs(USAGE_SEPARATOR, out); | |
bad4c729 | 1122 | fprintf(out, USAGE_HELP_OPTIONS(31)); |
e3a4aaa7 | 1123 | |
fff8ad58 KZ |
1124 | list_available_columns(out); |
1125 | ||
bad4c729 | 1126 | fprintf(out, USAGE_MAN_TAIL("fdisk(8)")); |
6e1eda6f | 1127 | exit(EXIT_SUCCESS); |
e3a4aaa7 KZ |
1128 | } |
1129 | ||
1130 | ||
5b72b3dd KZ |
1131 | enum { |
1132 | ACT_FDISK = 0, /* default */ | |
1133 | ACT_LIST, | |
99d78b2f | 1134 | ACT_LIST_DETAILS, |
5b72b3dd KZ |
1135 | ACT_SHOWSIZE |
1136 | }; | |
1137 | ||
e1144767 DB |
1138 | int main(int argc, char **argv) |
1139 | { | |
f2229320 | 1140 | int rc, i, c, act = ACT_FDISK, noauto_pt = 0; |
d0c9ddc3 | 1141 | int colormode = UL_COLORMODE_UNDEF; |
4e0e8253 | 1142 | struct fdisk_context *cxt; |
fff8ad58 | 1143 | char *outarg = NULL; |
9cd88771 | 1144 | const char *devname, *lockmode = NULL; |
354f8cc8 | 1145 | enum { |
9cd88771 KZ |
1146 | OPT_BYTES = CHAR_MAX + 1, |
1147 | OPT_LOCK | |
354f8cc8 | 1148 | }; |
e3a4aaa7 | 1149 | static const struct option longopts[] = { |
354f8cc8 | 1150 | { "bytes", no_argument, NULL, OPT_BYTES }, |
e3a4aaa7 KZ |
1151 | { "color", optional_argument, NULL, 'L' }, |
1152 | { "compatibility", optional_argument, NULL, 'c' }, | |
4b4e391a | 1153 | { "cylinders", required_argument, NULL, 'C' }, |
f1970cc5 | 1154 | { "heads", required_argument, NULL, 'H' }, |
4b4e391a | 1155 | { "sectors", required_argument, NULL, 'S' }, |
e3a4aaa7 KZ |
1156 | { "getsz", no_argument, NULL, 's' }, |
1157 | { "help", no_argument, NULL, 'h' }, | |
1158 | { "list", no_argument, NULL, 'l' }, | |
99d78b2f | 1159 | { "list-details", no_argument, NULL, 'x' }, |
9cd88771 | 1160 | { "lock", optional_argument, NULL, OPT_LOCK }, |
f2229320 | 1161 | { "noauto-pt", no_argument, NULL, 'n' }, |
e3a4aaa7 KZ |
1162 | { "sector-size", required_argument, NULL, 'b' }, |
1163 | { "type", required_argument, NULL, 't' }, | |
1164 | { "units", optional_argument, NULL, 'u' }, | |
1165 | { "version", no_argument, NULL, 'V' }, | |
55ef5938 | 1166 | { "output", required_argument, NULL, 'o' }, |
aeb9a30b | 1167 | { "protect-boot", no_argument, NULL, 'B' }, |
cb9a4b00 | 1168 | { "wipe", required_argument, NULL, 'w' }, |
ba465623 | 1169 | { "wipe-partitions",required_argument, NULL, 'W' }, |
e3a4aaa7 KZ |
1170 | { NULL, 0, NULL, 0 } |
1171 | }; | |
1172 | ||
7eda085c KZ |
1173 | setlocale(LC_ALL, ""); |
1174 | bindtextdomain(PACKAGE, LOCALEDIR); | |
1175 | textdomain(PACKAGE); | |
2c308875 | 1176 | close_stdout_atexit(); |
2b6fc908 | 1177 | |
4e0e8253 | 1178 | fdisk_init_debug(0); |
053939a4 | 1179 | scols_init_debug(0); |
e6d0c4c1 KZ |
1180 | fdiskprog_init_debug(); |
1181 | ||
4e0e8253 KZ |
1182 | cxt = fdisk_new_context(); |
1183 | if (!cxt) | |
1184 | err(EXIT_FAILURE, _("failed to allocate libfdisk context")); | |
1185 | ||
6a632136 | 1186 | fdisk_set_ask(cxt, ask_callback, NULL); |
416c43a9 | 1187 | |
f2229320 | 1188 | while ((c = getopt_long(argc, argv, "b:Bc::C:hH:lL::no:sS:t:u::vVw:W:x", |
e3a4aaa7 | 1189 | longopts, NULL)) != -1) { |
2b6fc908 KZ |
1190 | switch (c) { |
1191 | case 'b': | |
6bcd192c KZ |
1192 | { |
1193 | size_t sz = strtou32_or_err(optarg, | |
1194 | _("invalid sector size argument")); | |
1195 | if (sz != 512 && sz != 1024 && sz != 2048 && sz != 4096) | |
6e1eda6f | 1196 | errx(EXIT_FAILURE, _("invalid sector size argument")); |
6bcd192c | 1197 | fdisk_save_user_sector_size(cxt, sz, sz); |
2b6fc908 | 1198 | break; |
6bcd192c | 1199 | } |
9ff89c5d | 1200 | case 'B': |
aeb9a30b KZ |
1201 | fdisk_enable_bootbits_protection(cxt, 1); |
1202 | break; | |
0e6f4a20 | 1203 | case 'C': |
1653f0b0 KZ |
1204 | fdisk_save_user_geometry(cxt, |
1205 | strtou32_or_err(optarg, | |
1206 | _("invalid cylinders argument")), | |
1207 | 0, 0); | |
0e6f4a20 | 1208 | break; |
78498b7b | 1209 | case 'c': |
852ce62b | 1210 | if (optarg) { |
2b0bc17b | 1211 | /* this setting is independent on the current |
e3a4aaa7 KZ |
1212 | * actively used label |
1213 | */ | |
1214 | char *p = *optarg == '=' ? optarg + 1 : optarg; | |
6a632136 | 1215 | struct fdisk_label *lb = fdisk_get_label(cxt, "dos"); |
e3a4aaa7 | 1216 | |
852ce62b KZ |
1217 | if (!lb) |
1218 | err(EXIT_FAILURE, _("not found DOS label driver")); | |
e3a4aaa7 | 1219 | if (strcmp(p, "dos") == 0) |
852ce62b | 1220 | fdisk_dos_enable_compatible(lb, TRUE); |
e3a4aaa7 | 1221 | else if (strcmp(p, "nondos") == 0) |
852ce62b | 1222 | fdisk_dos_enable_compatible(lb, FALSE); |
6e1eda6f RM |
1223 | else |
1224 | errx(EXIT_FAILURE, _("unknown compatibility mode '%s'"), p); | |
852ce62b KZ |
1225 | } |
1226 | /* use default if no optarg specified */ | |
78498b7b | 1227 | break; |
0e6f4a20 | 1228 | case 'H': |
1653f0b0 KZ |
1229 | fdisk_save_user_geometry(cxt, 0, |
1230 | strtou32_or_err(optarg, | |
1231 | _("invalid heads argument")), | |
1232 | 0); | |
0e6f4a20 KZ |
1233 | break; |
1234 | case 'S': | |
1653f0b0 KZ |
1235 | fdisk_save_user_geometry(cxt, 0, 0, |
1236 | strtou32_or_err(optarg, | |
1237 | _("invalid sectors argument"))); | |
0e6f4a20 | 1238 | break; |
2b6fc908 | 1239 | case 'l': |
5b72b3dd | 1240 | act = ACT_LIST; |
2b6fc908 | 1241 | break; |
99d78b2f KZ |
1242 | case 'x': |
1243 | act = ACT_LIST_DETAILS; | |
1244 | break; | |
80a1712f | 1245 | case 'L': |
5d51dc2a | 1246 | colormode = UL_COLORMODE_AUTO; |
80a1712f KZ |
1247 | if (optarg) |
1248 | colormode = colormode_or_err(optarg, | |
1249 | _("unsupported color mode")); | |
1250 | break; | |
f2229320 KZ |
1251 | case 'n': |
1252 | noauto_pt = 1; | |
1253 | break; | |
fff8ad58 KZ |
1254 | case 'o': |
1255 | outarg = optarg; | |
1256 | break; | |
2b6fc908 | 1257 | case 's': |
5b72b3dd | 1258 | act = ACT_SHOWSIZE; |
2b6fc908 | 1259 | break; |
565b7da6 KZ |
1260 | case 't': |
1261 | { | |
1262 | struct fdisk_label *lb = NULL; | |
1263 | ||
6a632136 | 1264 | while (fdisk_next_label(cxt, &lb) == 0) |
565b7da6 KZ |
1265 | fdisk_label_set_disabled(lb, 1); |
1266 | ||
6a632136 | 1267 | lb = fdisk_get_label(cxt, optarg); |
565b7da6 KZ |
1268 | if (!lb) |
1269 | errx(EXIT_FAILURE, _("unsupported disklabel: %s"), optarg); | |
1270 | fdisk_label_set_disabled(lb, 0); | |
1ce1a112 | 1271 | break; |
565b7da6 | 1272 | } |
2b6fc908 | 1273 | case 'u': |
ec10aa67 KZ |
1274 | if (optarg && *optarg == '=') |
1275 | optarg++; | |
6a632136 | 1276 | if (fdisk_set_unit(cxt, optarg) != 0) |
6e1eda6f | 1277 | errx(EXIT_FAILURE, _("unsupported unit")); |
2b6fc908 | 1278 | break; |
e3a4aaa7 KZ |
1279 | case 'V': /* preferred for util-linux */ |
1280 | case 'v': /* for backward compatibility only */ | |
2c308875 | 1281 | print_version(EXIT_SUCCESS); |
cb9a4b00 KZ |
1282 | case 'w': |
1283 | wipemode = wipemode_from_string(optarg); | |
1284 | if (wipemode < 0) | |
1285 | errx(EXIT_FAILURE, _("unsupported wipe mode")); | |
1286 | break; | |
ba465623 KZ |
1287 | case 'W': |
1288 | pwipemode = wipemode_from_string(optarg); | |
1289 | if (pwipemode < 0) | |
1290 | errx(EXIT_FAILURE, _("unsupported wipe mode")); | |
1291 | break; | |
e1144767 | 1292 | case 'h': |
6e1eda6f | 1293 | usage(); |
354f8cc8 KZ |
1294 | case OPT_BYTES: |
1295 | fdisk_set_size_unit(cxt, FDISK_SIZEUNIT_BYTES); | |
1296 | break; | |
9cd88771 KZ |
1297 | case OPT_LOCK: |
1298 | lockmode = "1"; | |
1299 | if (optarg) { | |
1300 | if (*optarg == '=') | |
1301 | optarg++; | |
1302 | lockmode = optarg; | |
1303 | } | |
1304 | break; | |
2b6fc908 | 1305 | default: |
677ec86c | 1306 | errtryhelp(EXIT_FAILURE); |
2b6fc908 | 1307 | } |
6dbe3af9 | 1308 | } |
2b6fc908 | 1309 | |
6bcd192c KZ |
1310 | if (argc-optind != 1 && fdisk_has_user_device_properties(cxt)) |
1311 | warnx(_("The device properties (sector size and geometry) should" | |
1312 | " be used with one specified device only.")); | |
7eda085c | 1313 | |
d0c9ddc3 | 1314 | colors_init(colormode, "fdisk"); |
c1154128 | 1315 | is_interactive = isatty(STDIN_FILENO); |
ffcf0540 | 1316 | |
5b72b3dd KZ |
1317 | switch (act) { |
1318 | case ACT_LIST: | |
99d78b2f | 1319 | case ACT_LIST_DETAILS: |
6a632136 | 1320 | fdisk_enable_listonly(cxt, 1); |
99d78b2f KZ |
1321 | |
1322 | if (act == ACT_LIST_DETAILS) | |
1323 | fdisk_enable_details(cxt, 1); | |
1324 | ||
fff8ad58 | 1325 | init_fields(cxt, outarg, NULL); |
ffcf0540 | 1326 | |
2b6fc908 KZ |
1327 | if (argc > optind) { |
1328 | int k; | |
8fdd483c | 1329 | |
4a52959d WS |
1330 | for (rc = 0, k = optind; k < argc; k++) |
1331 | rc += print_device_pt(cxt, argv[k], 1, 0, k != optind); | |
8fdd483c | 1332 | |
8fdd483c KZ |
1333 | if (rc) |
1334 | return EXIT_FAILURE; | |
ea4824f1 | 1335 | } else |
d2c47697 | 1336 | print_all_devices_pt(cxt, 0); |
5b72b3dd | 1337 | break; |
2b6fc908 | 1338 | |
5b72b3dd | 1339 | case ACT_SHOWSIZE: |
9564e46c | 1340 | /* deprecated */ |
6e1eda6f RM |
1341 | if (argc - optind <= 0) { |
1342 | warnx(_("bad usage")); | |
1343 | errtryhelp(EXIT_FAILURE); | |
1344 | } | |
6da365de | 1345 | for (i = optind; i < argc; i++) { |
0073a4cf KZ |
1346 | uintmax_t blks = get_dev_blocks(argv[i]); |
1347 | ||
5b72b3dd | 1348 | if (argc - optind == 1) |
0073a4cf | 1349 | printf("%ju\n", blks); |
2b6fc908 | 1350 | else |
0073a4cf | 1351 | printf("%s: %ju\n", argv[i], blks); |
6dbe3af9 | 1352 | } |
5b72b3dd | 1353 | break; |
6dbe3af9 | 1354 | |
5b72b3dd | 1355 | case ACT_FDISK: |
6e1eda6f RM |
1356 | if (argc-optind != 1) { |
1357 | warnx(_("bad usage")); | |
1358 | errtryhelp(EXIT_FAILURE); | |
1359 | } | |
7eda085c | 1360 | |
5b72b3dd | 1361 | /* Here starts interactive mode, use fdisk_{warn,info,..} functions */ |
496c979a | 1362 | color_scheme_enable("welcome", UL_COLOR_GREEN); |
09f0c3d9 | 1363 | fdisk_info(cxt, _("Welcome to fdisk (%s)."), PACKAGE_STRING); |
80a1712f KZ |
1364 | color_disable(); |
1365 | fdisk_info(cxt, _("Changes will remain in memory only, until you decide to write them.\n" | |
1366 | "Be careful before using the write command.\n")); | |
2d8988bd | 1367 | |
9cd88771 KZ |
1368 | devname = argv[optind]; |
1369 | rc = fdisk_assign_device(cxt, devname, 0); | |
e146ae4e | 1370 | if (rc == -EACCES) { |
9cd88771 | 1371 | rc = fdisk_assign_device(cxt, devname, 1); |
e146ae4e | 1372 | if (rc == 0) |
62eea9ce | 1373 | fdisk_warnx(cxt, _("Device is open in read-only mode.")); |
e146ae4e KZ |
1374 | } |
1375 | if (rc) | |
9cd88771 | 1376 | err(EXIT_FAILURE, _("cannot open %s"), devname); |
2d8988bd | 1377 | |
dee0c29c KZ |
1378 | if (fdisk_device_is_used(cxt)) |
1379 | fdisk_warnx(cxt, _( | |
1380 | "This disk is currently in use - repartitioning is probably a bad idea.\n" | |
1381 | "It's recommended to umount all file systems, and swapoff all swap\n" | |
1382 | "partitions on this disk.\n")); | |
1383 | ||
5b72b3dd | 1384 | fflush(stdout); |
56c07b96 | 1385 | |
9cd88771 KZ |
1386 | if (!fdisk_is_readonly(cxt) |
1387 | && blkdev_lock(fdisk_get_devfd(cxt), devname, lockmode) != 0) { | |
1388 | fdisk_deassign_device(cxt, 1); | |
1389 | fdisk_unref_context(cxt); | |
1390 | return EXIT_FAILURE; | |
1391 | } | |
1392 | ||
5635d195 KZ |
1393 | if (fdisk_get_collision(cxt)) |
1394 | follow_wipe_mode(cxt); | |
cb9a4b00 | 1395 | |
aa36c2cf | 1396 | if (!fdisk_has_label(cxt)) { |
2d8988bd | 1397 | fdisk_info(cxt, _("Device does not contain a recognized partition table.")); |
f2229320 KZ |
1398 | if (!noauto_pt) |
1399 | fdisk_create_disklabel(cxt, NULL); | |
433d05ff | 1400 | |
aa36c2cf | 1401 | } else if (fdisk_is_label(cxt, GPT) && fdisk_gpt_is_hybrid(cxt)) |
433d05ff | 1402 | fdisk_warnx(cxt, _( |
09af3db4 | 1403 | "A hybrid GPT was detected. You have to sync " |
433d05ff | 1404 | "the hybrid MBR manually (expert command 'M').")); |
6dbe3af9 | 1405 | |
fff8ad58 KZ |
1406 | init_fields(cxt, outarg, NULL); /* -o <columns> */ |
1407 | ||
fadd8e08 KZ |
1408 | if (!fdisk_is_readonly(cxt)) { |
1409 | fdisk_get_partitions(cxt, &original_layout); | |
1410 | device_is_used = fdisk_device_is_used(cxt); | |
1411 | } | |
1412 | ||
5b72b3dd KZ |
1413 | while (1) |
1414 | process_fdisk_menu(&cxt); | |
1415 | } | |
9777759a | 1416 | |
c7119037 | 1417 | fdisk_unref_context(cxt); |
5b72b3dd | 1418 | return EXIT_SUCCESS; |
6dbe3af9 | 1419 | } |