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