]> git.ipfire.org Git - thirdparty/util-linux.git/blame - fdisk/sfdisk.c
fdisk: verify writing to streams was successful
[thirdparty/util-linux.git] / fdisk / sfdisk.c
CommitLineData
fd6b7a7f
KZ
1/*
2 * sfdisk version 3.0 - aeb - 950813
3 *
4 * Copyright (C) 1995 Andries E. Brouwer (aeb@cwi.nl)
5 *
6 * This program is free software. You can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation: either Version 1
9 * or (at your option) any later version.
10 *
11 * A.V. Le Blanc (LeBlanc@mcc.ac.uk) wrote Linux fdisk 1992-1994,
12 * patched by various people (faith@cs.unc.edu, martin@cs.unc.edu,
13 * leisner@sdsp.mc.xerox.com, esr@snark.thyrsus.com, aeb@cwi.nl)
14 * 1993-1995, with version numbers (as far as I have seen) 0.93 - 2.0e.
15 * This program had (head,sector,cylinder) as basic unit, and was
16 * (therefore) broken in several ways for the use on larger disks -
17 * for example, my last patch (from 2.0d to 2.0e) was required
18 * to allow a partition to cross cylinder 8064, and to write an
19 * extended partition past the 4GB mark.
20 *
21 * The current program is a rewrite from scratch, and I started a
22 * version numbering at 3.0.
9df2ac60 23 * Andries Brouwer, aeb@cwi.nl, 950813
fd6b7a7f
KZ
24 *
25 * Well, a good user interface is still lacking. On the other hand,
26 * many configurations cannot be handled by any other fdisk.
27 * I changed the name to sfdisk to prevent confusion. - aeb, 970501
28 */
29
30#define PROGNAME "sfdisk"
fd6b7a7f
KZ
31
32#include <stdio.h>
33#include <stdlib.h> /* atoi, free */
34#include <stdarg.h> /* varargs */
35#include <unistd.h> /* read, write */
36#include <fcntl.h> /* O_RDWR */
37#include <errno.h> /* ERANGE */
c0f19ccf 38#include <string.h> /* strchr(), strrchr() */
fd6b7a7f
KZ
39#include <ctype.h>
40#include <getopt.h>
41#include <sys/ioctl.h>
42#include <sys/stat.h>
22853e4a 43#include <sys/utsname.h>
4310e47a 44#include <limits.h>
11ef0c35
KZ
45
46#include "c.h"
7eda085c 47#include "nls.h"
109dbc4f 48#include "xalloc.h"
810f986b 49#include "blkdev.h"
8a4a67b9 50#include "linux_version.h"
7eda085c 51#include "common.h"
929f243f 52#include "wholedisk.h"
5dbff4c0 53#include "gpt.h"
6bec8710
KZ
54#include "pathnames.h"
55#include "canonicalize.h"
34ca51dc 56#include "rpmatch.h"
b2d28533 57#include "closestream.h"
5dbff4c0 58
fd6b7a7f
KZ
59/*
60 * Table of contents:
61 * A. About seeking
62 * B. About sectors
63 * C. About heads, sectors and cylinders
64 * D. About system Ids
65 * E. About partitions
66 * F. The standard input
67 * G. The command line
68 * H. Listing the current situation
69 * I. Writing the new situation
70 */
71int exit_status = 0;
72
37b94458
KZ
73int force = 0; /* 1: do what I say, even if it is stupid ... */
74int quiet = 0; /* 1: suppress all warnings */
22853e4a
KZ
75/* IA-64 gcc spec file currently does -DLinux... */
76#undef Linux
37b94458
KZ
77int Linux = 0; /* 1: suppress warnings irrelevant for Linux */
78int DOS = 0; /* 1: shift extended partitions by #sectors, not 1 */
79int DOS_extended = 0; /* 1: use starting cylinder boundary of extd partn */
80int dump = 0; /* 1: list in a format suitable for later input */
81int verify = 0; /* 1: check that listed partition is reasonable */
82int no_write = 0; /* 1: do not actually write to disk */
83int no_reread = 0; /* 1: skip the BLKRRPART ioctl test at startup */
84int leave_last = 0; /* 1: don't allocate the last cylinder */
fd6b7a7f
KZ
85int opt_list = 0;
86char *save_sector_file = NULL;
87char *restore_sector_file = NULL;
88
c129767e 89static void
4a01477b 90my_warn(char *s, ...) {
c129767e
KZ
91 va_list p;
92
93 va_start(p, s);
0b0bb920
KZ
94 if (!quiet) {
95 fflush(stdout);
96 vfprintf(stderr, s, p);
97 fflush(stderr);
98 }
fd6b7a7f
KZ
99 va_end(p);
100}
101
22853e4a 102static void
fd6b7a7f
KZ
103error(char *s, ...) {
104 va_list p;
105
106 va_start(p, s);
107 fflush(stdout);
108 fprintf(stderr, "\n" PROGNAME ": ");
109 vfprintf(stderr, s, p);
c129767e 110 fflush(stderr);
fd6b7a7f
KZ
111 va_end(p);
112}
113
fd6b7a7f
KZ
114/*
115 * A. About seeking
116 */
117
118/*
119 * sseek: seek to specified sector - return 0 on failure
120 *
22853e4a 121 * Note: we use 512-byte sectors here, irrespective of the hardware ss.
fd6b7a7f 122 */
fd6b7a7f 123
22853e4a 124static int
8c4c0268 125sseek(char *dev, int fd, unsigned long s) {
cf6d7fae
KZ
126 off_t in, out;
127 in = ((off_t) s << 9);
fd6b7a7f 128
22853e4a 129 if ((out = lseek(fd, in, SEEK_SET)) != in) {
cf6d7fae 130 perror("lseek");
7eda085c 131 error(_("seek error on %s - cannot seek to %lu\n"), dev, s);
fd6b7a7f
KZ
132 return 0;
133 }
134
135 if (in != out) {
7eda085c 136 error(_("seek error: wanted 0x%08x%08x, got 0x%08x%08x\n"),
37b94458
KZ
137 (unsigned int)(in >> 32), (unsigned int)(in & 0xffffffff),
138 (unsigned int)(out >> 32), (unsigned int)(out & 0xffffffff));
fd6b7a7f
KZ
139 return 0;
140 }
141 return 1;
142}
143
144/*
145 * B. About sectors
146 */
147
148/*
149 * We preserve all sectors read in a chain - some of these will
150 * have to be modified and written back.
151 */
152struct sector {
153 struct sector *next;
6c709b57 154 unsigned long long sectornumber;
fd6b7a7f
KZ
155 int to_be_written;
156 char data[512];
157} *sectorhead;
158
22853e4a 159static void
fd6b7a7f
KZ
160free_sectors(void) {
161 struct sector *s;
162
163 while (sectorhead) {
164 s = sectorhead;
165 sectorhead = s->next;
166 free(s);
167 }
168}
169
22853e4a 170static struct sector *
6c709b57 171get_sector(char *dev, int fd, unsigned long long sno) {
fd6b7a7f
KZ
172 struct sector *s;
173
37b94458 174 for (s = sectorhead; s; s = s->next)
c129767e 175 if (s->sectornumber == sno)
fd6b7a7f
KZ
176 return s;
177
178 if (!sseek(dev, fd, sno))
179 return 0;
180
109dbc4f 181 s = xmalloc(sizeof(struct sector));
fd6b7a7f
KZ
182
183 if (read(fd, s->data, sizeof(s->data)) != sizeof(s->data)) {
22853e4a
KZ
184 if (errno) /* 0 in case we read past end-of-disk */
185 perror("read");
7eda085c 186 error(_("read error on %s - cannot read sector %lu\n"), dev, sno);
fd6b7a7f
KZ
187 free(s);
188 return 0;
189 }
190
191 s->next = sectorhead;
192 sectorhead = s;
193 s->sectornumber = sno;
194 s->to_be_written = 0;
195
196 return s;
197}
198
22853e4a 199static int
37b94458 200msdos_signature(struct sector *s) {
934238cd 201 unsigned char *data = (unsigned char *)s->data;
364cda48 202 if (data[510] == 0x55 && data[511] == 0xaa)
37b94458 203 return 1;
364cda48
KZ
204 error(_("ERROR: sector %lu does not have an msdos signature\n"),
205 s->sectornumber);
206 return 0;
fd6b7a7f
KZ
207}
208
22853e4a 209static int
fd6b7a7f
KZ
210write_sectors(char *dev, int fd) {
211 struct sector *s;
212
213 for (s = sectorhead; s; s = s->next)
214 if (s->to_be_written) {
215 if (!sseek(dev, fd, s->sectornumber))
216 return 0;
217 if (write(fd, s->data, sizeof(s->data)) != sizeof(s->data)) {
218 perror("write");
7eda085c 219 error(_("write error on %s - cannot write sector %lu\n"),
37b94458 220 dev, s->sectornumber);
fd6b7a7f
KZ
221 return 0;
222 }
223 s->to_be_written = 0;
224 }
225 return 1;
226}
227
22853e4a 228static void
fd6b7a7f
KZ
229ulong_to_chars(unsigned long u, char *uu) {
230 int i;
231
37b94458 232 for (i = 0; i < 4; i++) {
fd6b7a7f
KZ
233 uu[i] = (u & 0xff);
234 u >>= 8;
235 }
236}
237
22853e4a 238static unsigned long
fd6b7a7f
KZ
239chars_to_ulong(unsigned char *uu) {
240 int i;
241 unsigned long u = 0;
242
37b94458 243 for (i = 3; i >= 0; i--)
fd6b7a7f
KZ
244 u = (u << 8) | uu[i];
245 return u;
246}
247
22853e4a 248static int
fd6b7a7f
KZ
249save_sectors(char *dev, int fdin) {
250 struct sector *s;
251 char ss[516];
78917e48 252 int fdout = -1;
fd6b7a7f
KZ
253
254 fdout = open(save_sector_file, O_WRONLY | O_CREAT, 0444);
255 if (fdout < 0) {
256 perror(save_sector_file);
7eda085c 257 error(_("cannot open partition sector save file (%s)\n"),
37b94458 258 save_sector_file);
78917e48 259 goto err;
fd6b7a7f
KZ
260 }
261
262 for (s = sectorhead; s; s = s->next)
263 if (s->to_be_written) {
264 ulong_to_chars(s->sectornumber, ss);
265 if (!sseek(dev, fdin, s->sectornumber))
78917e48 266 goto err;
37b94458 267 if (read(fdin, ss + 4, 512) != 512) {
fd6b7a7f 268 perror("read");
7eda085c 269 error(_("read error on %s - cannot read sector %lu\n"),
37b94458 270 dev, s->sectornumber);
78917e48 271 goto err;
fd6b7a7f
KZ
272 }
273 if (write(fdout, ss, sizeof(ss)) != sizeof(ss)) {
274 perror("write");
7eda085c 275 error(_("write error on %s\n"), save_sector_file);
78917e48 276 goto err;
fd6b7a7f
KZ
277 }
278 }
78917e48
KZ
279
280 close(fdout);
fd6b7a7f 281 return 1;
78917e48 282
37b94458 283 err:
78917e48
KZ
284 if (fdout >= 0)
285 close(fdout);
286 return 0;
fd6b7a7f
KZ
287}
288
e82810c6 289static int reread_disk_partition(char *dev, int fd);
fd6b7a7f 290
22853e4a 291static int
fd6b7a7f 292restore_sectors(char *dev) {
78917e48
KZ
293 int fdin = -1, fdout = -1;
294 int ct;
fd6b7a7f 295 struct stat statbuf;
823a6aa1 296 char *ss0 = NULL, *ss;
fd6b7a7f
KZ
297 unsigned long sno;
298
299 if (stat(restore_sector_file, &statbuf) < 0) {
300 perror(restore_sector_file);
7eda085c 301 error(_("cannot stat partition restore file (%s)\n"),
37b94458 302 restore_sector_file);
78917e48 303 goto err;
fd6b7a7f
KZ
304 }
305 if (statbuf.st_size % 516) {
7eda085c 306 error(_("partition restore file has wrong size - not restoring\n"));
78917e48 307 goto err;
fd6b7a7f 308 }
99d618c0
DR
309
310 ss0 = xmalloc(statbuf.st_size);
823a6aa1
SK
311 ss = ss0;
312
fd6b7a7f
KZ
313 fdin = open(restore_sector_file, O_RDONLY);
314 if (fdin < 0) {
315 perror(restore_sector_file);
7eda085c 316 error(_("cannot open partition restore file (%s)\n"),
37b94458 317 restore_sector_file);
78917e48 318 goto err;
fd6b7a7f
KZ
319 }
320 if (read(fdin, ss, statbuf.st_size) != statbuf.st_size) {
321 perror("read");
7eda085c 322 error(_("error reading %s\n"), restore_sector_file);
78917e48 323 goto err;
fd6b7a7f
KZ
324 }
325
326 fdout = open(dev, O_WRONLY);
327 if (fdout < 0) {
328 perror(dev);
7eda085c 329 error(_("cannot open device %s for writing\n"), dev);
78917e48 330 goto err;
fd6b7a7f
KZ
331 }
332
37b94458
KZ
333 ct = statbuf.st_size / 516;
334 while (ct--) {
335 sno = chars_to_ulong((unsigned char *)ss);
fd6b7a7f 336 if (!sseek(dev, fdout, sno))
37b94458
KZ
337 goto err;
338 if (write(fdout, ss + 4, 512) != 512) {
fd6b7a7f 339 perror(dev);
7eda085c 340 error(_("error writing sector %lu on %s\n"), sno, dev);
78917e48 341 goto err;
fd6b7a7f
KZ
342 }
343 ss += 516;
344 }
345 free(ss0);
823a6aa1 346 ss0 = NULL;
fd6b7a7f 347
574d9252 348 if (!reread_disk_partition(dev, fdout)) /* closes fdout */
37b94458 349 goto err;
78917e48 350 close(fdin);
fd6b7a7f
KZ
351
352 return 1;
78917e48 353
37b94458 354 err:
823a6aa1 355 free(ss0);
78917e48
KZ
356 if (fdin >= 0)
357 close(fdin);
358 if (fdout >= 0)
359 close(fdout);
360
361 return 0;
fd6b7a7f
KZ
362}
363
364/*
365 * C. About heads, sectors and cylinders
366 */
367
368/*
369 * <linux/hdreg.h> defines HDIO_GETGEO and
370 * struct hd_geometry {
371 * unsigned char heads;
372 * unsigned char sectors;
373 * unsigned short cylinders;
374 * unsigned long start;
375 * };
22853e4a
KZ
376 *
377 * For large disks g.cylinders is truncated, so we use BLKGETSIZE.
fd6b7a7f
KZ
378 */
379
7eda085c
KZ
380/*
381 * We consider several geometries for a disk:
382 * B - the BIOS geometry, gotten from the kernel via HDIO_GETGEO
383 * F - the fdisk geometry
384 * U - the user-specified geometry
385 *
386 * 0 means unspecified / unknown
387 */
388struct geometry {
37b94458
KZ
389 unsigned long long total_size; /* in sectors */
390 unsigned long cylindersize; /* in sectors */
391 unsigned long heads, sectors, cylinders;
392 unsigned long start;
7eda085c 393} B, F, U;
fd6b7a7f 394
22853e4a
KZ
395static struct geometry
396get_geometry(char *dev, int fd, int silent) {
fd6b7a7f 397 struct hd_geometry g;
2cccd0ff
KZ
398 unsigned long cyls;
399 unsigned long long sectors;
22853e4a 400 struct geometry R;
fd6b7a7f 401
6b0054a2
ST
402#ifdef HDIO_GETGEO
403 if (ioctl(fd, HDIO_GETGEO, &g))
404#endif
405 {
22853e4a
KZ
406 g.heads = g.sectors = g.cylinders = g.start = 0;
407 if (!silent)
66d28be8 408 warnx(_("Disk %s: cannot get geometry\n"), dev);
22853e4a 409 }
2cccd0ff
KZ
410
411 R.start = g.start;
22853e4a
KZ
412 R.heads = g.heads;
413 R.sectors = g.sectors;
414 R.cylindersize = R.heads * R.sectors;
2cccd0ff 415 R.cylinders = 0;
0b0bb920 416 R.total_size = 0;
2cccd0ff 417
810f986b 418 if (blkdev_get_sectors(fd, &sectors) == -1) {
0b0bb920
KZ
419 /* maybe an ordinary file */
420 struct stat s;
421
422 if (fstat(fd, &s) == 0 && S_ISREG(s.st_mode))
423 R.total_size = (s.st_size >> 9);
424 else if (!silent)
66d28be8 425 warnx(_("Disk %s: cannot get size\n"), dev);
0b0bb920 426 } else
37b94458 427 R.total_size = sectors;
0b0bb920
KZ
428
429 if (R.cylindersize && R.total_size) {
37b94458
KZ
430 sectors /= R.cylindersize;
431 cyls = sectors;
432 if (cyls != sectors)
433 cyls = ~0;
434 R.cylinders = cyls;
2cccd0ff 435 }
0b0bb920 436
22853e4a
KZ
437 return R;
438}
fd6b7a7f 439
22853e4a
KZ
440static void
441get_cylindersize(char *dev, int fd, int silent) {
442 struct geometry R;
fd6b7a7f 443
22853e4a 444 R = get_geometry(dev, fd, silent);
fd6b7a7f 445
65387261
LC
446 B.heads = (U.heads ? U.heads : R.heads ? R.heads : 255);
447 B.sectors = (U.sectors ? U.sectors : R.sectors ? R.sectors : 63);
22853e4a 448 B.cylinders = (U.cylinders ? U.cylinders : R.cylinders);
fd6b7a7f 449
7eda085c 450 B.cylindersize = B.heads * B.sectors;
0b0bb920
KZ
451 B.total_size = R.total_size;
452
453 if (B.cylinders == 0 && B.cylindersize != 0)
37b94458 454 B.cylinders = B.total_size / B.cylindersize;
fd6b7a7f 455
22853e4a 456 if (R.start && !force) {
be350fb9
BS
457 my_warn(_("Warning: start=%lu - this looks like a partition rather than\n"
458 "the entire disk. Using fdisk on it is probably meaningless.\n"
459 "[Use the --force option if you really want this]\n"),
37b94458 460 R.start);
22853e4a
KZ
461 exit(1);
462 }
cf3f26bf 463#if 0
22853e4a 464 if (R.heads && B.heads != R.heads)
4a01477b 465 my_warn(_("Warning: HDIO_GETGEO says that there are %lu heads\n"),
37b94458 466 R.heads);
22853e4a 467 if (R.sectors && B.sectors != R.sectors)
4a01477b 468 my_warn(_("Warning: HDIO_GETGEO says that there are %lu sectors\n"),
37b94458 469 R.sectors);
22853e4a 470 if (R.cylinders && B.cylinders != R.cylinders
37b94458 471 && B.cylinders < 65536 && R.cylinders < 65536)
be350fb9 472 my_warn(_("Warning: BLKGETSIZE/HDIO_GETGEO says that there are %lu cylinders\n"),
37b94458 473 R.cylinders);
cf3f26bf 474#endif
22853e4a 475
7eda085c 476 if (B.sectors > 63)
be350fb9
BS
477 my_warn(_("Warning: unlikely number of sectors (%lu) - usually at most 63\n"
478 "This will give problems with all software that uses C/H/S addressing.\n"),
37b94458 479 B.sectors);
fd6b7a7f 480 if (!silent)
37b94458
KZ
481 printf(_("\nDisk %s: %lu cylinders, %lu heads, %lu sectors/track\n"),
482 dev, B.cylinders, B.heads, B.sectors);
fd6b7a7f
KZ
483}
484
37b94458
KZ
485typedef struct {
486 unsigned char h, s, c;
9df2ac60 487} __attribute__ ((packed)) chs; /* has some c bits in s */
37b94458 488chs zero_chs = { 0, 0, 0 };
fd6b7a7f 489
37b94458
KZ
490typedef struct {
491 unsigned long h, s, c;
492} longchs;
fd6b7a7f
KZ
493longchs zero_longchs;
494
22853e4a 495static chs
37b94458 496longchs_to_chs(longchs aa, struct geometry G) {
fd6b7a7f
KZ
497 chs a;
498
499 if (aa.h < 256 && aa.s < 64 && aa.c < 1024) {
500 a.h = aa.h;
501 a.s = aa.s | ((aa.c >> 2) & 0xc0);
502 a.c = (aa.c & 0xff);
7eda085c
KZ
503 } else if (G.heads && G.sectors) {
504 a.h = G.heads - 1;
505 a.s = G.sectors | 0xc0;
fd6b7a7f
KZ
506 a.c = 0xff;
507 } else
37b94458 508 a = zero_chs;
fd6b7a7f
KZ
509 return a;
510}
511
22853e4a 512static longchs
37b94458 513chs_to_longchs(chs a) {
fd6b7a7f
KZ
514 longchs aa;
515
516 aa.h = a.h;
517 aa.s = (a.s & 0x3f);
518 aa.c = (a.s & 0xc0);
519 aa.c = (aa.c << 2) + a.c;
520 return aa;
521}
522
22853e4a 523static longchs
37b94458 524ulong_to_longchs(unsigned long sno, struct geometry G) {
fd6b7a7f
KZ
525 longchs aa;
526
7eda085c
KZ
527 if (G.heads && G.sectors && G.cylindersize) {
528 aa.s = 1 + sno % G.sectors;
529 aa.h = (sno / G.sectors) % G.heads;
530 aa.c = sno / G.cylindersize;
fd6b7a7f
KZ
531 return aa;
532 } else {
533 return zero_longchs;
534 }
535}
536
22853e4a 537static chs
37b94458 538ulong_to_chs(unsigned long sno, struct geometry G) {
7eda085c 539 return longchs_to_chs(ulong_to_longchs(sno, G), G);
fd6b7a7f
KZ
540}
541
22853e4a
KZ
542#if 0
543static unsigned long
37b94458
KZ
544longchs_to_ulong(longchs aa, struct geometry G) {
545 return (aa.c * G.cylindersize + aa.h * G.sectors + aa.s - 1);
22853e4a
KZ
546}
547
548static unsigned long
37b94458 549chs_to_ulong(chs a, struct geometry G) {
7eda085c 550 return longchs_to_ulong(chs_to_longchs(a), G);
fd6b7a7f 551}
22853e4a 552#endif
fd6b7a7f 553
22853e4a 554static int
37b94458 555is_equal_chs(chs a, chs b) {
fd6b7a7f
KZ
556 return (a.h == b.h && a.s == b.s && a.c == b.c);
557}
558
22853e4a 559static int
37b94458 560chs_ok(chs a, char *v, char *w) {
fd6b7a7f
KZ
561 longchs aa = chs_to_longchs(a);
562 int ret = 1;
563
564 if (is_equal_chs(a, zero_chs))
37b94458 565 return 1;
7eda085c 566 if (B.heads && aa.h >= B.heads) {
4a01477b 567 my_warn(_("%s of partition %s has impossible value for head: "
37b94458 568 "%lu (should be in 0-%lu)\n"), w, v, aa.h, B.heads - 1);
fd6b7a7f
KZ
569 ret = 0;
570 }
7eda085c 571 if (B.sectors && (aa.s == 0 || aa.s > B.sectors)) {
4a01477b 572 my_warn(_("%s of partition %s has impossible value for sector: "
37b94458 573 "%lu (should be in 1-%lu)\n"), w, v, aa.s, B.sectors);
fd6b7a7f
KZ
574 ret = 0;
575 }
7eda085c 576 if (B.cylinders && aa.c >= B.cylinders) {
4a01477b 577 my_warn(_("%s of partition %s has impossible value for cylinders: "
37b94458 578 "%lu (should be in 0-%lu)\n"), w, v, aa.c, B.cylinders - 1);
fd6b7a7f
KZ
579 ret = 0;
580 }
581 return ret;
582}
583
584/*
585 * D. About system Ids
586 */
587
588#define EMPTY_PARTITION 0
589#define EXTENDED_PARTITION 5
2b6fc908 590#define WIN98_EXTENDED 0x0f
fd6b7a7f
KZ
591#define DM6_AUX1PARTITION 0x51
592#define DM6_AUX3PARTITION 0x53
2b6fc908
KZ
593#define DM6_PARTITION 0x54
594#define EZD_PARTITION 0x55
fd6b7a7f
KZ
595#define LINUX_SWAP 0x82
596#define LINUX_NATIVE 0x83
597#define LINUX_EXTENDED 0x85
2b6fc908 598#define BSD_PARTITION 0xa5
e8f26419 599#define NETBSD_PARTITION 0xa9
fd6b7a7f 600
7eda085c 601/* List of partition types now in i386_sys_types.c */
fd6b7a7f 602
22853e4a 603static const char *
fd6b7a7f
KZ
604sysname(unsigned char type) {
605 struct systypes *s;
606
7eda085c 607 for (s = i386_sys_types; s->name; s++)
37b94458
KZ
608 if (s->type == type)
609 return _(s->name);
7eda085c 610 return _("Unknown");
fd6b7a7f
KZ
611}
612
22853e4a 613static void
fd6b7a7f
KZ
614list_types(void) {
615 struct systypes *s;
616
7eda085c
KZ
617 printf(_("Id Name\n\n"));
618 for (s = i386_sys_types; s->name; s++)
37b94458 619 printf("%2x %s\n", s->type, _(s->name));
fd6b7a7f
KZ
620}
621
22853e4a 622static int
fd6b7a7f 623is_extended(unsigned char type) {
37b94458
KZ
624 return (type == EXTENDED_PARTITION
625 || type == LINUX_EXTENDED || type == WIN98_EXTENDED);
2b6fc908
KZ
626}
627
22853e4a 628static int
2b6fc908 629is_bsd(unsigned char type) {
37b94458 630 return (type == BSD_PARTITION || type == NETBSD_PARTITION);
fd6b7a7f
KZ
631}
632
633/*
634 * E. About partitions
635 */
636
637/* MS/DOS partition */
638
639struct partition {
37b94458 640 unsigned char bootable; /* 0 or 0x80 */
fd6b7a7f
KZ
641 chs begin_chs;
642 unsigned char sys_type;
643 chs end_chs;
644 unsigned int start_sect; /* starting sector counting from 0 */
0b0bb920 645 unsigned int nr_sects; /* nr of sectors in partition */
9df2ac60 646} __attribute__ ((packed));
fd6b7a7f
KZ
647
648/* Unfortunately, partitions are not aligned, and non-Intel machines
649 are unhappy with non-aligned integers. So, we need a copy by hand. */
22853e4a 650static int
fd6b7a7f
KZ
651copy_to_int(unsigned char *cp) {
652 unsigned int m;
653
654 m = *cp++;
655 m += (*cp++ << 8);
656 m += (*cp++ << 16);
657 m += (*cp++ << 24);
658 return m;
659}
660
22853e4a 661static void
fd6b7a7f 662copy_from_int(int m, char *cp) {
37b94458
KZ
663 *cp++ = (m & 0xff);
664 m >>= 8;
665 *cp++ = (m & 0xff);
666 m >>= 8;
667 *cp++ = (m & 0xff);
668 m >>= 8;
fd6b7a7f
KZ
669 *cp++ = (m & 0xff);
670}
671
22853e4a 672static void
fd6b7a7f
KZ
673copy_to_part(char *cp, struct partition *p) {
674 p->bootable = *cp++;
675 p->begin_chs.h = *cp++;
676 p->begin_chs.s = *cp++;
677 p->begin_chs.c = *cp++;
678 p->sys_type = *cp++;
679 p->end_chs.h = *cp++;
680 p->end_chs.s = *cp++;
681 p->end_chs.c = *cp++;
37b94458
KZ
682 p->start_sect = copy_to_int((unsigned char *)cp);
683 p->nr_sects = copy_to_int((unsigned char *)cp + 4);
fd6b7a7f
KZ
684}
685
22853e4a 686static void
fd6b7a7f
KZ
687copy_from_part(struct partition *p, char *cp) {
688 *cp++ = p->bootable;
689 *cp++ = p->begin_chs.h;
690 *cp++ = p->begin_chs.s;
691 *cp++ = p->begin_chs.c;
692 *cp++ = p->sys_type;
693 *cp++ = p->end_chs.h;
694 *cp++ = p->end_chs.s;
695 *cp++ = p->end_chs.c;
696 copy_from_int(p->start_sect, cp);
37b94458 697 copy_from_int(p->nr_sects, cp + 4);
fd6b7a7f
KZ
698}
699
700/* Roughly speaking, Linux doesn't use any of the above fields except
701 for partition type, start sector and number of sectors. (However,
702 see also linux/drivers/scsi/fdomain.c.)
703 The only way partition type is used (in the kernel) is the comparison
704 for equality with EXTENDED_PARTITION (and these Disk Manager types). */
705
706struct part_desc {
6c709b57
PU
707 unsigned long long start;
708 unsigned long long size;
709 unsigned long long sector, offset; /* disk location of this info */
fd6b7a7f 710 struct partition p;
37b94458 711 struct part_desc *ep; /* extended partition containing this one */
2b6fc908
KZ
712 int ptype;
713#define DOS_TYPE 0
714#define BSD_TYPE 1
fd6b7a7f
KZ
715} zero_part_desc;
716
22853e4a 717static struct part_desc *
fd6b7a7f
KZ
718outer_extended_partition(struct part_desc *p) {
719 while (p->ep)
37b94458 720 p = p->ep;
fd6b7a7f
KZ
721 return p;
722}
723
22853e4a 724static int
fd6b7a7f
KZ
725is_parent(struct part_desc *pp, struct part_desc *p) {
726 while (p) {
727 if (pp == p)
37b94458 728 return 1;
fd6b7a7f
KZ
729 p = p->ep;
730 }
731 return 0;
732}
733
734struct disk_desc {
e8f26419 735 struct part_desc partitions[512];
fd6b7a7f
KZ
736 int partno;
737} oldp, newp;
738
739/* determine where on the disk this information goes */
22853e4a 740static void
fd6b7a7f
KZ
741add_sector_and_offset(struct disk_desc *z) {
742 int pno;
743 struct part_desc *p;
744
745 for (pno = 0; pno < z->partno; pno++) {
746 p = &(z->partitions[pno]);
37b94458 747 p->offset = 0x1be + (pno % 4) * sizeof(struct partition);
fd6b7a7f
KZ
748 p->sector = (p->ep ? p->ep->start : 0);
749 }
750}
751
752/* tell the kernel to reread the partition tables */
22853e4a 753static int
7eda085c 754reread_ioctl(int fd) {
6b0054a2
ST
755#ifdef BLKRRPART
756 if (ioctl(fd, BLKRRPART))
757#else
758 errno = ENOSYS;
759#endif
760 {
628e3019
FB
761 /* perror might change errno */
762 int err = errno;
763
fd6b7a7f 764 perror("BLKRRPART");
d162fcb5
KZ
765
766 /* 2.6.8 returns EIO for a zero table */
628e3019 767 if (err == EBUSY)
37b94458 768 return -1;
fd6b7a7f
KZ
769 }
770 return 0;
771}
772
773/* reread after writing */
e82810c6 774static int
fd6b7a7f 775reread_disk_partition(char *dev, int fd) {
7eda085c 776 printf(_("Re-reading the partition table ...\n"));
fd6b7a7f
KZ
777 fflush(stdout);
778 sync();
fd6b7a7f 779
4e4a25c0 780 if (reread_ioctl(fd) && is_blkdev(fd)) {
66d28be8 781 warnx(_("The command to re-read the partition table failed.\n"
4e4a25c0
DB
782 "Run partprobe(8), kpartx(8) or reboot your system now,\n"
783 "before using mkfs\n"));
37b94458 784 return 0;
e82810c6 785 }
fd6b7a7f 786
e9070942 787 if (fsync(fd) || close(fd)) {
37b94458 788 perror(dev);
66d28be8 789 warnx(_("Error closing %s\n"), dev);
37b94458 790 return 0;
fd6b7a7f
KZ
791 }
792 printf("\n");
e82810c6
AG
793
794 return 1;
fd6b7a7f
KZ
795}
796
797/* find Linux name of this partition, assuming that it will have a name */
22853e4a 798static int
fd6b7a7f
KZ
799index_to_linux(int pno, struct disk_desc *z) {
800 int i, ct = 1;
801 struct part_desc *p = &(z->partitions[0]);
37b94458 802 for (i = 0; i < pno; i++, p++)
c129767e 803 if (i < 4 || (p->size > 0 && !is_extended(p->p.sys_type)))
37b94458 804 ct++;
fd6b7a7f
KZ
805 return ct;
806}
807
22853e4a 808static int
fd6b7a7f
KZ
809linux_to_index(int lpno, struct disk_desc *z) {
810 int i, ct = 0;
811 struct part_desc *p = &(z->partitions[0]);
37b94458
KZ
812 for (i = 0; i < z->partno && ct < lpno; i++, p++)
813 if ((i < 4 || (p->size > 0 && !is_extended(p->p.sys_type)))
814 && ++ct == lpno)
815 return i;
fd6b7a7f
KZ
816 return -1;
817}
818
22853e4a 819static int
fd6b7a7f
KZ
820asc_to_index(char *pnam, struct disk_desc *z) {
821 int pnum, pno;
822
823 if (*pnam == '#') {
37b94458 824 pno = atoi(pnam + 1);
fd6b7a7f
KZ
825 } else {
826 pnum = atoi(pnam);
827 pno = linux_to_index(pnum, z);
828 }
829 if (!(pno >= 0 && pno < z->partno))
109dbc4f 830 errx(EXIT_FAILURE, _("%s: no such partition\n"), pnam);
fd6b7a7f
KZ
831 return pno;
832}
833
834/*
835 * List partitions - in terms of sectors, blocks or cylinders
836 */
837#define F_SECTOR 1
838#define F_BLOCK 2
839#define F_CYLINDER 3
840#define F_MEGABYTE 4
841
842int default_format = F_MEGABYTE;
843int specified_format = 0;
844int show_extended = 0;
845int one_only = 0;
846int one_only_pno;
847int increment = 0;
848
22853e4a 849static void
fd6b7a7f 850set_format(char c) {
37b94458
KZ
851 switch (c) {
852 default:
66d28be8 853 warnx(_("unrecognized format - using sectors\n"));
7068841a 854 /* fallthrough */
37b94458
KZ
855 case 'S':
856 specified_format = F_SECTOR;
857 break;
858 case 'B':
859 specified_format = F_BLOCK;
860 break;
861 case 'C':
862 specified_format = F_CYLINDER;
863 break;
864 case 'M':
865 specified_format = F_MEGABYTE;
866 break;
fd6b7a7f
KZ
867 }
868}
869
22853e4a 870static unsigned long
fd6b7a7f 871unitsize(int format) {
7eda085c 872 default_format = (B.cylindersize ? F_CYLINDER : F_MEGABYTE);
fd6b7a7f 873 if (!format && !(format = specified_format))
37b94458 874 format = default_format;
fd6b7a7f 875
37b94458
KZ
876 switch (format) {
877 default:
878 case F_CYLINDER:
c129767e 879 if (B.cylindersize)
37b94458
KZ
880 return B.cylindersize;
881 case F_SECTOR:
fd6b7a7f 882 return 1;
37b94458 883 case F_BLOCK:
fd6b7a7f 884 return 2;
37b94458 885 case F_MEGABYTE:
fd6b7a7f
KZ
886 return 2048;
887 }
888}
889
c4730f10 890static unsigned long long
fd6b7a7f 891get_disksize(int format) {
dfb536c3 892 if (B.total_size && leave_last)
37b94458
KZ
893 /* don't use last cylinder (--leave-last option) */
894 return (B.total_size - B.cylindersize) / unitsize(format);
dfb536c3
KZ
895
896 return B.total_size / unitsize(format);
fd6b7a7f
KZ
897}
898
22853e4a 899static void
7eda085c 900out_partition_header(char *dev, int format, struct geometry G) {
fd6b7a7f 901 if (dump) {
1f1614f6
KZ
902 printf("# partition table of %s\n", dev);
903 printf("unit: sectors\n\n");
fd6b7a7f
KZ
904 return;
905 }
906
7eda085c 907 default_format = (G.cylindersize ? F_CYLINDER : F_MEGABYTE);
fd6b7a7f 908 if (!format && !(format = specified_format))
37b94458 909 format = default_format;
fd6b7a7f 910
37b94458
KZ
911 switch (format) {
912 default:
66d28be8 913 warnx(_("unimplemented format - using %s\n"),
37b94458
KZ
914 G.cylindersize ? _("cylinders") : _("sectors"));
915 case F_CYLINDER:
7eda085c 916 if (G.cylindersize) {
37b94458
KZ
917 printf(_("Units = cylinders of %lu bytes, blocks of 1024 bytes"
918 ", counting from %d\n\n"), G.cylindersize << 9, increment);
be350fb9 919 printf(_(" Device Boot Start End #cyls #blocks Id System\n"));
fd6b7a7f
KZ
920 break;
921 }
922 /* fall through */
37b94458 923 case F_SECTOR:
7eda085c 924 printf(_("Units = sectors of 512 bytes, counting from %d\n\n"),
fd6b7a7f 925 increment);
ffc43748 926 printf(_(" Device Boot Start End #sectors Id System\n"));
fd6b7a7f 927 break;
37b94458 928 case F_BLOCK:
7eda085c 929 printf(_("Units = blocks of 1024 bytes, counting from %d\n\n"),
fd6b7a7f 930 increment);
ffc43748 931 printf(_(" Device Boot Start End #blocks Id System\n"));
fd6b7a7f 932 break;
37b94458 933 case F_MEGABYTE:
df1dddf9 934 printf(_("Units = mebibytes of 1048576 bytes, blocks of 1024 bytes"
37b94458 935 ", counting from %d\n\n"), increment);
be350fb9 936 printf(_(" Device Boot Start End MiB #blocks Id System\n"));
fd6b7a7f
KZ
937 break;
938 }
939}
940
941static void
6c709b57
PU
942out_rounddown(int width, unsigned long long n, unsigned long unit, int inc) {
943 printf("%*llu", width, inc + n / unit);
fd6b7a7f 944 if (unit != 1)
37b94458 945 putchar((n % unit) ? '+' : ' ');
fd6b7a7f
KZ
946 putchar(' ');
947}
948
949static void
6c709b57
PU
950out_roundup(int width, unsigned long long n, unsigned long unit, int inc) {
951 if (n == (unsigned long long)(-1))
37b94458 952 printf("%*s", width, "-");
fd6b7a7f 953 else
6c709b57 954 printf("%*llu", width, inc + n / unit);
fd6b7a7f 955 if (unit != 1)
37b94458 956 putchar(((n + 1) % unit) ? '-' : ' ');
fd6b7a7f
KZ
957 putchar(' ');
958}
959
960static void
6c709b57
PU
961out_roundup_size(int width, unsigned long long n, unsigned long unit) {
962 printf("%*llu", width, (n + unit - 1) / unit);
fd6b7a7f 963 if (unit != 1)
37b94458 964 putchar((n % unit) ? '-' : ' ');
fd6b7a7f
KZ
965 putchar(' ');
966}
967
ffc43748
KZ
968static struct geometry
969get_fdisk_geometry_one(struct part_desc *p) {
970 struct geometry G;
971
f27bec29 972 memset(&G, 0, sizeof(struct geometry));
7eda085c
KZ
973 chs b = p->p.end_chs;
974 longchs bb = chs_to_longchs(b);
37b94458 975 G.heads = bb.h + 1;
ffc43748 976 G.sectors = bb.s;
37b94458 977 G.cylindersize = G.heads * G.sectors;
ffc43748
KZ
978 return G;
979}
980
981static int
982get_fdisk_geometry(struct disk_desc *z) {
983 struct part_desc *p;
984 int pno, agree;
985 struct geometry G0, G;
986
f27bec29 987 memset(&G0, 0, sizeof(struct geometry));
ffc43748 988 agree = 0;
37b94458 989 for (pno = 0; pno < z->partno; pno++) {
ffc43748
KZ
990 p = &(z->partitions[pno]);
991 if (p->size != 0 && p->p.sys_type != 0) {
992 G = get_fdisk_geometry_one(p);
993 if (!G0.heads) {
994 G0 = G;
995 agree = 1;
996 } else if (G.heads != G0.heads || G.sectors != G0.sectors) {
997 agree = 0;
998 break;
999 }
1000 }
1001 }
1002 F = (agree ? G0 : B);
7eda085c
KZ
1003 return (F.sectors != B.sectors || F.heads != B.heads);
1004}
1005
22853e4a 1006static void
7eda085c
KZ
1007out_partition(char *dev, int format, struct part_desc *p,
1008 struct disk_desc *z, struct geometry G) {
6c709b57 1009 unsigned long long start, end, size;
fd6b7a7f
KZ
1010 int pno, lpno;
1011
1012 if (!format && !(format = specified_format))
37b94458 1013 format = default_format;
fd6b7a7f 1014
37b94458
KZ
1015 pno = p - &(z->partitions[0]); /* our index */
1016 lpno = index_to_linux(pno, z); /* name of next one that has a name */
1017 if (pno == linux_to_index(lpno, z)) /* was that us? */
1018 printf("%s", partname(dev, lpno, 10)); /* yes */
c129767e 1019 else if (show_extended)
37b94458 1020 printf(" - ");
fd6b7a7f 1021 else
37b94458 1022 return;
fd6b7a7f
KZ
1023 putchar(dump ? ':' : ' ');
1024
1025 start = p->start;
1026 end = p->start + p->size - 1;
1027 size = p->size;
1028
1029 if (dump) {
6c709b57
PU
1030 printf(" start=%9llu", start);
1031 printf(", size=%9llu", size);
2b6fc908 1032 if (p->ptype == DOS_TYPE) {
eb63b9b8 1033 printf(", Id=%2x", p->p.sys_type);
2b6fc908 1034 if (p->p.bootable == 0x80)
1f1614f6 1035 printf(", bootable");
2b6fc908 1036 }
fd6b7a7f
KZ
1037 printf("\n");
1038 return;
1039 }
1040
c129767e 1041 if (p->ptype != DOS_TYPE || p->p.bootable == 0)
37b94458 1042 printf(" ");
c129767e 1043 else if (p->p.bootable == 0x80)
37b94458 1044 printf(" * ");
fd6b7a7f 1045 else
37b94458 1046 printf(" ? "); /* garbage */
fd6b7a7f 1047
37b94458
KZ
1048 switch (format) {
1049 case F_CYLINDER:
7eda085c
KZ
1050 if (G.cylindersize) {
1051 out_rounddown(6, start, G.cylindersize, increment);
1052 out_roundup(6, end, G.cylindersize, increment);
1053 out_roundup_size(6, size, G.cylindersize);
ffc43748 1054 out_rounddown(9, size, 2, 0);
fd6b7a7f
KZ
1055 break;
1056 }
1057 /* fall through */
37b94458
KZ
1058 default:
1059 case F_SECTOR:
fd6b7a7f
KZ
1060 out_rounddown(9, start, 1, increment);
1061 out_roundup(9, end, 1, increment);
ffc43748 1062 out_rounddown(10, size, 1, 0);
fd6b7a7f 1063 break;
37b94458 1064 case F_BLOCK:
fd6b7a7f
KZ
1065#if 0
1066 printf("%8lu,%3lu ",
37b94458 1067 p->sector / 2, ((p->sector & 1) ? 512 : 0) + p->offset);
fd6b7a7f
KZ
1068#endif
1069 out_rounddown(8, start, 2, increment);
1070 out_roundup(8, end, 2, increment);
ffc43748 1071 out_rounddown(9, size, 2, 0);
fd6b7a7f 1072 break;
37b94458 1073 case F_MEGABYTE:
fd6b7a7f
KZ
1074 out_rounddown(5, start, 2048, increment);
1075 out_roundup(5, end, 2048, increment);
1076 out_roundup_size(5, size, 2048);
ffc43748 1077 out_rounddown(9, size, 2, 0);
fd6b7a7f
KZ
1078 break;
1079 }
2b6fc908 1080 if (p->ptype == DOS_TYPE) {
37b94458 1081 printf(" %2x %s\n", p->p.sys_type, sysname(p->p.sys_type));
2b6fc908
KZ
1082 } else {
1083 printf("\n");
1084 }
fd6b7a7f
KZ
1085
1086 /* Is chs as we expect? */
2b6fc908 1087 if (!quiet && p->ptype == DOS_TYPE) {
fd6b7a7f
KZ
1088 chs a, b;
1089 longchs aa, bb;
37b94458 1090 a = (size ? ulong_to_chs(start, G) : zero_chs);
fd6b7a7f
KZ
1091 b = p->p.begin_chs;
1092 aa = chs_to_longchs(a);
1093 bb = chs_to_longchs(b);
c129767e 1094 if (a.s && !is_equal_chs(a, b))
66d28be8 1095 warnx(_("\t\tstart: (c,h,s) expected (%ld,%ld,%ld) found (%ld,%ld,%ld)\n"),
37b94458
KZ
1096 aa.c, aa.h, aa.s, bb.c, bb.h, bb.s);
1097 a = (size ? ulong_to_chs(end, G) : zero_chs);
fd6b7a7f
KZ
1098 b = p->p.end_chs;
1099 aa = chs_to_longchs(a);
1100 bb = chs_to_longchs(b);
c129767e 1101 if (a.s && !is_equal_chs(a, b))
66d28be8 1102 warnx(_("\t\tend: (c,h,s) expected (%ld,%ld,%ld) found (%ld,%ld,%ld)\n"),
37b94458 1103 aa.c, aa.h, aa.s, bb.c, bb.h, bb.s);
c129767e 1104 if (G.cylinders && G.cylinders < 1024 && bb.c > G.cylinders)
66d28be8 1105 warnx(_("partition ends on cylinder %ld, beyond the end of the disk\n"),
37b94458 1106 bb.c);
fd6b7a7f
KZ
1107 }
1108}
1109
22853e4a 1110static void
fd6b7a7f
KZ
1111out_partitions(char *dev, struct disk_desc *z) {
1112 int pno, format = 0;
1113
1114 if (z->partno == 0)
66d28be8 1115 warnx(_("No partitions found\n"));
fd6b7a7f 1116 else {
ffc43748 1117 if (get_fdisk_geometry(z) && !dump) {
66d28be8 1118 warnx(_("Warning: The partition table looks like it was made\n"
37b94458
KZ
1119 " for C/H/S=*/%ld/%ld (instead of %ld/%ld/%ld).\n"
1120 "For this listing I'll assume that geometry.\n"),
1121 F.heads, F.sectors, B.cylinders, B.heads, B.sectors);
eb63b9b8 1122 }
ffc43748 1123
7eda085c 1124 out_partition_header(dev, format, F);
37b94458 1125 for (pno = 0; pno < z->partno; pno++) {
7eda085c 1126 out_partition(dev, format, &(z->partitions[pno]), z, F);
37b94458
KZ
1127 if (show_extended && pno % 4 == 3)
1128 printf("\n");
fd6b7a7f
KZ
1129 }
1130 }
1131}
1132
1133static int
1134disj(struct part_desc *p, struct part_desc *q) {
37b94458
KZ
1135 return ((p->start + p->size <= q->start)
1136 || (is_extended(p->p.sys_type)
1137 && q->start + q->size <= p->start + p->size));
fd6b7a7f
KZ
1138}
1139
22853e4a 1140static char *
fd6b7a7f
KZ
1141pnumber(struct part_desc *p, struct disk_desc *z) {
1142 static char buf[20];
1143 int this, next;
1144 struct part_desc *p0 = &(z->partitions[0]);
1145
37b94458
KZ
1146 this = index_to_linux(p - p0, z);
1147 next = index_to_linux(p - p0 + 1, z);
fd6b7a7f
KZ
1148
1149 if (next > this)
37b94458 1150 sprintf(buf, "%d", this);
fd6b7a7f 1151 else
37b94458 1152 sprintf(buf, "[%d]", this);
fd6b7a7f
KZ
1153 return buf;
1154}
1155
22853e4a 1156static int
4310e47a 1157partitions_ok(int fd, struct disk_desc *z) {
fd6b7a7f
KZ
1158 struct part_desc *partitions = &(z->partitions[0]), *p, *q;
1159 int partno = z->partno;
1160
1161#define PNO(p) pnumber(p, z)
1162
1163 /* Have at least 4 partitions been defined? */
1164 if (partno < 4) {
37b94458 1165 if (!partno)
109dbc4f 1166 errx(EXIT_FAILURE, _("no partition table present."));
37b94458 1167 else
109dbc4f 1168 errx(EXIT_FAILURE, _("strange, only %d partitions defined."), partno);
37b94458 1169 return 0;
fd6b7a7f
KZ
1170 }
1171
1172 /* Are the partitions of size 0 marked empty?
1173 And do they have start = 0? And bootable = 0? */
1174 for (p = partitions; p - partitions < partno; p++)
37b94458
KZ
1175 if (p->size == 0) {
1176 if (p->p.sys_type != EMPTY_PARTITION)
be350fb9 1177 my_warn(_("Warning: partition %s has size 0 but is not marked Empty\n"),
37b94458
KZ
1178 PNO(p));
1179 else if (p->p.bootable != 0)
1180 my_warn(_("Warning: partition %s has size 0 and is bootable\n"),
1181 PNO(p));
1182 else if (p->p.start_sect != 0)
be350fb9 1183 my_warn(_("Warning: partition %s has size 0 and nonzero start\n"),
37b94458
KZ
1184 PNO(p));
1185 /* all this is probably harmless, no error return */
1186 }
fd6b7a7f
KZ
1187
1188 /* Are the logical partitions contained in their extended partitions? */
37b94458
KZ
1189 for (p = partitions + 4; p < partitions + partno; p++)
1190 if (p->ptype == DOS_TYPE)
1191 if (p->size && !is_extended(p->p.sys_type)) {
1192 q = p->ep;
1193 if (p->start < q->start
1194 || p->start + p->size > q->start + q->size) {
850ca1a8
BS
1195 my_warn(_("Warning: partition %s is not contained in "
1196 "partition %s\n"), PNO(p), PNO(q));
37b94458
KZ
1197 return 0;
1198 }
1199 }
fd6b7a7f
KZ
1200
1201 /* Are the data partitions mutually disjoint? */
37b94458
KZ
1202 for (p = partitions; p < partitions + partno; p++)
1203 if (p->size && !is_extended(p->p.sys_type))
1204 for (q = p + 1; q < partitions + partno; q++)
1205 if (q->size && !is_extended(q->p.sys_type))
1206 if (!((p->start > q->start) ? disj(q, p) : disj(p, q))) {
850ca1a8
BS
1207 my_warn(_("Warning: partitions %s and %s overlap\n"),
1208 PNO(p), PNO(q));
37b94458
KZ
1209 return 0;
1210 }
fd6b7a7f 1211
2b6fc908
KZ
1212 /* Are the data partitions and the extended partition
1213 table sectors disjoint? */
37b94458
KZ
1214 for (p = partitions; p < partitions + partno; p++)
1215 if (p->size && !is_extended(p->p.sys_type))
1216 for (q = partitions; q < partitions + partno; q++)
1217 if (is_extended(q->p.sys_type))
1218 if (p->start <= q->start && p->start + p->size > q->start) {
1219 my_warn(_("Warning: partition %s contains part of "
6c709b57 1220 "the partition table (sector %llu),\n"
37b94458
KZ
1221 "and will destroy it when filled\n"),
1222 PNO(p), q->start);
1223 return 0;
1224 }
2b6fc908 1225
fd6b7a7f 1226 /* Do they start past zero and end before end-of-disk? */
37b94458 1227 {
c4730f10 1228 unsigned long long ds = get_disksize(F_SECTOR);
37b94458
KZ
1229 for (p = partitions; p < partitions + partno; p++)
1230 if (p->size) {
1231 if (p->start == 0) {
1232 my_warn(_("Warning: partition %s starts at sector 0\n"),
1233 PNO(p));
1234 return 0;
1235 }
1236 if (p->size && p->start + p->size > ds) {
be350fb9 1237 my_warn(_("Warning: partition %s extends past end of disk\n"),
37b94458
KZ
1238 PNO(p));
1239 return 0;
1240 }
1241 }
fd6b7a7f
KZ
1242 }
1243
4310e47a
PU
1244 int sector_size;
1245 if (blkdev_get_sector_size(fd, &sector_size) == -1)
1246 sector_size = DEFAULT_SECTOR_SIZE;
1247
1248 /* Is the size of partitions less than 2^32 sectors limit? */
1249 for (p = partitions; p < partitions + partno; p++)
1250 if (p->size > UINT_MAX) {
1251 unsigned long long bytes = p->size * sector_size;
1252 int giga = bytes / 1000000000;
1253 int hectogiga = (giga + 50) / 100;
1254 my_warn(_("Warning: partition %s has size %d.%d TB (%llu bytes),\n"
1255 "which is larger than the %llu bytes limit imposed\n"
1256 "by the DOS partition table for %d-byte sectors\n"),
1257 PNO(p), hectogiga / 10, hectogiga % 10,
1258 bytes,
1259 (unsigned long long) UINT_MAX * sector_size,
1260 sector_size);
1261 return 0;
1262 }
1263
1264 /* Do the partitions start below the 2^32 sectors limit? */
1265 for (p = partitions; p < partitions + partno; p++)
1266 if (p->start > UINT_MAX) {
1267 unsigned long long bytes = p->start * sector_size;
1268 int giga = bytes / 1000000000;
1269 int hectogiga = (giga + 50) / 100;
1270 my_warn(_("Warning: partition %s starts at sector %llu (%d.%d TB for %d-byte sectors),\n"
1271 "which exceeds the DOS partition table limit of %llu sectors\n"),
1272 PNO(p),
1273 p->start,
1274 hectogiga / 10,
1275 hectogiga % 10,
1276 sector_size,
1277 (unsigned long long) UINT_MAX);
1278 return 0;
1279 }
1280
fd6b7a7f
KZ
1281 /* At most one chain of DOS extended partitions ? */
1282 /* It seems that the OS/2 fdisk has the additional requirement
1283 that the extended partition must be the fourth one */
37b94458
KZ
1284 {
1285 int ect = 0;
1286 for (p = partitions; p < partitions + 4; p++)
1287 if (p->p.sys_type == EXTENDED_PARTITION)
1288 ect++;
1289 if (ect > 1 && !Linux) {
be350fb9
BS
1290 my_warn(_("Among the primary partitions, at most one can be extended\n"
1291 " (although this is not a problem under Linux)\n"));
37b94458
KZ
1292 return 0;
1293 }
fd6b7a7f
KZ
1294 }
1295
1296 /*
1297 * Do all partitions start at a cylinder boundary ?
1298 * (this is not required for Linux)
1299 * The first partition starts after MBR.
1300 * Logical partitions start slightly after the containing extended partn.
1301 */
cc393e38 1302 if (B.cylindersize && !Linux) {
37b94458
KZ
1303 for (p = partitions; p < partitions + partno; p++)
1304 if (p->size) {
1305 if (p->start % B.cylindersize != 0
1306 && (!p->ep
1307 || p->start / B.cylindersize !=
1308 p->ep->start / B.cylindersize)
1309 && (p->p.start_sect >= B.cylindersize)) {
1310 my_warn(_("Warning: partition %s does not start "
1311 "at a cylinder boundary\n"), PNO(p));
26f0feac
PU
1312 if (specified_format == F_CYLINDER)
1313 return 0;
37b94458
KZ
1314 }
1315 if ((p->start + p->size) % B.cylindersize) {
1316 my_warn(_("Warning: partition %s does not end "
1317 "at a cylinder boundary\n"), PNO(p));
26f0feac
PU
1318 if (specified_format == F_CYLINDER)
1319 return 0;
37b94458
KZ
1320 }
1321 }
fd6b7a7f
KZ
1322 }
1323
1324 /* Usually, one can boot only from primary partitions. */
1325 /* In fact, from a unique one only. */
1326 /* do not warn about bootable extended partitions -
1327 often LILO is there */
37b94458
KZ
1328 {
1329 int pno = -1;
1330 for (p = partitions; p < partitions + partno; p++)
1331 if (p->p.bootable) {
1332 if (pno == -1)
1333 pno = p - partitions;
1334 else if (p - partitions < 4) {
be350fb9
BS
1335 my_warn(_("Warning: more than one primary partition is marked "
1336 "bootable (active)\n"
1337 "This does not matter for LILO, but the DOS MBR will "
1338 "not boot this disk.\n"));
37b94458
KZ
1339 break;
1340 }
1341 if (p - partitions >= 4) {
be350fb9
BS
1342 my_warn(_("Warning: usually one can boot from primary partitions "
1343 "only\nLILO disregards the `bootable' flag.\n"));
37b94458
KZ
1344 break;
1345 }
1346 }
1347 if (pno == -1 || pno >= 4)
be350fb9
BS
1348 my_warn(_("Warning: no primary partition is marked bootable (active)\n"
1349 "This does not matter for LILO, but the DOS MBR will "
1350 "not boot this disk.\n"));
fd6b7a7f
KZ
1351 }
1352
1353 /* Is chs as we expect? */
37b94458
KZ
1354 for (p = partitions; p < partitions + partno; p++)
1355 if (p->ptype == DOS_TYPE) {
1356 chs a, b;
1357 longchs aa, bb;
1358 a = p->size ? ulong_to_chs(p->start, B) : zero_chs;
1359 b = p->p.begin_chs;
1360 aa = chs_to_longchs(a);
1361 bb = chs_to_longchs(b);
cc393e38 1362 if (!Linux && !chs_ok(b, PNO(p), _("start")))
37b94458
KZ
1363 return 0;
1364 if (a.s && !is_equal_chs(a, b))
be350fb9 1365 my_warn(_("partition %s: start: (c,h,s) expected (%ld,%ld,%ld) found (%ld,%ld,%ld)\n"),
37b94458
KZ
1366 PNO(p), aa.c, aa.h, aa.s, bb.c, bb.h, bb.s);
1367 a = p->size ? ulong_to_chs(p->start + p->size - 1, B) : zero_chs;
1368 b = p->p.end_chs;
1369 aa = chs_to_longchs(a);
1370 bb = chs_to_longchs(b);
cc393e38 1371 if (!Linux && !chs_ok(b, PNO(p), _("end")))
37b94458
KZ
1372 return 0;
1373 if (a.s && !is_equal_chs(a, b))
be350fb9 1374 my_warn(_("partition %s: end: (c,h,s) expected (%ld,%ld,%ld) found (%ld,%ld,%ld)\n"),
37b94458
KZ
1375 PNO(p), aa.c, aa.h, aa.s, bb.c, bb.h, bb.s);
1376 if (B.cylinders && B.cylinders < 1024 && bb.c > B.cylinders)
be350fb9 1377 my_warn(_("partition %s ends on cylinder %ld, beyond the end of the disk\n"),
37b94458
KZ
1378 PNO(p), bb.c);
1379 }
fd6b7a7f
KZ
1380
1381 return 1;
1382
1383#undef PNO
1384}
1385
1386static void
1387extended_partition(char *dev, int fd, struct part_desc *ep, struct disk_desc *z) {
1388 char *cp;
1389 struct sector *s;
6c709b57 1390 unsigned long long start, here, next;
fd6b7a7f
KZ
1391 int i, moretodo = 1;
1392 struct partition p;
1393 struct part_desc *partitions = &(z->partitions[0]);
bdb8757e 1394 size_t pno = z->partno;
fd6b7a7f
KZ
1395
1396 here = start = ep->start;
1397
22853e4a
KZ
1398 if (B.cylindersize && start % B.cylindersize) {
1399 /* This is BAD */
1400 if (DOS_extended) {
1401 here = start -= (start % B.cylindersize);
66d28be8
DB
1402 warnx(_("Warning: shifted start of the extd partition "
1403 "from %lld to %lld\n"
37b94458
KZ
1404 "(For listing purposes only. "
1405 "Do not change its contents.)\n"), ep->start, start);
22853e4a 1406 } else {
66d28be8 1407 warnx(_("Warning: extended partition does not start at a "
37b94458
KZ
1408 "cylinder boundary.\n"
1409 "DOS and Linux will interpret the contents differently.\n"));
22853e4a
KZ
1410 }
1411 }
1412
fd6b7a7f
KZ
1413 while (moretodo) {
1414 moretodo = 0;
1415
1416 if (!(s = get_sector(dev, fd, here)))
1417 break;
1418
1419 if (!msdos_signature(s))
1420 break;
1421
1422 cp = s->data + 0x1be;
1423
37b94458 1424 if (pno + 4 >= ARRAY_SIZE(z->partitions)) {
66d28be8 1425 warnx(_("too many partitions - ignoring those past nr (%ld)\n"),
37b94458 1426 pno - 1);
fd6b7a7f
KZ
1427 break;
1428 }
1429
1430 next = 0;
1431
37b94458 1432 for (i = 0; i < 4; i++, cp += sizeof(struct partition)) {
fd6b7a7f
KZ
1433 partitions[pno].sector = here;
1434 partitions[pno].offset = cp - s->data;
1435 partitions[pno].ep = ep;
37b94458 1436 copy_to_part(cp, &p);
fd6b7a7f 1437 if (is_extended(p.sys_type)) {
7eda085c 1438 partitions[pno].start = start + p.start_sect;
fd6b7a7f 1439 if (next)
66d28be8 1440 warnx(_("tree of partitions?\n"));
7eda085c 1441 else
37b94458 1442 next = partitions[pno].start; /* follow `upper' branch */
fd6b7a7f
KZ
1443 moretodo = 1;
1444 } else {
1445 partitions[pno].start = here + p.start_sect;
1446 }
1447 partitions[pno].size = p.nr_sects;
2b6fc908
KZ
1448 partitions[pno].ptype = DOS_TYPE;
1449 partitions[pno].p = p;
1450 pno++;
ffc43748 1451 }
fd6b7a7f
KZ
1452 here = next;
1453 }
1454
1455 z->partno = pno;
1456}
1457
2b6fc908 1458#define BSD_DISKMAGIC (0x82564557UL)
63cccae4 1459#define BSD_MAXPARTITIONS 16
ffc43748 1460#define BSD_FS_UNUSED 0
2b6fc908
KZ
1461typedef unsigned char u8;
1462typedef unsigned short u16;
1463typedef unsigned int u32;
1464struct bsd_disklabel {
37b94458
KZ
1465 u32 d_magic;
1466 char d_junk1[4];
1467 char d_typename[16];
1468 char d_packname[16];
1469 char d_junk2[92];
1470 u32 d_magic2;
1471 char d_junk3[2];
1472 u16 d_npartitions; /* number of partitions in following */
1473 char d_junk4[8];
1474 struct bsd_partition { /* the partition table */
1475 u32 p_size; /* number of sectors in partition */
1476 u32 p_offset; /* starting sector */
1477 u32 p_fsize; /* filesystem basic fragment size */
1478 u8 p_fstype; /* filesystem type, see below */
1479 u8 p_frag; /* filesystem fragments per block */
1480 u16 p_cpg; /* filesystem cylinders per group */
1481 } d_partitions[BSD_MAXPARTITIONS]; /* actually may be more */
2b6fc908
KZ
1482};
1483
1484static void
1485bsd_partition(char *dev, int fd, struct part_desc *ep, struct disk_desc *z) {
37b94458
KZ
1486 struct bsd_disklabel *l;
1487 struct bsd_partition *bp, *bp0;
6c709b57 1488 unsigned long long start = ep->start;
37b94458
KZ
1489 struct sector *s;
1490 struct part_desc *partitions = &(z->partitions[0]);
1491 size_t pno = z->partno;
2b6fc908 1492
37b94458
KZ
1493 if (!(s = get_sector(dev, fd, start + 1)))
1494 return;
1495 l = (struct bsd_disklabel *)(s->data);
1496 if (l->d_magic != BSD_DISKMAGIC || l->d_magic2 != BSD_DISKMAGIC)
1497 return;
1498
1499 bp = bp0 = &l->d_partitions[0];
1500 while (bp - bp0 < BSD_MAXPARTITIONS && bp - bp0 < l->d_npartitions) {
1501 if (pno + 1 >= ARRAY_SIZE(z->partitions)) {
66d28be8
DB
1502 warnx(_("too many partitions - ignoring those "
1503 "past nr (%ld)\n"), pno - 1);
37b94458
KZ
1504 break;
1505 }
1506 if (bp->p_fstype != BSD_FS_UNUSED) {
1507 partitions[pno].start = bp->p_offset;
1508 partitions[pno].size = bp->p_size;
1509 partitions[pno].sector = start + 1;
1510 partitions[pno].offset = (char *)bp - (char *)bp0;
1511 partitions[pno].ep = 0;
1512 partitions[pno].ptype = BSD_TYPE;
1513 pno++;
2b6fc908 1514 }
37b94458
KZ
1515 bp++;
1516 }
1517 z->partno = pno;
2b6fc908
KZ
1518}
1519
fd6b7a7f
KZ
1520static int
1521msdos_partition(char *dev, int fd, unsigned long start, struct disk_desc *z) {
1522 int i;
1523 char *cp;
1524 struct partition pt;
1525 struct sector *s;
1526 struct part_desc *partitions = &(z->partitions[0]);
1527 int pno = z->partno;
ca04a95a
ST
1528 int bsd_later = 1;
1529#ifdef __linux__
37b94458 1530 bsd_later = (get_linux_version() >= KERNEL_VERSION(2, 3, 40));
ca04a95a 1531#endif
fd6b7a7f
KZ
1532
1533 if (!(s = get_sector(dev, fd, start)))
1534 return 0;
1535
1536 if (!msdos_signature(s))
1537 return 0;
1538
1539 cp = s->data + 0x1be;
37b94458 1540 copy_to_part(cp, &pt);
fd6b7a7f
KZ
1541
1542 /* If I am not mistaken, recent kernels will hide this from us,
37b94458 1543 so we will never actually see traces of a Disk Manager */
fd6b7a7f
KZ
1544 if (pt.sys_type == DM6_PARTITION
1545 || pt.sys_type == EZD_PARTITION
1546 || pt.sys_type == DM6_AUX1PARTITION
1547 || pt.sys_type == DM6_AUX3PARTITION) {
66d28be8 1548 warnx(_("detected Disk Manager - unable to handle that\n"));
fd6b7a7f
KZ
1549 return 0;
1550 }
bb92c8ea
PU
1551
1552 unsigned int sig = *(unsigned short *)(s->data + 2);
1553 if (sig <= 0x1ae
1554 && *(unsigned short *)(s->data + sig) == 0x55aa
1555 && (1 & *(unsigned char *)(s->data + sig + 2))) {
66d28be8 1556 warnx(_("DM6 signature found - giving up\n"));
37b94458 1557 return 0;
fd6b7a7f
KZ
1558 }
1559
37b94458 1560 for (pno = 0; pno < 4; pno++, cp += sizeof(struct partition)) {
fd6b7a7f
KZ
1561 partitions[pno].sector = start;
1562 partitions[pno].offset = cp - s->data;
37b94458 1563 copy_to_part(cp, &pt);
fd6b7a7f
KZ
1564 partitions[pno].start = start + pt.start_sect;
1565 partitions[pno].size = pt.nr_sects;
1566 partitions[pno].ep = 0;
1567 partitions[pno].p = pt;
1568 }
1569
1570 z->partno = pno;
1571
37b94458 1572 for (i = 0; i < 4; i++) {
fd6b7a7f
KZ
1573 if (is_extended(partitions[i].p.sys_type)) {
1574 if (!partitions[i].size) {
66d28be8 1575 warnx(_("strange..., an extended partition of size 0?\n"));
fd6b7a7f
KZ
1576 continue;
1577 }
1578 extended_partition(dev, fd, &partitions[i], z);
1579 }
22853e4a 1580 if (!bsd_later && is_bsd(partitions[i].p.sys_type)) {
2b6fc908 1581 if (!partitions[i].size) {
66d28be8 1582 warnx(_("strange..., a BSD partition of size 0?\n"));
2b6fc908
KZ
1583 continue;
1584 }
1585 bsd_partition(dev, fd, &partitions[i], z);
1586 }
1587 }
22853e4a
KZ
1588
1589 if (bsd_later) {
37b94458 1590 for (i = 0; i < 4; i++) {
22853e4a
KZ
1591 if (is_bsd(partitions[i].p.sys_type)) {
1592 if (!partitions[i].size) {
66d28be8 1593 warnx(_("strange..., a BSD partition of size 0?\n"));
22853e4a
KZ
1594 continue;
1595 }
1596 bsd_partition(dev, fd, &partitions[i], z);
1597 }
1598 }
1599 }
c64061c9 1600
fd6b7a7f
KZ
1601 return 1;
1602}
1603
1604static int
4dd3383a
SK
1605osf_partition(char *dev __attribute__ ((__unused__)),
1606 int fd __attribute__ ((__unused__)),
1607 unsigned long start __attribute__ ((__unused__)),
37b94458
KZ
1608 struct disk_desc *z __attribute__ ((__unused__))) {
1609 return 0;
fd6b7a7f
KZ
1610}
1611
2b6fc908 1612static int
4dd3383a
SK
1613sun_partition(char *dev __attribute__ ((__unused__)),
1614 int fd __attribute__ ((__unused__)),
1615 unsigned long start __attribute__ ((__unused__)),
37b94458
KZ
1616 struct disk_desc *z __attribute__ ((__unused__))) {
1617 return 0;
2b6fc908
KZ
1618}
1619
1620static int
4dd3383a
SK
1621amiga_partition(char *dev __attribute__ ((__unused__)),
1622 int fd __attribute__ ((__unused__)),
1623 unsigned long start __attribute__ ((__unused__)),
37b94458
KZ
1624 struct disk_desc *z __attribute__ ((__unused__))) {
1625 return 0;
2b6fc908
KZ
1626}
1627
22853e4a 1628static void
fd6b7a7f
KZ
1629get_partitions(char *dev, int fd, struct disk_desc *z) {
1630 z->partno = 0;
1631
2b6fc908
KZ
1632 if (!msdos_partition(dev, fd, 0, z)
1633 && !osf_partition(dev, fd, 0, z)
1634 && !sun_partition(dev, fd, 0, z)
1635 && !amiga_partition(dev, fd, 0, z)) {
66d28be8 1636 warnx(_(" %s: unrecognized partition table type\n"), dev);
fd6b7a7f
KZ
1637 return;
1638 }
1639}
1640
22853e4a 1641static int
fd6b7a7f
KZ
1642write_partitions(char *dev, int fd, struct disk_desc *z) {
1643 struct sector *s;
1644 struct part_desc *partitions = &(z->partitions[0]), *p;
1645 int pno = z->partno;
1646
1647 if (no_write) {
66d28be8 1648 warnx(_("-n flag was given: Nothing changed\n"));
fd6b7a7f
KZ
1649 exit(0);
1650 }
1651
37b94458 1652 for (p = partitions; p < partitions + pno; p++) {
fd6b7a7f 1653 s = get_sector(dev, fd, p->sector);
37b94458
KZ
1654 if (!s)
1655 return 0;
fd6b7a7f 1656 s->to_be_written = 1;
df1dddf9
KZ
1657 if (p->ptype == DOS_TYPE) {
1658 copy_from_part(&(p->p), s->data + p->offset);
1659 s->data[510] = 0x55;
37b94458 1660 s->data[511] = (unsigned char)0xaa;
df1dddf9 1661 }
fd6b7a7f
KZ
1662 }
1663 if (save_sector_file) {
1664 if (!save_sectors(dev, fd)) {
109dbc4f 1665 errx(EXIT_FAILURE, _("Failed saving the old sectors - aborting\n"));
fd6b7a7f
KZ
1666 return 0;
1667 }
1668 }
1669 if (!write_sectors(dev, fd)) {
7eda085c 1670 error(_("Failed writing the partition on %s\n"), dev);
fd6b7a7f
KZ
1671 return 0;
1672 }
5ac78ead
BR
1673 if (fsync(fd)) {
1674 perror(dev);
1675 error(_("Failed writing the partition on %s\n"), dev);
1676 return 0;
1677 }
fd6b7a7f
KZ
1678 return 1;
1679}
1680
1681/*
1682 * F. The standard input
1683 */
1684
1685/*
1686 * Input format:
1687 * <start> <size> <type> <bootable> <c,h,s> <c,h,s>
1688 * Fields are separated by whitespace or comma or semicolon possibly
1689 * followed by whitespace; initial and trailing whitespace is ignored.
1690 * Numbers can be octal, decimal or hexadecimal, decimal is default
1691 * The <c,h,s> parts can (and probably should) be omitted.
1692 * Bootable is specified as [*|-], with as default not-bootable.
1693 * Type is given in hex, without the 0x prefix, or is [E|S|L|X], where
1694 * L (LINUX_NATIVE (83)) is the default, S is LINUX_SWAP (82), and E
1695 * is EXTENDED_PARTITION (5), X is LINUX_EXTENDED (85).
1696 * The default value of start is the first nonassigned sector/cylinder/...
1697 * The default value of size is as much as possible (until next
1698 * partition or end-of-disk).
1699 * .: end of chain of extended partitions.
1700 *
1701 * On interactive input an empty line means: all defaults.
1702 * Otherwise empty lines are ignored.
1703 */
1704
1705int eof, eob;
1706
1707struct dumpfld {
1708 int fldno;
1709 char *fldname;
1710 int is_bool;
1711} dumpflds[] = {
37b94458
KZ
1712 {
1713 0, "start", 0}, {
1714 1, "size", 0}, {
1715 2, "Id", 0}, {
1716 3, "bootable", 1}, {
1717 4, "bh", 0}, {
1718 5, "bs", 0}, {
1719 6, "bc", 0}, {
1720 7, "eh", 0}, {
1721 8, "es", 0}, {
1722 9, "ec", 0}
fd6b7a7f
KZ
1723};
1724
1725/*
1726 * Read a line, split it into fields
1727 *
1728 * (some primitive handwork, but a more elaborate parser seems
1729 * unnecessary)
1730 */
1731#define RD_EOF (-1)
1732#define RD_CMD (-2)
1733
22853e4a 1734static int
934238cd
RD
1735read_stdin(char **fields, char *line, int fieldssize, int linesize) {
1736 char *lp, *ip;
fd6b7a7f
KZ
1737 int c, fno;
1738
1739 /* boolean true and empty string at start */
1740 line[0] = '*';
1741 line[1] = 0;
37b94458
KZ
1742 for (fno = 0; fno < fieldssize; fno++)
1743 fields[fno] = line + 1;
fd6b7a7f
KZ
1744 fno = 0;
1745
1746 /* read a line from stdin */
37b94458 1747 lp = fgets(line + 2, linesize - 2, stdin);
fd6b7a7f
KZ
1748 if (lp == NULL) {
1749 eof = 1;
1750 return RD_EOF;
1751 }
c0f19ccf 1752 if (!(lp = strchr(lp, '\n')))
109dbc4f 1753 errx(EXIT_FAILURE, _("long or incomplete input line - quitting"));
fd6b7a7f
KZ
1754 *lp = 0;
1755
1756 /* remove comments, if any */
37b94458
KZ
1757 if ((lp = strchr(line + 2, '#')) != 0)
1758 *lp = 0;
fd6b7a7f
KZ
1759
1760 /* recognize a few commands - to be expanded */
37b94458 1761 if (!strcmp(line + 2, "unit: sectors")) {
fd6b7a7f
KZ
1762 specified_format = F_SECTOR;
1763 return RD_CMD;
1764 }
1765
1766 /* dump style? - then bad input is fatal */
37b94458 1767 if ((ip = strchr(line + 2, ':')) != 0) {
fd6b7a7f
KZ
1768 struct dumpfld *d;
1769
37b94458
KZ
1770 nxtfld:
1771 ip++;
1772 while (isspace(*ip))
fd6b7a7f 1773 ip++;
37b94458
KZ
1774 if (*ip == 0)
1775 return fno;
1776 for (d = dumpflds; (size_t) (d - dumpflds) < ARRAY_SIZE(dumpflds); d++) {
1777 if (!strncmp(ip, d->fldname, strlen(d->fldname))) {
1778 ip += strlen(d->fldname);
1779 while (isspace(*ip))
1780 ip++;
1781 if (d->is_bool)
1782 fields[d->fldno] = line;
1783 else if (*ip == '=') {
1784 while (isspace(*++ip)) ;
1785 fields[d->fldno] = ip;
1786 while (isalnum(*ip)) /* 0x07FF */
1787 ip++;
1788 } else
109dbc4f 1789 errx(EXIT_FAILURE, _("input error: `=' expected after %s field"),
37b94458
KZ
1790 d->fldname);
1791 if (fno <= d->fldno)
1792 fno = d->fldno + 1;
1793 if (*ip == 0)
1794 return fno;
1795 if (*ip != ',' && *ip != ';')
109dbc4f 1796 errx(EXIT_FAILURE, _("input error: unexpected character %c after %s field"),
37b94458
KZ
1797 *ip, d->fldname);
1798 *ip = 0;
1799 goto nxtfld;
fd6b7a7f 1800 }
37b94458 1801 }
109dbc4f 1802 errx(EXIT_FAILURE, _("unrecognized input: %s"), ip);
fd6b7a7f
KZ
1803 }
1804
1805 /* split line into fields */
37b94458 1806 lp = ip = line + 2;
fd6b7a7f 1807 fields[fno++] = lp;
37b94458
KZ
1808 while ((c = *ip++) != 0) {
1809 if (!lp[-1] && (c == '\t' || c == ' ')) ;
fd6b7a7f
KZ
1810 else if (c == '\t' || c == ' ' || c == ',' || c == ';') {
1811 *lp++ = 0;
1812 if (fno < fieldssize)
1813 fields[fno++] = lp;
1814 continue;
1815 } else
37b94458 1816 *lp++ = c;
fd6b7a7f
KZ
1817 }
1818
37b94458
KZ
1819 if (lp == fields[fno - 1])
1820 fno--;
fd6b7a7f
KZ
1821 return fno;
1822}
1823
1824/* read a number, use default if absent */
364cda48 1825/* a sign gives an offset from the default */
22853e4a 1826static int
fd6b7a7f
KZ
1827get_ul(char *u, unsigned long *up, unsigned long def, int base) {
1828 char *nu;
364cda48
KZ
1829 int sign = 0;
1830 unsigned long val;
fd6b7a7f 1831
364cda48
KZ
1832 if (*u == '+') {
1833 sign = 1;
1834 u++;
1835 } else if (*u == '-') {
1836 sign = -1;
1837 u++;
1838 }
fd6b7a7f
KZ
1839 if (*u) {
1840 errno = 0;
364cda48 1841 val = strtoul(u, &nu, base);
fd6b7a7f 1842 if (errno == ERANGE) {
66d28be8 1843 warnx(_("number too big\n"));
fd6b7a7f
KZ
1844 return -1;
1845 }
1846 if (*nu) {
66d28be8 1847 warnx(_("trailing junk after number\n"));
fd6b7a7f
KZ
1848 return -1;
1849 }
364cda48 1850 if (sign == 1)
37b94458 1851 val = def + val;
364cda48 1852 else if (sign == -1)
37b94458 1853 val = def - val;
364cda48 1854 *up = val;
fd6b7a7f 1855 } else
37b94458 1856 *up = def;
fd6b7a7f
KZ
1857 return 0;
1858}
1859
b7767afc
PU
1860
1861/* read a number, use default if absent */
1862/* a sign gives an offset from the default */
1863static int
1864get_ull(char *u, unsigned long long *up, unsigned long long def, int base) {
1865 char *nu;
1866 int sign = 0;
1867 unsigned long long val;
1868
1869 if (*u == '+') {
1870 sign = 1;
1871 u++;
1872 } else if (*u == '-') {
1873 sign = -1;
1874 u++;
1875 }
1876 if (*u) {
1877 errno = 0;
1878 val = strtoull(u, &nu, base);
1879 if (errno == ERANGE) {
66d28be8 1880 warnx(_("number too big\n"));
b7767afc
PU
1881 return -1;
1882 }
1883 if (*nu) {
66d28be8 1884 warnx(_("trailing junk after number\n"));
b7767afc
PU
1885 return -1;
1886 }
1887 if (sign == 1)
1888 val = def + val;
1889 else if (sign == -1)
1890 val = def - val;
1891 *up = val;
1892 } else
1893 *up = def;
1894 return 0;
1895}
1896
1897
fd6b7a7f
KZ
1898/* There are two common ways to structure extended partitions:
1899 as nested boxes, and as a chain. Sometimes the partitions
1900 must be given in order. Sometimes all logical partitions
1901 must lie inside the outermost extended partition.
1902NESTED: every partition is contained in the surrounding partitions
1903 and is disjoint from all others.
1904CHAINED: every data partition is contained in the surrounding partitions
1905 and disjoint from all others, but extended partitions may lie outside
1906 (insofar as allowed by all_logicals_inside_outermost_extended).
1907ONESECTOR: all data partitions are mutually disjoint; extended partitions
1908 each use one sector only (except perhaps for the outermost one).
1909*/
1910int partitions_in_order = 0;
1911int all_logicals_inside_outermost_extended = 1;
1912enum { NESTED, CHAINED, ONESECTOR } boxes = NESTED;
1913
1914/* find the default value for <start> - assuming entire units */
6c709b57 1915static unsigned long long
fd6b7a7f 1916first_free(int pno, int is_extended, struct part_desc *ep, int format,
6c709b57
PU
1917 unsigned long long mid, struct disk_desc *z) {
1918 unsigned long long ff, fff;
fd6b7a7f
KZ
1919 unsigned long unit = unitsize(format);
1920 struct part_desc *partitions = &(z->partitions[0]), *pp = 0;
1921
1922 /* if containing ep undefined, look at its container */
1923 if (ep && ep->p.sys_type == EMPTY_PARTITION)
37b94458 1924 ep = ep->ep;
fd6b7a7f
KZ
1925
1926 if (ep) {
1927 if (boxes == NESTED || (boxes == CHAINED && !is_extended))
37b94458 1928 pp = ep;
fd6b7a7f 1929 else if (all_logicals_inside_outermost_extended)
37b94458 1930 pp = outer_extended_partition(ep);
fd6b7a7f
KZ
1931 }
1932#if 0
1933 ff = pp ? (pp->start + unit - 1) / unit : 0;
1934#else
1935 /* rounding up wastes almost an entire cylinder - round down
1936 and leave it to compute_start_sect() to fix the difference */
1937 ff = pp ? pp->start / unit : 0;
1938#endif
1939 /* MBR and 1st sector of an extended partition are never free */
1940 if (unit == 1)
37b94458 1941 ff++;
fd6b7a7f 1942
37b94458
KZ
1943 again:
1944 for (pp = partitions; pp < partitions + pno; pp++) {
fd6b7a7f
KZ
1945 if (!is_parent(pp, ep) && pp->size > 0) {
1946 if ((partitions_in_order || pp->start / unit <= ff
37b94458 1947 || (mid && pp->start / unit <= mid))
fd6b7a7f
KZ
1948 && (fff = (pp->start + pp->size + unit - 1) / unit) > ff) {
1949 ff = fff;
1950 goto again;
1951 }
1952 }
1953 }
1954
1955 return ff;
1956}
1957
1958/* find the default value for <size> - assuming entire units */
6c709b57 1959static unsigned long long
fd6b7a7f 1960max_length(int pno, int is_extended, struct part_desc *ep, int format,
6c709b57 1961 unsigned long long start, struct disk_desc *z) {
c4730f10 1962 unsigned long long fu;
fd6b7a7f
KZ
1963 unsigned long unit = unitsize(format);
1964 struct part_desc *partitions = &(z->partitions[0]), *pp = 0;
1965
1966 /* if containing ep undefined, look at its container */
1967 if (ep && ep->p.sys_type == EMPTY_PARTITION)
37b94458 1968 ep = ep->ep;
fd6b7a7f
KZ
1969
1970 if (ep) {
1971 if (boxes == NESTED || (boxes == CHAINED && !is_extended))
37b94458 1972 pp = ep;
fd6b7a7f 1973 else if (all_logicals_inside_outermost_extended)
37b94458 1974 pp = outer_extended_partition(ep);
fd6b7a7f
KZ
1975 }
1976 fu = pp ? (pp->start + pp->size) / unit : get_disksize(format);
c64061c9 1977
37b94458
KZ
1978 for (pp = partitions; pp < partitions + pno; pp++)
1979 if (!is_parent(pp, ep) && pp->size > 0
1980 && pp->start / unit >= start && pp->start / unit < fu)
1981 fu = pp->start / unit;
fd6b7a7f
KZ
1982
1983 return (fu > start) ? fu - start : 0;
1984}
1985
1986/* compute starting sector of a partition inside an extended one */
d26aa358 1987/* return 0 on failure */
fd6b7a7f 1988/* ep is 0 or points to surrounding extended partition */
22853e4a 1989static int
fd6b7a7f 1990compute_start_sect(struct part_desc *p, struct part_desc *ep) {
6c709b57 1991 unsigned long long base;
7eda085c 1992 int inc = (DOS && B.sectors) ? B.sectors : 1;
fd6b7a7f
KZ
1993 int delta;
1994
1995 if (ep && p->start + p->size >= ep->start + 1)
37b94458 1996 delta = p->start - ep->start - inc;
fd6b7a7f 1997 else if (p->start == 0 && p->size > 0)
37b94458 1998 delta = -inc;
fd6b7a7f 1999 else
37b94458 2000 delta = 0;
d26aa358 2001
fd6b7a7f 2002 if (delta < 0) {
6c709b57 2003 unsigned long long old_size = p->size;
fd6b7a7f
KZ
2004 p->start -= delta;
2005 p->size += delta;
2006 if (is_extended(p->p.sys_type) && boxes == ONESECTOR)
37b94458
KZ
2007 p->size = inc;
2008 else if ((ssize_t) old_size <= (ssize_t) - delta) {
4a01477b 2009 my_warn(_("no room for partition descriptor\n"));
fd6b7a7f
KZ
2010 return 0;
2011 }
2012 }
2013 base = (!ep ? 0
37b94458
KZ
2014 : (is_extended(p->p.sys_type) ?
2015 outer_extended_partition(ep) : ep)->start);
fd6b7a7f
KZ
2016 p->ep = ep;
2017 if (p->p.sys_type == EMPTY_PARTITION && p->size == 0) {
37b94458 2018 p->p.start_sect = 0;
fd6b7a7f
KZ
2019 p->p.begin_chs = zero_chs;
2020 p->p.end_chs = zero_chs;
2021 } else {
37b94458
KZ
2022 p->p.start_sect = p->start - base;
2023 p->p.begin_chs = ulong_to_chs(p->start, B);
2024 p->p.end_chs = ulong_to_chs(p->start + p->size - 1, B);
fd6b7a7f
KZ
2025 }
2026 p->p.nr_sects = p->size;
2027 return 1;
c64061c9 2028}
fd6b7a7f
KZ
2029
2030/* build the extended partition surrounding a given logical partition */
22853e4a 2031static int
fd6b7a7f
KZ
2032build_surrounding_extended(struct part_desc *p, struct part_desc *ep,
2033 struct disk_desc *z) {
7eda085c 2034 int inc = (DOS && B.sectors) ? B.sectors : 1;
fd6b7a7f
KZ
2035 int format = F_SECTOR;
2036 struct part_desc *p0 = &(z->partitions[0]), *eep = ep->ep;
2037
2038 if (boxes == NESTED) {
37b94458
KZ
2039 ep->start = first_free(ep - p0, 1, eep, format, p->start, z);
2040 ep->size = max_length(ep - p0, 1, eep, format, ep->start, z);
fd6b7a7f 2041 if (ep->start > p->start || ep->start + ep->size < p->start + p->size) {
4a01477b 2042 my_warn(_("cannot build surrounding extended partition\n"));
fd6b7a7f
KZ
2043 return 0;
2044 }
2045 } else {
2046 ep->start = p->start;
c129767e 2047 if (boxes == CHAINED)
37b94458 2048 ep->size = p->size;
fd6b7a7f 2049 else
37b94458 2050 ep->size = inc;
fd6b7a7f
KZ
2051 }
2052
2053 ep->p.nr_sects = ep->size;
2054 ep->p.bootable = 0;
2055 ep->p.sys_type = EXTENDED_PARTITION;
2056 if (!compute_start_sect(ep, eep) || !compute_start_sect(p, ep)) {
2057 ep->p.sys_type = EMPTY_PARTITION;
2058 ep->size = 0;
2059 return 0;
2060 }
2061
2062 return 1;
2063}
2064
22853e4a 2065static int
fd6b7a7f
KZ
2066read_line(int pno, struct part_desc *ep, char *dev, int interactive,
2067 struct disk_desc *z) {
934238cd
RD
2068 char line[1000];
2069 char *fields[11];
37b94458 2070 int fno, pct = pno % 4;
fd6b7a7f 2071 struct part_desc p, *orig;
6c709b57 2072 unsigned long long ff, ff1, ul, ml, ml1, def;
fd6b7a7f
KZ
2073 int format, lpno, is_extd;
2074
2075 if (eof || eob)
37b94458 2076 return -1;
fd6b7a7f
KZ
2077
2078 lpno = index_to_linux(pno, z);
2079
2080 if (interactive) {
2081 if (pct == 0 && (show_extended || pno == 0))
37b94458 2082 my_warn("\n");
4a01477b 2083 my_warn("%s:", partname(dev, lpno, 10));
fd6b7a7f
KZ
2084 }
2085
2086 /* read input line - skip blank lines when reading from a file */
2087 do {
11ef0c35 2088 fno = read_stdin(fields, line, ARRAY_SIZE(fields), ARRAY_SIZE(line));
37b94458 2089 } while (fno == RD_CMD || (fno == 0 && !interactive));
fd6b7a7f
KZ
2090 if (fno == RD_EOF) {
2091 return -1;
2092 } else if (fno > 10 && *(fields[10]) != 0) {
66d28be8 2093 warnx(_("too many input fields\n"));
fd6b7a7f
KZ
2094 return 0;
2095 }
2096
2097 if (fno == 1 && !strcmp(fields[0], ".")) {
2098 eob = 1;
2099 return -1;
2100 }
2101
2102 /* use specified format, but round to cylinders if F_MEGABYTE specified */
2103 format = 0;
cc393e38 2104 if (B.cylindersize && specified_format == F_MEGABYTE && !Linux)
37b94458 2105 format = F_CYLINDER;
fd6b7a7f
KZ
2106
2107 orig = (one_only ? &(oldp.partitions[pno]) : 0);
2108
2109 p = zero_part_desc;
2110 p.ep = ep;
2111
2112 /* first read the type - we need to know whether it is extended */
2113 /* stop reading when input blank (defaults) and all is full */
2114 is_extd = 0;
2115 if (fno == 0) { /* empty line */
2116 if (orig && is_extended(orig->p.sys_type))
37b94458 2117 is_extd = 1;
fd6b7a7f
KZ
2118 ff = first_free(pno, is_extd, ep, format, 0, z);
2119 ml = max_length(pno, is_extd, ep, format, ff, z);
2120 if (ml == 0 && is_extd == 0) {
2121 is_extd = 1;
2122 ff = first_free(pno, is_extd, ep, format, 0, z);
2123 ml = max_length(pno, is_extd, ep, format, ff, z);
2124 }
2125 if (ml == 0 && pno >= 4) {
2126 /* no free blocks left - don't read any further */
4a01477b 2127 my_warn(_("No room for more\n"));
fd6b7a7f
KZ
2128 return -1;
2129 }
2130 }
2131 if (fno < 3 || !*(fields[2]))
37b94458
KZ
2132 ul = orig ? orig->p.sys_type :
2133 (is_extd || (pno > 3 && pct == 1 && show_extended))
2134 ? EXTENDED_PARTITION : LINUX_NATIVE;
c129767e 2135 else if (!strcmp(fields[2], "L"))
37b94458 2136 ul = LINUX_NATIVE;
c129767e 2137 else if (!strcmp(fields[2], "S"))
37b94458 2138 ul = LINUX_SWAP;
c129767e 2139 else if (!strcmp(fields[2], "E"))
37b94458 2140 ul = EXTENDED_PARTITION;
c129767e 2141 else if (!strcmp(fields[2], "X"))
37b94458 2142 ul = LINUX_EXTENDED;
6c709b57 2143 else if (get_ull(fields[2], &ul, LINUX_NATIVE, 16))
37b94458 2144 return 0;
fd6b7a7f 2145 if (ul > 255) {
4a01477b 2146 my_warn(_("Illegal type\n"));
fd6b7a7f
KZ
2147 return 0;
2148 }
2149 p.p.sys_type = ul;
2150 is_extd = is_extended(ul);
2151
2152 /* find start */
2153 ff = first_free(pno, is_extd, ep, format, 0, z);
2154 ff1 = ff * unitsize(format);
2155 def = orig ? orig->start : (pno > 4 && pct > 1) ? 0 : ff1;
2156 if (fno < 1 || !*(fields[0]))
37b94458 2157 p.start = def;
fd6b7a7f 2158 else {
6c709b57 2159 if (get_ull(fields[0], &ul, def / unitsize(0), 0))
37b94458 2160 return 0;
fd6b7a7f
KZ
2161 p.start = ul * unitsize(0);
2162 p.start -= (p.start % unitsize(format));
2163 }
2164
2165 /* find length */
2166 ml = max_length(pno, is_extd, ep, format, p.start / unitsize(format), z);
2167 ml1 = ml * unitsize(format);
2168 def = orig ? orig->size : (pno > 4 && pct > 1) ? 0 : ml1;
2169 if (fno < 2 || !*(fields[1]))
37b94458 2170 p.size = def;
f30f2bbc 2171 else if (!strcmp(fields[1], "+"))
37b94458 2172 p.size = ml1;
fd6b7a7f 2173 else {
6c709b57 2174 if (get_ull(fields[1], &ul, def / unitsize(0), 0))
37b94458 2175 return 0;
fd6b7a7f
KZ
2176 p.size = ul * unitsize(0) + unitsize(format) - 1;
2177 p.size -= (p.size % unitsize(format));
2178 }
2179 if (p.size > ml1) {
be350fb9 2180 my_warn(_("Warning: given size (%lu) exceeds max allowable size (%lu)\n"),
37b94458 2181 (p.size + unitsize(0) - 1) / unitsize(0), ml1 / unitsize(0));
fd6b7a7f 2182 if (!force)
37b94458 2183 return 0;
fd6b7a7f
KZ
2184 }
2185 if (p.size == 0 && pno >= 4 && (fno < 2 || !*(fields[1]))) {
4a01477b 2186 my_warn(_("Warning: empty partition\n"));
fd6b7a7f 2187 if (!force)
37b94458 2188 return 0;
fd6b7a7f
KZ
2189 }
2190 p.p.nr_sects = p.size;
2191
2192 if (p.size == 0 && !orig) {
c129767e 2193 if (fno < 1 || !*(fields[0]))
37b94458 2194 p.start = 0;
c129767e 2195 if (fno < 3 || !*(fields[2]))
37b94458 2196 p.p.sys_type = EMPTY_PARTITION;
fd6b7a7f
KZ
2197 }
2198
2199 if (p.start < ff1 && p.size > 0) {
4a01477b 2200 my_warn(_("Warning: bad partition start (earliest %lu)\n"),
37b94458 2201 (ff1 + unitsize(0) - 1) / unitsize(0));
fd6b7a7f 2202 if (!force)
37b94458 2203 return 0;
fd6b7a7f
KZ
2204 }
2205
2206 if (fno < 4 || !*(fields[3]))
37b94458 2207 ul = (orig ? orig->p.bootable : 0);
fd6b7a7f 2208 else if (!strcmp(fields[3], "-"))
37b94458 2209 ul = 0;
fd6b7a7f 2210 else if (!strcmp(fields[3], "*") || !strcmp(fields[3], "+"))
37b94458 2211 ul = 0x80;
fd6b7a7f 2212 else {
4a01477b 2213 my_warn(_("unrecognized bootable flag - choose - or *\n"));
37b94458 2214 return 0;
fd6b7a7f
KZ
2215 }
2216 p.p.bootable = ul;
2217
2218 if (ep && ep->p.sys_type == EMPTY_PARTITION) {
37b94458
KZ
2219 if (!build_surrounding_extended(&p, ep, z))
2220 return 0;
2221 } else if (!compute_start_sect(&p, ep))
fd6b7a7f
KZ
2222 return 0;
2223
37b94458
KZ
2224 {
2225 longchs aa = chs_to_longchs(p.p.begin_chs), bb;
fd6b7a7f 2226
37b94458
KZ
2227 if (fno < 5) {
2228 bb = aa;
2229 } else if (fno < 7) {
2230 my_warn(_("partial c,h,s specification?\n"));
2231 return 0;
2232 } else if (get_ul(fields[4], &bb.c, aa.c, 0) ||
2233 get_ul(fields[5], &bb.h, aa.h, 0) ||
2234 get_ul(fields[6], &bb.s, aa.s, 0))
2235 return 0;
2236 p.p.begin_chs = longchs_to_chs(bb, B);
2237 }
2238 {
2239 longchs aa = chs_to_longchs(p.p.end_chs), bb;
2240
2241 if (fno < 8) {
2242 bb = aa;
2243 } else if (fno < 10) {
2244 my_warn(_("partial c,h,s specification?\n"));
2245 return 0;
2246 } else if (get_ul(fields[7], &bb.c, aa.c, 0) ||
2247 get_ul(fields[8], &bb.h, aa.h, 0) ||
2248 get_ul(fields[9], &bb.s, aa.s, 0))
2249 return 0;
2250 p.p.end_chs = longchs_to_chs(bb, B);
fd6b7a7f
KZ
2251 }
2252
2253 if (pno > 3 && p.size && show_extended && p.p.sys_type != EMPTY_PARTITION
37b94458 2254 && (is_extended(p.p.sys_type) != (pct == 1))) {
4a01477b 2255 my_warn(_("Extended partition not where expected\n"));
fd6b7a7f 2256 if (!force)
37b94458 2257 return 0;
fd6b7a7f
KZ
2258 }
2259
2260 z->partitions[pno] = p;
2261 if (pno >= z->partno)
37b94458 2262 z->partno += 4; /* reqd for out_partition() */
fd6b7a7f
KZ
2263
2264 if (interactive)
37b94458 2265 out_partition(dev, 0, &(z->partitions[pno]), z, B);
fd6b7a7f
KZ
2266
2267 return 1;
2268}
2269
2270/* ep either points to the extended partition to contain this one,
2271 or to the empty partition that may become extended or is 0 */
22853e4a 2272static int
fd6b7a7f
KZ
2273read_partition(char *dev, int interactive, int pno, struct part_desc *ep,
2274 struct disk_desc *z) {
2275 struct part_desc *p = &(z->partitions[pno]);
2276 int i;
2277
2278 if (one_only) {
2279 *p = oldp.partitions[pno];
2280 if (one_only_pno != pno)
37b94458
KZ
2281 goto ret;
2282 } else if (!show_extended && pno > 4 && pno % 4)
2283 goto ret;
fd6b7a7f
KZ
2284
2285 while (!(i = read_line(pno, ep, dev, interactive, z)))
37b94458 2286 if (!interactive)
109dbc4f 2287 errx(EXIT_FAILURE, _("bad input"));
fd6b7a7f
KZ
2288 if (i < 0) {
2289 p->ep = ep;
2290 return 0;
2291 }
2292
37b94458 2293 ret:
fd6b7a7f
KZ
2294 p->ep = ep;
2295 if (pno >= z->partno)
37b94458 2296 z->partno += 4;
fd6b7a7f
KZ
2297 return 1;
2298}
2299
22853e4a 2300static void
fd6b7a7f
KZ
2301read_partition_chain(char *dev, int interactive, struct part_desc *ep,
2302 struct disk_desc *z) {
bdb8757e
SK
2303 int i;
2304 size_t base;
fd6b7a7f
KZ
2305
2306 eob = 0;
2307 while (1) {
2308 base = z->partno;
37b94458 2309 if (base + 4 > ARRAY_SIZE(z->partitions)) {
66d28be8 2310 warnx(_("too many partitions\n"));
fd6b7a7f
KZ
2311 break;
2312 }
37b94458
KZ
2313 for (i = 0; i < 4; i++)
2314 if (!read_partition(dev, interactive, base + i, ep, z))
2315 return;
2316 for (i = 0; i < 4; i++) {
2317 ep = &(z->partitions[base + i]);
fd6b7a7f 2318 if (is_extended(ep->p.sys_type) && ep->size)
37b94458 2319 break;
fd6b7a7f
KZ
2320 }
2321 if (i == 4) {
2322 /* nothing found - maybe an empty partition is going
2323 to be extended */
2324 if (one_only || show_extended)
37b94458
KZ
2325 break;
2326 ep = &(z->partitions[base + 1]);
fd6b7a7f 2327 if (ep->size || ep->p.sys_type != EMPTY_PARTITION)
37b94458 2328 break;
fd6b7a7f
KZ
2329 }
2330 }
2331}
2332
22853e4a 2333static void
fd6b7a7f 2334read_input(char *dev, int interactive, struct disk_desc *z) {
bdb8757e 2335 size_t i;
fd6b7a7f
KZ
2336 struct part_desc *partitions = &(z->partitions[0]), *ep;
2337
37b94458
KZ
2338 for (i = 0; i < ARRAY_SIZE(z->partitions); i++)
2339 partitions[i] = zero_part_desc;
fd6b7a7f
KZ
2340 z->partno = 0;
2341
2342 if (interactive)
be350fb9
BS
2343 my_warn(_("Input in the following format; absent fields get a default value.\n"
2344 "<start> <size> <type [E,S,L,X,hex]> <bootable [-,*]> <c,h,s> <c,h,s>\n"
2345 "Usually you only need to specify <start> and <size> (and perhaps <type>).\n"));
fd6b7a7f
KZ
2346 eof = 0;
2347
37b94458
KZ
2348 for (i = 0; i < 4; i++)
2349 read_partition(dev, interactive, i, 0, z);
2350 for (i = 0; i < 4; i++) {
2351 ep = partitions + i;
fd6b7a7f 2352 if (is_extended(ep->p.sys_type) && ep->size)
37b94458 2353 read_partition_chain(dev, interactive, ep, z);
fd6b7a7f
KZ
2354 }
2355 add_sector_and_offset(z);
2356}
2357
2358/*
2359 * G. The command line
2360 */
e0c97cdc
BS
2361static void usage(FILE * out)
2362{
2363 fputs(_("\nUsage:\n"), out);
2364 fprintf(out,
2365 _(" %s [options] <device> [...]\n"), program_invocation_short_name);
2366
2367 fputs(_("\nOptions:\n"), out);
2368 fputs(_(" -s, --show-size list size of a partition\n"
2369 " -c, --id change or print partition Id\n"
2370 " --change-id change Id\n"
2371 " --print-id print Id\n"), out);
2372 fputs(_(" -l, --list list partitions of each device\n"
2373 " -d, --dump idem, but in a format suitable for later input\n"
2374 " -i, --increment number cylinders etc. from 1 instead of from 0\n"
2375 " -u, --unit <letter> units to be used; <letter> can be one of\n"
2376 " S (sectors), C (cylinders), B (blocks), or M (MB)\n"), out);
2377 fputs(_(" -1, --one-only reserved option that does nothing currently\n"
2378 " -T, --list-types list the known partition types\n"
2379 " -D, --DOS for DOS-compatibility: waste a little space\n"
2380 " -E, --DOS-extended DOS extended partition compatibility\n"
2381 " -R, --re-read make the kernel reread the partition table\n"), out);
2382 fputs(_(" -N <number> change only the partition with this <number>\n"
2383 " -n do not actually write to disk\n"
2384 " -O <file> save the sectors that will be overwritten to <file>\n"
2385 " -I <file> restore sectors from <file>\n"), out);
2386 fputs(_(" -V, --verify check that the listed partitions are reasonable\n"
2387 " -v, --version display version information and exit\n"
2388 " -h, --help display this help text and exit\n"), out);
2389
2390 fputs(_("\nDangerous options:\n"), out);
2391 fputs(_(" -f, --force disable all consistency checking\n"
2392 " --no-reread do not check whether the partition is in use\n"
2393 " -q, --quiet suppress warning messages\n"
2394 " -L, --Linux do not complain about things irrelevant for Linux\n"), out);
2395 fputs(_(" -g, --show-geometry print the kernel's idea of the geometry\n"
2396 " -G, --show-pt-geometry print geometry guessed from the partition table\n"), out);
2397 fputs(_(" -A, --activate[=<device>] activate bootable flag\n"
2398 " -U, --unhide[=<dev>] set partition unhidden\n"
2399 " -x, --show-extended also list extended partitions in the output,\n"
2400 " or expect descriptors for them in the input\n"), out);
2401 fputs(_(" --leave-last do not allocate the last cylinder\n"
2402 " --IBM same as --leave-last\n"), out);
2403 fputs(_(" --in-order partitions are in order\n"
2404 " --not-in-order partitions are not in order\n"
2405 " --inside-outer all logicals inside outermost extended\n"
2406 " --not-inside-outer not all logicals inside outermost extended\n"), out);
2407 fputs(_(" --nested every partition is disjoint from all others\n"
2408 " --chained like nested, but extended partitions may lie outside\n"
2409 " --onesector partitions are mutually disjoint\n"), out);
2410
2411 fputs(_("\nOverride the detected geometry using:\n"
2412 " -C, --cylinders <number> set the number of cylinders to use\n"
2413 " -H, --heads <number> set the number of heads to use\n"
2414 " -S, --sectors <number> set the number of sectors to use\n\n"), out);
2415
2416 exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
fd6b7a7f
KZ
2417}
2418
fd6b7a7f
KZ
2419static void
2420activate_usage(char *progn) {
37b94458 2421 puts(_("Usage:"));
7eda085c 2422 printf(_("%s device list active partitions on device\n"), progn);
be350fb9 2423 printf(_("%s device n1 n2 ... activate partitions n1 ..., inactivate the rest\n"),
37b94458 2424 progn);
be350fb9 2425 printf(_("%s -An device activate partition n, inactivate the other ones\n"),
37b94458 2426 PROGNAME);
fd6b7a7f
KZ
2427 exit(1);
2428}
2429
2430static void
4dd3383a 2431unhide_usage(char *progn __attribute__ ((__unused__))) {
fd6b7a7f
KZ
2432 exit(1);
2433}
2434
cc80c234 2435static const char short_opts[] = "cdfghilnqsu:vx1A::C:DGH:I:LN:O:RS:TU::V";
fd6b7a7f
KZ
2436
2437#define PRINT_ID 0400
2438#define CHANGE_ID 01000
2439
4a0f60f6
SK
2440enum {
2441 OPT_NO_REREAD = CHAR_MAX + 1,
2442 OPT_LEAVE_LAST,
2443 OPT_IN_ORDER,
2444 OPT_NOT_IN_ORDER,
2445 OPT_INSIDE_OUTER,
2446 OPT_NOT_INSIDE_OUTER,
2447 OPT_NESTED,
2448 OPT_CHAINED,
2449 OPT_ONESECTOR
2450};
2451
fd6b7a7f 2452static const struct option long_opts[] = {
37b94458
KZ
2453 { "change-id", no_argument, NULL, 'c' + CHANGE_ID },
2454 { "print-id", no_argument, NULL, 'c' + PRINT_ID },
2455 { "id", no_argument, NULL, 'c' },
fd6b7a7f
KZ
2456 { "dump", no_argument, NULL, 'd' },
2457 { "force", no_argument, NULL, 'f' },
37b94458
KZ
2458 { "show-geometry", no_argument, NULL, 'g' },
2459 { "help", no_argument, NULL, 'h' },
fd6b7a7f
KZ
2460 { "increment", no_argument, NULL, 'i' },
2461 { "list", no_argument, NULL, 'l' },
2462 { "quiet", no_argument, NULL, 'q' },
2463 { "show-size", no_argument, NULL, 's' },
37b94458 2464 { "unit", required_argument, NULL, 'u' },
fd6b7a7f
KZ
2465 { "version", no_argument, NULL, 'v' },
2466 { "show-extended", no_argument, NULL, 'x' },
fd6b7a7f 2467 { "one-only", no_argument, NULL, '1' },
37b94458
KZ
2468 { "cylinders", required_argument, NULL, 'C' },
2469 { "heads", required_argument, NULL, 'H' },
2470 { "sectors", required_argument, NULL, 'S' },
cf3f26bf 2471 { "show-pt-geometry", no_argument, NULL, 'G' },
37b94458 2472 { "activate", optional_argument, NULL, 'A' },
fd6b7a7f 2473 { "DOS", no_argument, NULL, 'D' },
37b94458 2474 { "DOS-extended", no_argument, NULL, 'E' },
fd6b7a7f
KZ
2475 { "Linux", no_argument, NULL, 'L' },
2476 { "re-read", no_argument, NULL, 'R' },
2477 { "list-types", no_argument, NULL, 'T' },
37b94458 2478 { "unhide", optional_argument, NULL, 'U' },
4a0f60f6
SK
2479 { "no-reread", no_argument, NULL, OPT_NO_REREAD },
2480 { "IBM", no_argument, NULL, OPT_LEAVE_LAST },
2481 { "leave-last", no_argument, NULL, OPT_LEAVE_LAST },
2482/* dangerous flags - not all completely implemented */
2483 { "in-order", no_argument, NULL, OPT_IN_ORDER },
2484 { "not-in-order", no_argument, NULL, OPT_NOT_IN_ORDER },
2485 { "inside-outer", no_argument, NULL, OPT_INSIDE_OUTER },
2486 { "not-inside-outer", no_argument, NULL, OPT_NOT_INSIDE_OUTER },
2487 { "nested", no_argument, NULL, OPT_NESTED },
2488 { "chained", no_argument, NULL, OPT_CHAINED },
2489 { "onesector", no_argument, NULL, OPT_ONESECTOR },
fd6b7a7f
KZ
2490 { NULL, 0, NULL, 0 }
2491};
2492
3b622ddd
DB
2493static int is_ide_cdrom_or_tape(char *device)
2494{
2495 int fd, ret;
2b6fc908 2496
6ce0b7d8 2497 if ((fd = open(device, O_RDONLY)) < 0)
3b622ddd
DB
2498 return 0;
2499 ret = blkdev_is_cdrom(fd);
37b94458 2500
3b622ddd
DB
2501 close(fd);
2502 return ret;
2b6fc908
KZ
2503}
2504
ffc43748 2505static char *
37b94458
KZ
2506nextproc(FILE * procf) {
2507 static char devname[256];
2508 char line[1024], ptname[128];
2509 int ma, mi;
2510 unsigned long long sz;
ffc43748 2511
37b94458 2512 if (procf == NULL)
ffc43748 2513 return NULL;
37b94458
KZ
2514 while (fgets(line, sizeof(line), procf) != NULL) {
2515 if (sscanf(line, " %d %d %llu %128[^\n ]", &ma, &mi, &sz, ptname) != 4)
2516 continue;
2517 snprintf(devname, sizeof(devname), "/dev/%s", ptname);
2518 if (!is_whole_disk(devname))
2519 continue;
2520 return canonicalize_path(devname);
2521 }
2522
2523 return NULL;
78917e48 2524}
ffc43748 2525
5dbff4c0 2526static void
37b94458
KZ
2527gpt_warning(char *dev, int warn_only) {
2528 if (force)
2529 warn_only = 1;
2530
2531 if (dev && gpt_probe_signature_devname(dev)) {
2532 fflush(stdout);
2533 fprintf(stderr,
2534 _("\nWARNING: GPT (GUID Partition Table) detected on '%s'! "
2535 "The util sfdisk doesn't support GPT. Use GNU Parted.\n\n"),
2536 dev);
2537 if (!warn_only) {
2538 fprintf(stderr,
2539 _("Use the --force flag to overrule this check.\n"));
2540 exit(1);
5dbff4c0 2541 }
37b94458 2542 }
5dbff4c0
KZ
2543}
2544
22853e4a
KZ
2545static void do_list(char *dev, int silent);
2546static void do_size(char *dev, int silent);
2547static void do_geom(char *dev, int silent);
cf3f26bf 2548static void do_pt_geom(char *dev, int silent);
22853e4a
KZ
2549static void do_fdisk(char *dev);
2550static void do_reread(char *dev);
2551static void do_change_id(char *dev, char *part, char *id);
2552static void do_unhide(char **av, int ac, char *arg);
2553static void do_activate(char **av, int ac, char *arg);
fd6b7a7f 2554
2cccd0ff 2555unsigned long long total_size;
fd6b7a7f
KZ
2556
2557int
2558main(int argc, char **argv) {
2559 char *progn;
2560 int c;
2561 char *dev;
2562 int opt_size = 0;
2563 int opt_out_geom = 0;
cf3f26bf 2564 int opt_out_pt_geom = 0;
fd6b7a7f
KZ
2565 int opt_reread = 0;
2566 int activate = 0;
2567 int do_id = 0;
2568 int unhide = 0;
2569 int fdisk = 0;
2570 char *activatearg = 0;
2571 char *unhidearg = 0;
2572
7eda085c
KZ
2573 setlocale(LC_ALL, "");
2574 bindtextdomain(PACKAGE, LOCALEDIR);
2575 textdomain(PACKAGE);
b2d28533 2576 atexit(close_stdout);
7eda085c 2577
fd6b7a7f 2578 if (argc < 1)
109dbc4f 2579 errx(EXIT_FAILURE, _("no command?"));
c0f19ccf 2580 if ((progn = strrchr(argv[0], '/')) == NULL)
37b94458 2581 progn = argv[0];
fd6b7a7f 2582 else
37b94458 2583 progn++;
fd6b7a7f 2584 if (!strcmp(progn, "activate"))
37b94458 2585 activate = 1; /* equivalent to `sfdisk -A' */
fd6b7a7f
KZ
2586#if 0 /* not important enough to deserve a name */
2587 else if (!strcmp(progn, "unhide"))
37b94458 2588 unhide = 1; /* equivalent to `sfdisk -U' */
fd6b7a7f
KZ
2589#endif
2590 else
37b94458 2591 fdisk = 1;
fd6b7a7f 2592
37b94458 2593 while ((c = getopt_long(argc, argv, short_opts, long_opts, NULL)) != -1) {
fd6b7a7f 2594 switch (c) {
37b94458
KZ
2595 case 'f':
2596 force = 1;
2597 break; /* does not imply quiet */
2598 case 'g':
2599 opt_out_geom = 1;
2600 break;
2601 case 'G':
2602 opt_out_pt_geom = 1;
2603 break;
2604 case 'i':
2605 increment = 1;
2606 break;
2607 case 'c':
2608 case 'c' + PRINT_ID:
2609 case 'c' + CHANGE_ID:
2610 do_id = c;
2611 break;
2612 case 'd':
2613 dump = 1; /* fall through */
2614 case 'l':
2615 opt_list = 1;
2616 break;
2617 case 'n':
2618 no_write = 1;
2619 break;
2620 case 'q':
2621 quiet = 1;
2622 break;
2623 case 's':
2624 opt_size = 1;
2625 break;
2626 case 'u':
2627 set_format(*optarg);
2628 break;
2629 case 'v':
cc80c234 2630 printf(_("%s from %s\n"), program_invocation_short_name,
37b94458 2631 PACKAGE_STRING);
cc80c234 2632 return EXIT_SUCCESS;
37b94458 2633 case 'h':
cc80c234
SK
2634 usage(stdout);
2635 return EXIT_SUCCESS;
37b94458
KZ
2636 case 'x':
2637 show_extended = 1;
2638 break;
2639 case 'A':
fd6b7a7f 2640 activatearg = optarg;
37b94458
KZ
2641 activate = 1;
2642 break;
2643 case 'C':
2644 U.cylinders = atoi(optarg);
2645 break;
2646 case 'D':
2647 DOS = 1;
2648 break;
2649 case 'E':
2650 DOS_extended = 1;
2651 break;
2652 case 'H':
2653 U.heads = atoi(optarg);
2654 break;
2655 case 'L':
2656 Linux = 1;
2657 break;
2658 case 'N':
2659 one_only = atoi(optarg);
2660 break;
2661 case 'I':
2662 restore_sector_file = optarg;
2663 break;
2664 case 'O':
2665 save_sector_file = optarg;
2666 break;
2667 case 'R':
2668 opt_reread = 1;
2669 break;
2670 case 'S':
2671 U.sectors = atoi(optarg);
2672 break;
2673 case 'T':
fd6b7a7f
KZ
2674 list_types();
2675 exit(0);
37b94458 2676 case 'U':
fd6b7a7f 2677 unhidearg = optarg;
37b94458
KZ
2678 unhide = 1;
2679 break;
2680 case 'V':
2681 verify = 1;
2682 break;
2683 default:
2684 usage(stderr);
2685 break;
2686
2687 /* dangerous flags */
2688 case OPT_IN_ORDER:
2689 partitions_in_order = 1;
2690 break;
2691 case OPT_NOT_IN_ORDER:
2692 partitions_in_order = 0;
2693 break;
2694 case OPT_INSIDE_OUTER:
2695 all_logicals_inside_outermost_extended = 1;
2696 break;
2697 case OPT_NOT_INSIDE_OUTER:
2698 all_logicals_inside_outermost_extended = 0;
2699 break;
2700 case OPT_NESTED:
2701 boxes = NESTED;
2702 break;
2703 case OPT_CHAINED:
2704 boxes = CHAINED;
2705 break;
2706 case OPT_ONESECTOR:
2707 boxes = ONESECTOR;
2708 break;
2709
2710 /* more flags */
2711 case OPT_NO_REREAD:
2712 no_reread = 1;
2713 break;
2714 case OPT_LEAVE_LAST:
2715 leave_last = 1;
2716 break;
fd6b7a7f
KZ
2717 }
2718 }
2719
cf3f26bf
KZ
2720 if (optind == argc &&
2721 (opt_list || opt_out_geom || opt_out_pt_geom || opt_size || verify)) {
78917e48
KZ
2722 FILE *procf;
2723
ffc43748 2724 /* try all known devices */
fd6b7a7f 2725 total_size = 0;
78917e48 2726
6bec8710 2727 procf = fopen(_PATH_PROC_PARTITIONS, "r");
78917e48 2728 if (!procf)
6bec8710 2729 fprintf(stderr, _("cannot open %s\n"), _PATH_PROC_PARTITIONS);
78917e48
KZ
2730 else {
2731 while ((dev = nextproc(procf)) != NULL) {
37b94458
KZ
2732 if (!is_ide_cdrom_or_tape(dev)) {
2733 gpt_warning(dev, 1);
2734 if (opt_out_geom)
2735 do_geom(dev, 1);
2736 if (opt_out_pt_geom)
2737 do_pt_geom(dev, 1);
2738 if (opt_size)
2739 do_size(dev, 1);
2740 if (opt_list || verify)
2741 do_list(dev, 1);
6bec8710
KZ
2742 }
2743 free(dev);
78917e48
KZ
2744 }
2745 fclose(procf);
fd6b7a7f
KZ
2746 }
2747
2748 if (opt_size)
37b94458 2749 printf(_("total: %llu blocks\n"), total_size);
fd6b7a7f
KZ
2750
2751 exit(exit_status);
2752 }
2753
2754 if (optind == argc) {
2755 if (activate)
37b94458 2756 activate_usage(fdisk ? "sfdisk -A" : progn);
fd6b7a7f 2757 else if (unhide)
37b94458 2758 unhide_usage(fdisk ? "sfdisk -U" : progn);
fd6b7a7f 2759 else
37b94458 2760 usage(stderr);
fd6b7a7f
KZ
2761 }
2762
cf3f26bf 2763 if (opt_list || opt_out_geom || opt_out_pt_geom || opt_size || verify) {
fd6b7a7f 2764 while (optind < argc) {
5dbff4c0 2765 gpt_warning(argv[optind], 1);
fd6b7a7f 2766 if (opt_out_geom)
37b94458 2767 do_geom(argv[optind], 0);
cf3f26bf 2768 if (opt_out_pt_geom)
37b94458 2769 do_pt_geom(argv[optind], 0);
fd6b7a7f 2770 if (opt_size)
37b94458 2771 do_size(argv[optind], 0);
fd6b7a7f 2772 if (opt_list || verify)
37b94458 2773 do_list(argv[optind], 0);
fd6b7a7f
KZ
2774 optind++;
2775 }
2776 exit(exit_status);
2777 }
2778
37b94458 2779 if (optind != argc - 1)
5dbff4c0
KZ
2780 gpt_warning(argv[optind], 0);
2781
fd6b7a7f 2782 if (activate) {
37b94458 2783 do_activate(argv + optind, argc - optind, activatearg);
fd6b7a7f
KZ
2784 exit(exit_status);
2785 }
2786 if (unhide) {
37b94458 2787 do_unhide(argv + optind, argc - optind, unhidearg);
fd6b7a7f
KZ
2788 exit(exit_status);
2789 }
2790 if (do_id) {
37b94458 2791 if ((do_id & PRINT_ID) != 0 && optind != argc - 2)
109dbc4f 2792 errx(EXIT_FAILURE, _("usage: sfdisk --print-id device partition-number"));
37b94458 2793 else if ((do_id & CHANGE_ID) != 0 && optind != argc - 3)
109dbc4f 2794 errx(EXIT_FAILURE, _("usage: sfdisk --change-id device partition-number Id"));
37b94458 2795 else if (optind != argc - 3 && optind != argc - 2)
109dbc4f 2796 errx(EXIT_FAILURE, _("usage: sfdisk --id device partition-number [Id]"));
37b94458
KZ
2797 do_change_id(argv[optind], argv[optind + 1],
2798 (optind == argc - 2) ? 0 : argv[optind + 2]);
fd6b7a7f
KZ
2799 exit(exit_status);
2800 }
5dbff4c0 2801
37b94458 2802 if (optind != argc - 1)
109dbc4f 2803 errx(EXIT_FAILURE, _("can specify only one device (except with -l or -s)"));
fd6b7a7f
KZ
2804 dev = argv[optind];
2805
2806 if (opt_reread)
37b94458 2807 do_reread(dev);
fd6b7a7f 2808 else if (restore_sector_file)
37b94458 2809 restore_sectors(dev);
fd6b7a7f 2810 else
37b94458 2811 do_fdisk(dev);
fd6b7a7f
KZ
2812
2813 return 0;
2814}
2815
2816/*
2817 * H. Listing the current situation
2818 */
2819
22853e4a 2820static int
37b94458 2821my_open(char *dev, int rw, int silent) {
fd6b7a7f
KZ
2822 int fd, mode;
2823
2824 mode = (rw ? O_RDWR : O_RDONLY);
2825 fd = open(dev, mode);
2826 if (fd < 0 && !silent) {
2827 perror(dev);
e8f26419 2828 if (rw)
109dbc4f 2829 errx(EXIT_FAILURE, _("cannot open %s read-write"), dev);
e8f26419 2830 else
109dbc4f 2831 errx(EXIT_FAILURE, _("cannot open %s for reading"), dev);
fd6b7a7f
KZ
2832 }
2833 return fd;
2834}
2835
22853e4a 2836static void
37b94458 2837do_list(char *dev, int silent) {
fd6b7a7f
KZ
2838 int fd;
2839 struct disk_desc *z;
2840
2841 fd = my_open(dev, 0, silent);
2842 if (fd < 0)
2843 return;
2844
2845 z = &oldp;
2846
2847 free_sectors();
2848 get_cylindersize(dev, fd, dump ? 1 : opt_list ? 0 : 1);
2849 get_partitions(dev, fd, z);
2850
2851 if (opt_list)
37b94458 2852 out_partitions(dev, z);
fd6b7a7f
KZ
2853
2854 if (verify) {
4310e47a 2855 if (partitions_ok(fd, z))
37b94458 2856 my_warn(_("%s: OK\n"), dev);
fd6b7a7f 2857 else
37b94458 2858 exit_status = 1;
fd6b7a7f 2859 }
78917e48
KZ
2860
2861 close(fd);
fd6b7a7f
KZ
2862}
2863
22853e4a 2864static void
37b94458 2865do_geom(char *dev, int silent) {
fd6b7a7f 2866 int fd;
22853e4a 2867 struct geometry R;
fd6b7a7f
KZ
2868
2869 fd = my_open(dev, 0, silent);
2870 if (fd < 0)
2871 return;
2872
22853e4a
KZ
2873 R = get_geometry(dev, fd, silent);
2874 if (R.cylinders)
2875 printf(_("%s: %ld cylinders, %ld heads, %ld sectors/track\n"),
2876 dev, R.cylinders, R.heads, R.sectors);
78917e48
KZ
2877
2878 close(fd);
fd6b7a7f
KZ
2879}
2880
cf3f26bf 2881static void
37b94458 2882do_pt_geom(char *dev, int silent) {
cf3f26bf
KZ
2883 int fd;
2884 struct disk_desc *z;
2885 struct geometry R;
2886
2887 fd = my_open(dev, 0, silent);
2888 if (fd < 0)
2889 return;
2890
2891 z = &oldp;
2892
2893 free_sectors();
2894 get_cylindersize(dev, fd, 1);
2895 get_partitions(dev, fd, z);
2896
2897 R = B;
2898
2899 if (z->partno != 0 && get_fdisk_geometry(z)) {
37b94458
KZ
2900 R.heads = F.heads;
2901 R.sectors = F.sectors;
2902 R.cylindersize = R.heads * R.sectors;
2903 R.cylinders = (R.cylindersize == 0) ? 0 : R.total_size / R.cylindersize;
cf3f26bf
KZ
2904 }
2905
2906 if (R.cylinders)
2907 printf(_("%s: %ld cylinders, %ld heads, %ld sectors/track\n"),
2908 dev, R.cylinders, R.heads, R.sectors);
78917e48
KZ
2909
2910 close(fd);
cf3f26bf
KZ
2911}
2912
fd6b7a7f 2913/* for compatibility with earlier fdisk: provide option -s */
22853e4a 2914static void
37b94458 2915do_size(char *dev, int silent) {
7eda085c 2916 int fd;
2cccd0ff 2917 unsigned long long size;
fd6b7a7f
KZ
2918
2919 fd = my_open(dev, 0, silent);
2920 if (fd < 0)
2921 return;
2922
810f986b 2923 if (blkdev_get_sectors(fd, &size) == -1) {
c129767e 2924 if (!silent) {
fd6b7a7f 2925 perror(dev);
109dbc4f 2926 errx(EXIT_FAILURE, _("Cannot get size of %s"), dev);
fd6b7a7f 2927 }
06c243d3 2928 goto done;
fd6b7a7f
KZ
2929 }
2930
2931 size /= 2; /* convert sectors to blocks */
5c36a0eb
KZ
2932
2933 /* a CDROM drive without mounted CD yields MAXINT */
37b94458 2934 if (silent && size == ((1 << 30) - 1))
06c243d3 2935 goto done;
5c36a0eb 2936
fd6b7a7f 2937 if (silent)
37b94458 2938 printf("%s: %9llu\n", dev, size);
fd6b7a7f 2939 else
37b94458 2940 printf("%llu\n", size);
fd6b7a7f
KZ
2941
2942 total_size += size;
78917e48 2943
06c243d3 2944done:
78917e48 2945 close(fd);
fd6b7a7f
KZ
2946}
2947
2948/*
2949 * Activate: usually one wants to have a single primary partition
2950 * to be active. OS/2 fdisk makes non-bootable logical partitions
2951 * active - I don't know what that means to OS/2 Boot Manager.
2952 *
2953 * Call: activate /dev/hda 2 5 7 make these partitions active
2954 * and the remaining ones inactive
5c36a0eb 2955 * Or: sfdisk -A /dev/hda 2 5 7
fd6b7a7f
KZ
2956 *
2957 * If only a single partition must be active, one may also use the form
5c36a0eb 2958 * sfdisk -A2 /dev/hda
fd6b7a7f 2959 *
5c36a0eb 2960 * With "activate /dev/hda" or "sfdisk -A /dev/hda" the active partitions
fd6b7a7f 2961 * are listed but not changed. To get zero active partitions, use
5c36a0eb
KZ
2962 * "activate /dev/hda none" or "sfdisk -A /dev/hda none".
2963 * Use something like `echo ",,,*" | sfdisk -N2 /dev/hda' to only make
fd6b7a7f
KZ
2964 * /dev/hda2 active, without changing other partitions.
2965 *
2966 * A warning will be given if after the change not precisely one primary
2967 * partition is active.
2968 *
2969 * The present syntax was chosen to be (somewhat) compatible with the
2970 * activate from the LILO package.
2971 */
22853e4a 2972static void
37b94458 2973set_active(struct disk_desc *z, char *pnam) {
fd6b7a7f
KZ
2974 int pno;
2975
2976 pno = asc_to_index(pnam, z);
df1dddf9 2977 if (z->partitions[pno].ptype == DOS_TYPE)
37b94458 2978 z->partitions[pno].p.bootable = 0x80;
fd6b7a7f
KZ
2979}
2980
22853e4a 2981static void
37b94458 2982do_activate(char **av, int ac, char *arg) {
fd6b7a7f
KZ
2983 char *dev = av[0];
2984 int fd;
2985 int rw, i, pno, lpno;
2986 struct disk_desc *z;
2987
2988 z = &oldp;
2989
2990 rw = (!no_write && (arg || ac > 1));
2991 fd = my_open(dev, rw, 0);
2992
2993 free_sectors();
2994 get_cylindersize(dev, fd, 1);
2995 get_partitions(dev, fd, z);
2996
2997 if (!arg && ac == 1) {
2998 /* list active partitions */
37b94458 2999 for (pno = 0; pno < z->partno; pno++) {
fd6b7a7f
KZ
3000 if (z->partitions[pno].p.bootable) {
3001 lpno = index_to_linux(pno, z);
3002 if (pno == linux_to_index(lpno, z))
37b94458 3003 printf("%s\n", partname(dev, lpno, 0));
fd6b7a7f 3004 else
37b94458 3005 printf("%s#%d\n", dev, pno);
fd6b7a7f 3006 if (z->partitions[pno].p.bootable != 0x80)
37b94458
KZ
3007 my_warn(_("bad active byte: 0x%x instead of 0x80\n"),
3008 z->partitions[pno].p.bootable);
fd6b7a7f
KZ
3009 }
3010 }
3011 } else {
3012 /* clear `active byte' everywhere */
37b94458 3013 for (pno = 0; pno < z->partno; pno++)
df1dddf9
KZ
3014 if (z->partitions[pno].ptype == DOS_TYPE)
3015 z->partitions[pno].p.bootable = 0;
fd6b7a7f
KZ
3016
3017 /* then set where desired */
3018 if (ac == 1)
37b94458
KZ
3019 set_active(z, arg);
3020 else
3021 for (i = 1; i < ac; i++)
3022 set_active(z, av[i]);
fd6b7a7f
KZ
3023
3024 /* then write to disk */
c129767e 3025 if (write_partitions(dev, fd, z))
37b94458 3026 my_warn(_("Done\n\n"));
fd6b7a7f 3027 else
37b94458 3028 exit_status = 1;
fd6b7a7f
KZ
3029 }
3030 i = 0;
37b94458
KZ
3031 for (pno = 0; pno < z->partno && pno < 4; pno++)
3032 if (z->partitions[pno].p.bootable)
3033 i++;
fd6b7a7f 3034 if (i != 1)
be350fb9 3035 my_warn(_("You have %d active primary partitions. This does not matter for LILO,\n"
37b94458
KZ
3036 "but the DOS MBR will only boot a disk with 1 active partition.\n"),
3037 i);
78917e48
KZ
3038
3039 close(fd);
fd6b7a7f
KZ
3040}
3041
22853e4a 3042static void
37b94458 3043set_unhidden(struct disk_desc *z, char *pnam) {
fd6b7a7f
KZ
3044 int pno;
3045 unsigned char id;
3046
3047 pno = asc_to_index(pnam, z);
3048 id = z->partitions[pno].p.sys_type;
3049 if (id == 0x11 || id == 0x14 || id == 0x16 || id == 0x17)
37b94458 3050 id -= 0x10;
fd6b7a7f 3051 else
109dbc4f 3052 errx(EXIT_FAILURE, _("partition %s has id %x and is not hidden"), pnam, id);
fd6b7a7f
KZ
3053 z->partitions[pno].p.sys_type = id;
3054}
3055
3056/*
3057 * maybe remove and make part of --change-id
3058 */
22853e4a 3059static void
37b94458 3060do_unhide(char **av, int ac, char *arg) {
fd6b7a7f
KZ
3061 char *dev = av[0];
3062 int fd, rw, i;
3063 struct disk_desc *z;
3064
3065 z = &oldp;
3066
3067 rw = !no_write;
3068 fd = my_open(dev, rw, 0);
3069
3070 free_sectors();
3071 get_cylindersize(dev, fd, 1);
3072 get_partitions(dev, fd, z);
3073
3074 /* unhide where desired */
3075 if (ac == 1)
37b94458
KZ
3076 set_unhidden(z, arg);
3077 else
3078 for (i = 1; i < ac; i++)
3079 set_unhidden(z, av[i]);
fd6b7a7f
KZ
3080
3081 /* then write to disk */
c129767e 3082 if (write_partitions(dev, fd, z))
37b94458 3083 my_warn(_("Done\n\n"));
fd6b7a7f 3084 else
37b94458 3085 exit_status = 1;
78917e48
KZ
3086
3087 close(fd);
fd6b7a7f
KZ
3088}
3089
22853e4a
KZ
3090static void
3091do_change_id(char *dev, char *pnam, char *id) {
fd6b7a7f
KZ
3092 int fd, rw, pno;
3093 struct disk_desc *z;
3094 unsigned long i;
3095
3096 z = &oldp;
3097
3098 rw = !no_write;
3099 fd = my_open(dev, rw, 0);
3100
3101 free_sectors();
3102 get_cylindersize(dev, fd, 1);
3103 get_partitions(dev, fd, z);
3104
3105 pno = asc_to_index(pnam, z);
3106 if (id == 0) {
37b94458 3107 printf("%x\n", z->partitions[pno].p.sys_type);
574d9252 3108 goto done;
fd6b7a7f
KZ
3109 }
3110 i = strtoul(id, NULL, 16);
3111 if (i > 255)
109dbc4f 3112 errx(EXIT_FAILURE, _("Bad Id %lx"), i);
fd6b7a7f
KZ
3113 z->partitions[pno].p.sys_type = i;
3114
c129767e 3115 if (write_partitions(dev, fd, z))
37b94458 3116 my_warn(_("Done\n\n"));
fd6b7a7f 3117 else
37b94458 3118 exit_status = 1;
78917e48 3119
574d9252 3120done:
78917e48 3121 close(fd);
fd6b7a7f
KZ
3122}
3123
22853e4a 3124static void
fd6b7a7f
KZ
3125do_reread(char *dev) {
3126 int fd;
3127
3128 fd = my_open(dev, 0, 0);
e82810c6 3129 if (reread_ioctl(fd)) {
66d28be8 3130 warnx(_("This disk is currently in use.\n"));
37b94458 3131 exit(1);
e82810c6 3132 }
78917e48
KZ
3133
3134 close(fd);
fd6b7a7f
KZ
3135}
3136
3137/*
3138 * I. Writing the new situation
3139 */
3140
22853e4a 3141static void
37b94458 3142do_fdisk(char *dev) {
fd6b7a7f 3143 int fd;
34ca51dc 3144 char answer[32];
fd6b7a7f
KZ
3145 struct stat statbuf;
3146 int interactive = isatty(0);
3147 struct disk_desc *z;
3148
3149 if (stat(dev, &statbuf) < 0) {
3150 perror(dev);
109dbc4f 3151 errx(EXIT_FAILURE, _("Fatal error: cannot find %s"), dev);
fd6b7a7f
KZ
3152 }
3153 if (!S_ISBLK(statbuf.st_mode)) {
66d28be8 3154 warnx(_("Warning: %s is not a block device\n"), dev);
7eda085c 3155 no_reread = 1;
fd6b7a7f
KZ
3156 }
3157 fd = my_open(dev, !no_write, 0);
3158
c129767e 3159 if (!no_write && !no_reread) {
4a01477b 3160 my_warn(_("Checking that no-one is using this disk right now ...\n"));
c129767e 3161 if (reread_ioctl(fd)) {
66d28be8 3162 warnx(_("\nThis disk is currently in use - repartitioning is probably a bad idea.\n"
be350fb9
BS
3163 "Umount all file systems, and swapoff all swap partitions on this disk.\n"
3164 "Use the --no-reread flag to suppress this check.\n"));
fd6b7a7f 3165 if (!force) {
66d28be8 3166 warnx(_("Use the --force flag to overrule all checks.\n"));
fd6b7a7f
KZ
3167 exit(1);
3168 }
3169 } else
37b94458 3170 my_warn(_("OK\n"));
fd6b7a7f
KZ
3171 }
3172
3173 z = &oldp;
3174
3175 free_sectors();
3176 get_cylindersize(dev, fd, 0);
3177 get_partitions(dev, fd, z);
3178
7eda085c 3179 printf(_("Old situation:\n"));
fd6b7a7f
KZ
3180 out_partitions(dev, z);
3181
3182 if (one_only && (one_only_pno = linux_to_index(one_only, z)) < 0)
109dbc4f 3183 errx(EXIT_FAILURE, _("Partition %d does not exist, cannot change it"), one_only);
fd6b7a7f
KZ
3184
3185 z = &newp;
3186
37b94458 3187 while (1) {
fd6b7a7f
KZ
3188
3189 read_input(dev, interactive, z);
3190
7eda085c 3191 printf(_("New situation:\n"));
fd6b7a7f
KZ
3192 out_partitions(dev, z);
3193
4310e47a 3194 if (!partitions_ok(fd, z) && !force) {
c129767e 3195 if (!interactive)
109dbc4f
DB
3196 errx(EXIT_FAILURE, _("I don't like these partitions - nothing changed.\n"
3197 "(If you really want this, use the --force option.)"));
fd6b7a7f 3198 else
66d28be8 3199 warnx(_("I don't like this - probably you should answer No\n"));
fd6b7a7f 3200 }
fd6b7a7f 3201 if (interactive) {
34ca51dc 3202 ask:
fd6b7a7f 3203 if (no_write)
34ca51dc
SK
3204 /* TRANSLATORS: sfdisk uses rpmatch which means the answers y and n
3205 * should be translated, but that is not the case with q answer. */
37b94458 3206 printf(_("Are you satisfied with this? [ynq] "));
fd6b7a7f 3207 else
37b94458 3208 printf(_("Do you want to write this to disk? [ynq] "));
34ca51dc
SK
3209 fgets(answer, sizeof(answer), stdin);
3210 if (answer[0] == 'q' || answer[0] == 'Q') {
109dbc4f 3211 errx(EXIT_FAILURE, _("Quitting - nothing changed"));
34ca51dc 3212 } else if (rpmatch(answer) == 1) {
fd6b7a7f 3213 continue;
34ca51dc 3214 } else if (rpmatch(answer) == 0) {
fd6b7a7f
KZ
3215 break;
3216 } else {
7eda085c 3217 printf(_("Please answer one of y,n,q\n"));
fd6b7a7f
KZ
3218 goto ask;
3219 }
3220 } else
37b94458 3221 break;
fd6b7a7f
KZ
3222 }
3223
c129767e 3224 if (write_partitions(dev, fd, z))
37b94458 3225 printf(_("Successfully wrote the new partition table\n\n"));
fd6b7a7f 3226 else
37b94458 3227 exit_status = 1;
fd6b7a7f 3228
574d9252
KZ
3229 if (!reread_disk_partition(dev, fd)) { /* close fd on success */
3230 close(fd);
37b94458 3231 exit_status = 1;
574d9252 3232 }
be350fb9
BS
3233 my_warn(_("If you created or changed a DOS partition, /dev/foo7, say, then use dd(1)\n"
3234 "to zero the first 512 bytes: dd if=/dev/zero of=/dev/foo7 bs=512 count=1\n"
3235 "(See fdisk(8).)\n"));
78917e48 3236
fd6b7a7f 3237 sync(); /* superstition */
fd6b7a7f
KZ
3238 exit(exit_status);
3239}