summaryrefslogtreecommitdiff
path: root/sfdisk.c
diff options
context:
space:
mode:
authorEric Andersen2000-07-07 20:54:30 +0000
committerEric Andersen2000-07-07 20:54:30 +0000
commite6b9dfa96730d9cedfb1f22a4bc0f3bcb6949ea6 (patch)
tree770f9754e5f23af81d0efd9975c0a03feeb6cabb /sfdisk.c
parent53a955786d71ba891cf98e5c5e4bcbbc6f0ded3e (diff)
downloadbusybox-e6b9dfa96730d9cedfb1f22a4bc0f3bcb6949ea6.zip
busybox-e6b9dfa96730d9cedfb1f22a4bc0f3bcb6949ea6.tar.gz
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
Diffstat (limited to 'sfdisk.c')
-rw-r--r--sfdisk.c2999
1 files changed, 0 insertions, 2999 deletions
diff --git a/sfdisk.c b/sfdisk.c
deleted file mode 100644
index 8d2142b..0000000
--- a/sfdisk.c
+++ /dev/null
@@ -1,2999 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * sfdisk version 3.0 - aeb - 950813
- *
- * Copyright (C) 1995 Andries E. Brouwer (aeb@cwi.nl)
- *
- * This program is free software. You can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation: either Version 1
- * or (at your option) any later version.
- *
- * A.V. Le Blanc (LeBlanc@mcc.ac.uk) wrote Linux fdisk 1992-1994,
- * patched by various people (faith@cs.unc.edu, martin@cs.unc.edu,
- * leisner@sdsp.mc.xerox.com, esr@snark.thyrsus.com, aeb@cwi.nl)
- * 1993-1995, with version numbers (as far as I have seen) 0.93 - 2.0e.
- * This program had (head,sector,cylinder) as basic unit, and was
- * (therefore) broken in several ways for the use on larger disks -
- * for example, my last patch (from 2.0d to 2.0e) was required
- * to allow a partition to cross cylinder 8064, and to write an
- * extended partition past the 4GB mark.
- *
- * The current program is a rewrite from scratch, and I started a
- * version numbering at 3.0.
- * Andries Brouwer, aeb@cwi.nl, 950813
- *
- * Well, a good user interface is still lacking. On the other hand,
- * many configurations cannot be handled by any other fdisk.
- * I changed the name to sfdisk to prevent confusion. - aeb, 970501
- *
- * Changes:
- * 19990319 - Arnaldo Carvalho de Melo <acme@conectiva.com.br> - i18n
- *
- * busyboxed by Erik Andersen <andersee@debian.org> -- I stipped out
- * all the NLS, pulled in some includes, and made stuff smaller...
- */
-
-#define PROGNAME "sfdisk"
-#define VERSION "3.07"
-#define DATE "990908"
-
-#include "internal.h"
-#include <stdio.h>
-#include <stdlib.h> /* atoi, free */
-#include <stdarg.h> /* varargs */
-#include <unistd.h> /* read, write */
-#include <fcntl.h> /* O_RDWR */
-#include <errno.h> /* ERANGE */
-#include <string.h> /* index() */
-#include <ctype.h>
-#include <getopt.h>
-#include <sys/ioctl.h>
-#include <sys/stat.h>
-#include <linux/unistd.h> /* _syscall */
-#include <linux/hdreg.h> /* HDIO_GETGEO */
-#include <linux/fs.h> /* BLKGETSIZE */
-
-#define BB_DECLARE_EXTERN
-#define bb_need_memory_exhausted
-#include "messages.c"
-
-static const char sfdisk_usage[] =
- "sfdisk [options] device ...\n"
-#ifndef BB_FEATURE_TRIVIAL_HELP
- "\ndevice: something like /dev/hda or /dev/sda\n"
- "useful options:\n"
- " -s [or --show-size]: list size of a partition\n"
- " -c [or --id]: print or change partition Id\n"
- " -l [or --list]: list partitions of each device\n"
- " -d [or --dump]: idem, but in a format suitable for later input\n"
- " -i [or --increment]: number cylinders etc. from 1 instead of from 0\n"
- " -uS, -uB, -uC, -uM: accept/report in units of sectors/blocks/cylinders/MB\n"
- " -T [or --list-types]:list the known partition types\n"
- " -D [or --DOS]: for DOS-compatibility: waste a little space\n"
- " -R [or --re-read]: make kernel reread partition table\n"
- " -N# : change only the partition with number #\n"
- " -n : do not actually write to disk\n"
- " -O file : save the sectors that will be overwritten to file\n"
- " -I file : restore these sectors again\n"
- " -v [or --version]: print version\n"
- " -? [or --help]: print this message\n"
- "dangerous options:\n"
- " -g [or --show-geometry]: print the kernel's idea of the geometry\n"
- " -x [or --show-extended]: also list extended partitions on output\n\n"
- " or expect descriptors for them on input\n"
- " -L [or --Linux]: do not complain about things irrelevant for Linux\n"
- " -q [or --quiet]: suppress warning messages\n"
- " You can override the detected geometry using:\n"
- " -C# [or --cylinders #]:set the number of cylinders to use\n"
- " -H# [or --heads #]: set the number of heads to use\n"
- " -S# [or --sectors #]: set the number of sectors to use\n"
-
- "You can disable all consistency checking with:\n"
- " -f [or --force]: do what I say, even if it is stupid\n"
-#endif
- ;
-
-
-
-/* common stuff for fdisk, cfdisk, sfdisk */
-struct systypes {
- unsigned char type;
- char *name;
-};
-
-static struct systypes i386_sys_types[] = {
- {0x00, "Empty"},
- {0x01, "FAT12"},
- {0x02, "XENIX root"},
- {0x03, "XENIX usr"},
- {0x04, "FAT16 <32M"},
- {0x05, "Extended"}, /* DOS 3.3+ extended partition */
- {0x06, "FAT16"}, /* DOS 16-bit >=32M */
- {0x07, "HPFS/NTFS"}, /* OS/2 IFS, eg, HPFS or NTFS or QNX */
- {0x08, "AIX"}, /* AIX boot (AIX -- PS/2 port or SplitDrive) */
- {0x09, "AIX bootable"}, /* AIX data or Coherent */
- {0x0a, "OS/2 Boot Manager"}, /* OS/2 Boot Manager */
- {0x0b, "Win95 FAT32"},
- {0x0c, "Win95 FAT32 (LBA)"}, /* LBA really is `Extended Int 13h' */
- {0x0e, "Win95 FAT16 (LBA)"},
- {0x0f, "Win95 Ext'd (LBA)"},
- {0x10, "OPUS"},
- {0x11, "Hidden FAT12"},
- {0x12, "Compaq diagnostics"},
- {0x14, "Hidden FAT16 <32M"},
- {0x16, "Hidden FAT16"},
- {0x17, "Hidden HPFS/NTFS"},
- {0x18, "AST Windows swapfile"},
- {0x1b, "Hidden Win95 FAT32"},
- {0x1c, "Hidden Win95 FAT32 (LBA)"},
- {0x1e, "Hidden Win95 FAT16 (LBA)"},
- {0x24, "NEC DOS"},
- {0x3c, "PartitionMagic recovery"},
- {0x40, "Venix 80286"},
- {0x41, "PPC PReP Boot"},
- {0x42, "SFS"},
- {0x4d, "QNX4.x"},
- {0x4e, "QNX4.x 2nd part"},
- {0x4f, "QNX4.x 3rd part"},
- {0x50, "OnTrack DM"},
- {0x51, "OnTrack DM6 Aux1"}, /* (or Novell) */
- {0x52, "CP/M"}, /* CP/M or Microport SysV/AT */
- {0x53, "OnTrack DM6 Aux3"},
- {0x54, "OnTrackDM6"},
- {0x55, "EZ-Drive"},
- {0x56, "Golden Bow"},
- {0x5c, "Priam Edisk"},
- {0x61, "SpeedStor"},
- {0x63, "GNU HURD or SysV"}, /* GNU HURD or Mach or Sys V/386 (such as ISC UNIX) */
- {0x64, "Novell Netware 286"},
- {0x65, "Novell Netware 386"},
- {0x70, "DiskSecure Multi-Boot"},
- {0x75, "PC/IX"},
- {0x80, "Old Minix"}, /* Minix 1.4a and earlier */
- {0x81, "Minix / old Linux"}, /* Minix 1.4b and later */
- {0x82, "Linux swap"}, /* also Solaris */
- {0x83, "Linux"},
- {0x84, "OS/2 hidden C: drive"},
- {0x85, "Linux extended"},
- {0x86, "NTFS volume set"},
- {0x87, "NTFS volume set"},
- {0x93, "Amoeba"},
- {0x94, "Amoeba BBT"}, /* (bad block table) */
- {0xa0, "IBM Thinkpad hibernation"},
- {0xa5, "BSD/386"},
- {0xa6, "OpenBSD"},
- {0xa7, "NeXTSTEP"},
- {0xb7, "BSDI fs"},
- {0xb8, "BSDI swap"},
- {0xc1, "DRDOS/sec (FAT-12)"},
- {0xc4, "DRDOS/sec (FAT-16 < 32M)"},
- {0xc6, "DRDOS/sec (FAT-16)"},
- {0xc7, "Syrinx"},
- {0xdb, "CP/M / CTOS / ..."}, /* CP/M or Concurrent CP/M or Concurrent DOS or CTOS */
- {0xe1, "DOS access"}, /* DOS access or SpeedStor 12-bit FAT extended partition */
- {0xe3, "DOS R/O"}, /* DOS R/O or SpeedStor */
- {0xe4, "SpeedStor"}, /* SpeedStor 16-bit FAT extended partition < 1024 cyl. */
- {0xeb, "BeOS fs"},
- {0xf1, "SpeedStor"},
- {0xf4, "SpeedStor"}, /* SpeedStor large partition */
- {0xf2, "DOS secondary"}, /* DOS 3.3+ secondary */
- {0xfd, "Linux raid autodetect"}, /* New (2.2.x) raid partition with autodetect
- using persistent superblock */
- {0xfe, "LANstep"}, /* SpeedStor >1024 cyl. or LANstep */
- {0xff, "BBT"}, /* Xenix Bad Block Table */
- {0, 0}
-};
-
-#define SIZE(a) (sizeof(a)/sizeof(a[0]))
-
-/*
- * Table of contents:
- * A. About seeking
- * B. About sectors
- * C. About heads, sectors and cylinders
- * D. About system Ids
- * E. About partitions
- * F. The standard input
- * G. The command line
- * H. Listing the current situation
- * I. Writing the new situation
- */
-static int exit_status = 0;
-
-static int force = 0; /* 1: do what I say, even if it is stupid ... */
-static int quiet = 0; /* 1: suppress all warnings */
-static int Linux = 0; /* 1: suppress warnings irrelevant for Linux */
-static int DOS = 0; /* 1: shift extended partitions by #sectors, not 1 */
-static int dump = 0; /* 1: list in a format suitable for later input */
-static int verify = 0; /* 1: check that listed partition is reasonable */
-static int no_write = 0; /* 1: do not actually write to disk */
-static int no_reread = 0; /* 1: skip the BLKRRPART ioctl test at startup */
-static int leave_last = 0; /* 1: don't allocate the last cylinder */
-static int opt_list = 0;
-static char *save_sector_file = NULL;
-static char *restore_sector_file = NULL;
-
-static void warn(char *s, ...) __attribute__ ((format (printf, 1, 2)));
-static void warn(char *s, ...)
-{
- va_list p;
-
- va_start(p, s);
- fflush(stdout);
- if (!quiet)
- vfprintf(stderr, s, p);
- va_end(p);
-}
-
-/*
- * A. About seeking
- */
-
-/*
- * sseek: seek to specified sector - return 0 on failure
- *
- * For >4GB disks lseek needs a > 32bit arg, and we have to use llseek.
- * On the other hand, a 32 bit sector number is OK until 2TB.
- * The routines _llseek and sseek below are the only ones that
- * know about the loff_t type.
- */
-#ifndef __alpha__
-static
-_syscall5(int, _llseek, uint, fd, ulong, hi, ulong, lo,
- loff_t *, res, uint, wh);
-#endif
-
-static int sseek(char *dev, unsigned int fd, unsigned long s)
-{
- loff_t in, out;
-
- in = ((loff_t) s << 9);
- out = 1;
-
-#ifndef __alpha__
- if (_llseek(fd, in >> 32, in & 0xffffffff, &out, SEEK_SET) != 0) {
-#else
- if ((out = lseek(fd, in, SEEK_SET)) != in) {
-#endif
- perror("llseek");
- errorMsg("seek error on %s - cannot seek to %lu\n", dev, s);
- return 0;
- }
-
- if (in != out) {
- errorMsg("seek error: wanted 0x%08x%08x, got 0x%08x%08x\n",
- (uint) (in >> 32), (uint) (in & 0xffffffff),
- (uint) (out >> 32), (uint) (out & 0xffffffff));
- return 0;
- }
- return 1;
-}
-
-/*
- * B. About sectors
- */
-
-/*
- * We preserve all sectors read in a chain - some of these will
- * have to be modified and written back.
- */
-struct sector {
- struct sector *next;
- unsigned long sectornumber;
- int to_be_written;
- char data[512];
-} *sectorhead;
-
-static void free_sectors(void)
-{
- struct sector *s;
-
- while (sectorhead) {
- s = sectorhead;
- sectorhead = s->next;
- free(s);
- }
-}
-
-static struct sector *get_sector(char *dev, int fd, unsigned long sno)
-{
- struct sector *s;
-
- for (s = sectorhead; s; s = s->next)
- if (s->sectornumber == sno)
- return s;
-
- if (!sseek(dev, fd, sno))
- return 0;
-
- s = (struct sector *) xmalloc(sizeof(struct sector));
-
- if (read(fd, s->data, sizeof(s->data)) != sizeof(s->data)) {
- perror("read");
- errorMsg("read error on %s - cannot read sector %lu\n", dev, sno);
- free(s);
- return 0;
- }
-
- s->next = sectorhead;
- sectorhead = s;
- s->sectornumber = sno;
- s->to_be_written = 0;
-
- return s;
-}
-
-static int msdos_signature(struct sector *s)
-{
- if (*(unsigned short *) (s->data + 0x1fe) != 0xaa55) {
- errorMsg("ERROR: sector %lu does not have an msdos signature\n",
- s->sectornumber);
- return 0;
- }
- return 1;
-}
-
-static int write_sectors(char *dev, int fd)
-{
- struct sector *s;
-
- for (s = sectorhead; s; s = s->next)
- if (s->to_be_written) {
- if (!sseek(dev, fd, s->sectornumber))
- return 0;
- if (write(fd, s->data, sizeof(s->data)) != sizeof(s->data)) {
- perror("write");
- errorMsg("write error on %s - cannot write sector %lu\n",
- dev, s->sectornumber);
- return 0;
- }
- s->to_be_written = 0;
- }
- return 1;
-}
-
-static void ulong_to_chars(unsigned long u, char *uu)
-{
- int i;
-
- for (i = 0; i < 4; i++) {
- uu[i] = (u & 0xff);
- u >>= 8;
- }
-}
-
-static unsigned long chars_to_ulong(unsigned char *uu)
-{
- int i;
- unsigned long u = 0;
-
- for (i = 3; i >= 0; i--)
- u = (u << 8) | uu[i];
- return u;
-}
-
-static int save_sectors(char *dev, int fdin)
-{
- struct sector *s;
- char ss[516];
- int fdout;
-
- fdout = open(save_sector_file, O_WRONLY | O_CREAT, 0444);
- if (fdout < 0) {
- perror(save_sector_file);
- errorMsg("cannot open partition sector save file (%s)\n",
- save_sector_file);
- return 0;
- }
-
- for (s = sectorhead; s; s = s->next)
- if (s->to_be_written) {
- ulong_to_chars(s->sectornumber, ss);
- if (!sseek(dev, fdin, s->sectornumber))
- return 0;
- if (read(fdin, ss + 4, 512) != 512) {
- perror("read");
- errorMsg("read error on %s - cannot read sector %lu\n",
- dev, s->sectornumber);
- return 0;
- }
- if (write(fdout, ss, sizeof(ss)) != sizeof(ss)) {
- perror("write");
- errorMsg("write error on %s\n", save_sector_file);
- return 0;
- }
- }
- return 1;
-}
-
-static void reread_disk_partition(char *dev, int fd);
-
-static int restore_sectors(char *dev)
-{
- int fdin, fdout, ct;
- struct stat statbuf;
- char *ss0, *ss;
- unsigned long sno;
-
- if (stat(restore_sector_file, &statbuf) < 0) {
- perror(restore_sector_file);
- errorMsg("cannot stat partition restore file (%s)\n",
- restore_sector_file);
- return 0;
- }
- if (statbuf.st_size % 516) {
- errorMsg("partition restore file has wrong size - not restoring\n");
- return 0;
- }
- if (!(ss = (char *) malloc(statbuf.st_size))) {
- errorMsg(memory_exhausted, "sfdisk");
- return 0;
- }
- fdin = open(restore_sector_file, O_RDONLY);
- if (fdin < 0) {
- perror(restore_sector_file);
- errorMsg("cannot open partition restore file (%s)\n",
- restore_sector_file);
- return 0;
- }
- if (read(fdin, ss, statbuf.st_size) != statbuf.st_size) {
- perror("read");
- errorMsg("error reading %s\n", restore_sector_file);
- return 0;
- }
-
- fdout = open(dev, O_WRONLY);
- if (fdout < 0) {
- perror(dev);
- errorMsg("cannot open device %s for writing\n", dev);
- return 0;
- }
-
- ss0 = ss;
- ct = statbuf.st_size / 516;
- while (ct--) {
- sno = chars_to_ulong(ss);
- if (!sseek(dev, fdout, sno))
- return 0;
- if (write(fdout, ss + 4, 512) != 512) {
- perror(dev);
- errorMsg("error writing sector %lu on %s\n", sno, dev);
- return 0;
- }
- ss += 516;
- }
- free(ss0);
-
- reread_disk_partition(dev, fdout);
-
- return 1;
-}
-
-/*
- * C. About heads, sectors and cylinders
- */
-
-/*
- * <linux/hdreg.h> defines HDIO_GETGEO and
- * struct hd_geometry {
- * unsigned char heads;
- * unsigned char sectors;
- * unsigned short cylinders;
- * unsigned long start;
- * };
- */
-
-/*
- * We consider several geometries for a disk:
- * B - the BIOS geometry, gotten from the kernel via HDIO_GETGEO
- * F - the fdisk geometry
- * U - the user-specified geometry
- *
- * 0 means unspecified / unknown
- */
-struct geometry {
- unsigned long cylindersize;
- unsigned long heads, sectors, cylinders;
-} B, F, U;
-
-static void get_cylindersize(char *dev, int fd, int silent)
-{
- struct hd_geometry g;
- int ioctl_ok = 0;
-
- B.heads = B.sectors = B.cylinders = 0;
-
- if (!ioctl(fd, HDIO_GETGEO, &g)) {
- ioctl_ok = 1;
-
- B.heads = g.heads;
- B.sectors = g.sectors;
- B.cylinders = g.cylinders;
- }
-
- if (U.heads)
- B.heads = U.heads;
- if (U.sectors)
- B.sectors = U.sectors;
- if (U.cylinders)
- B.cylinders = U.cylinders;
-
- B.cylindersize = B.heads * B.sectors;
-
- if (ioctl_ok) {
- if (g.start && !force) {
- warn
- ("Warning: start=%ld - this looks like a partition rather than\n"
- "the entire disk. Using fdisk on it is probably meaningless.\n"
- "[Use the --force option if you really want this]\n",
- g.start);
- exit(1);
- }
- if (B.heads != g.heads)
- warn("Warning: HDIO_GETGEO says that there are %d heads\n",
- g.heads);
- if (B.sectors != g.sectors)
- warn("Warning: HDIO_GETGEO says that there are %d sectors\n",
- g.sectors);
- if (B.cylinders != g.cylinders)
- warn("Warning: HDIO_GETGEO says that there are %d cylinders\n",
- g.cylinders);
- } else if (!silent)
- if (!B.heads || !B.sectors || !B.cylinders)
- printf("Disk %s: cannot get geometry\n", dev);
- if (B.sectors > 63)
- warn
- ("Warning: unlikely number of sectors (%ld - usually at most 63\n"
- "This will give problems with all software that uses C/H/S addressing.\n",
- B.sectors);
- if (!silent)
- printf("\nDisk %s: %lu cylinders, %lu heads, %lu sectors/track\n",
- dev, B.cylinders, B.heads, B.sectors);
-}
-
-typedef struct {
- unsigned char h, s, c;
-} chs; /* has some c bits in s */
-static chs zero_chs = { 0, 0, 0 };
-
-typedef struct {
- unsigned long h, s, c;
-} longchs;
-static longchs zero_longchs;
-
-static chs longchs_to_chs(longchs aa, struct geometry G)
-{
- chs a;
-
- if (aa.h < 256 && aa.s < 64 && aa.c < 1024) {
- a.h = aa.h;
- a.s = aa.s | ((aa.c >> 2) & 0xc0);
- a.c = (aa.c & 0xff);
- } else if (G.heads && G.sectors) {
- a.h = G.heads - 1;
- a.s = G.sectors | 0xc0;
- a.c = 0xff;
- } else
- a = zero_chs;
- return a;
-}
-
-static longchs chs_to_longchs(chs a)
-{
- longchs aa;
-
- aa.h = a.h;
- aa.s = (a.s & 0x3f);
- aa.c = (a.s & 0xc0);
- aa.c = (aa.c << 2) + a.c;
- return aa;
-}
-
-static longchs ulong_to_longchs(unsigned long sno, struct geometry G)
-{
- longchs aa;
-
- if (G.heads && G.sectors && G.cylindersize) {
- aa.s = 1 + sno % G.sectors;
- aa.h = (sno / G.sectors) % G.heads;
- aa.c = sno / G.cylindersize;
- return aa;
- } else {
- return zero_longchs;
- }
-}
-
-//static unsigned long
-//longchs_to_ulong (longchs aa, struct geometry G) {
-// return (aa.c*G.cylindersize + aa.h*G.sectors + aa.s - 1);
-//}
-
-static chs ulong_to_chs(unsigned long sno, struct geometry G)
-{
- return longchs_to_chs(ulong_to_longchs(sno, G), G);
-}
-
-//static unsigned long
-//chs_to_ulong (chs a, struct geometry G) {
-// return longchs_to_ulong(chs_to_longchs(a), G);
-//}
-
-static int is_equal_chs(chs a, chs b)
-{
- return (a.h == b.h && a.s == b.s && a.c == b.c);
-}
-
-static int chs_ok(chs a, char *v, char *w)
-{
- longchs aa = chs_to_longchs(a);
- int ret = 1;
-
- if (is_equal_chs(a, zero_chs))
- return 1;
- if (B.heads && aa.h >= B.heads) {
- warn("%s of partition %s has impossible value for head: "
- "%ld (should be in 0-%ld)\n", w, v, aa.h, B.heads - 1);
- ret = 0;
- }
- if (B.sectors && (aa.s == 0 || aa.s > B.sectors)) {
- warn("%s of partition %s has impossible value for sector: "
- "%ld (should be in 1-%ld)\n", w, v, aa.s, B.sectors);
- ret = 0;
- }
- if (B.cylinders && aa.c >= B.cylinders) {
- warn("%s of partition %s has impossible value for cylinders: "
- "%ld (should be in 0-%ld)\n", w, v, aa.c, B.cylinders - 1);
- ret = 0;
- }
- return ret;
-}
-
-/*
- * D. About system Ids
- */
-
-#define EMPTY_PARTITION 0
-#define EXTENDED_PARTITION 5
-#define WIN98_EXTENDED 0x0f
-#define DM6_AUX1PARTITION 0x51
-#define DM6_AUX3PARTITION 0x53
-#define DM6_PARTITION 0x54
-#define EZD_PARTITION 0x55
-#define LINUX_SWAP 0x82
-#define LINUX_NATIVE 0x83
-#define LINUX_EXTENDED 0x85
-#define BSD_PARTITION 0xa5
-
-/* List of partition types now in i386_sys_types.c */
-
-static const char *sysname(unsigned char type)
-{
- struct systypes *s;
-
- for (s = i386_sys_types; s->name; s++)
- if (s->type == type)
- return s->name;
- return "Unknown";
-}
-
-static void list_types(void)
-{
- struct systypes *s;
-
- printf("Id Name\n\n");
- for (s = i386_sys_types; s->name; s++)
- printf("%2x %s\n", s->type, s->name);
-}
-
-static int is_extended(unsigned char type)
-{
- return (type == EXTENDED_PARTITION
- || type == LINUX_EXTENDED || type == WIN98_EXTENDED);
-}
-
-static int is_bsd(unsigned char type)
-{
- return (type == BSD_PARTITION);
-}
-
-/*
- * E. About partitions
- */
-
-/* MS/DOS partition */
-
-struct partition {
- unsigned char bootable; /* 0 or 0x80 */
- chs begin_chs;
- unsigned char sys_type;
- chs end_chs;
- unsigned int start_sect; /* starting sector counting from 0 */
- unsigned int nr_sects; /* nr of sectors in partition */
-};
-
-/* Unfortunately, partitions are not aligned, and non-Intel machines
- are unhappy with non-aligned integers. So, we need a copy by hand. */
-static int copy_to_int(unsigned char *cp)
-{
- unsigned int m;
-
- m = *cp++;
- m += (*cp++ << 8);
- m += (*cp++ << 16);
- m += (*cp++ << 24);
- return m;
-}
-
-static void copy_from_int(int m, char *cp)
-{
- *cp++ = (m & 0xff);
- m >>= 8;
- *cp++ = (m & 0xff);
- m >>= 8;
- *cp++ = (m & 0xff);
- m >>= 8;
- *cp++ = (m & 0xff);
-}
-
-static void copy_to_part(char *cp, struct partition *p)
-{
- p->bootable = *cp++;
- p->begin_chs.h = *cp++;
- p->begin_chs.s = *cp++;
- p->begin_chs.c = *cp++;
- p->sys_type = *cp++;
- p->end_chs.h = *cp++;
- p->end_chs.s = *cp++;
- p->end_chs.c = *cp++;
- p->start_sect = copy_to_int(cp);
- p->nr_sects = copy_to_int(cp + 4);
-}
-
-static void copy_from_part(struct partition *p, char *cp)
-{
- *cp++ = p->bootable;
- *cp++ = p->begin_chs.h;
- *cp++ = p->begin_chs.s;
- *cp++ = p->begin_chs.c;
- *cp++ = p->sys_type;
- *cp++ = p->end_chs.h;
- *cp++ = p->end_chs.s;
- *cp++ = p->end_chs.c;
- copy_from_int(p->start_sect, cp);
- copy_from_int(p->nr_sects, cp + 4);
-}
-
-/* Roughly speaking, Linux doesn't use any of the above fields except
- for partition type, start sector and number of sectors. (However,
- see also linux/drivers/scsi/fdomain.c.)
- The only way partition type is used (in the kernel) is the comparison
- for equality with EXTENDED_PARTITION (and these Disk Manager types). */
-
-struct part_desc {
- unsigned long start;
- unsigned long size;
- unsigned long sector, offset; /* disk location of this info */
- struct partition p;
- struct part_desc *ep; /* extended partition containing this one */
- int ptype;
-#define DOS_TYPE 0
-#define BSD_TYPE 1
-} zero_part_desc;
-
-struct part_desc *outer_extended_partition(struct part_desc *p)
-{
- while (p->ep)
- p = p->ep;
- return p;
-}
-
-static int is_parent(struct part_desc *pp, struct part_desc *p)
-{
- while (p) {
- if (pp == p)
- return 1;
- p = p->ep;
- }
- return 0;
-}
-
-struct disk_desc {
- struct part_desc partitions[128];
- int partno;
-} oldp, newp;
-
-/* determine where on the disk this information goes */
-static void add_sector_and_offset(struct disk_desc *z)
-{
- int pno;
- struct part_desc *p;
-
- for (pno = 0; pno < z->partno; pno++) {
- p = &(z->partitions[pno]);
- p->offset = 0x1be + (pno % 4) * sizeof(struct partition);
-
- p->sector = (p->ep ? p->ep->start : 0);
- }
-}
-
-/* tell the kernel to reread the partition tables */
-static int reread_ioctl(int fd)
-{
- if (ioctl(fd, BLKRRPART)) {
- perror("BLKRRPART");
- return -1;
- }
- return 0;
-}
-
-static int is_blockdev(int fd)
-{
- struct stat statbuf;
-
- return (fstat(fd, &statbuf) == 0 && S_ISBLK(statbuf.st_mode));
-}
-
-/* reread after writing */
-static void reread_disk_partition(char *dev, int fd)
-{
- printf("Re-reading the partition table ...\n");
- fflush(stdout);
- sync();
- sleep(3); /* superfluous since 1.3.20 */
-
- if (reread_ioctl(fd) && is_blockdev(fd))
- printf("The command to re-read the partition table failed\n"
- "Reboot your system now, before using mkfs\n");
-
- if (close(fd)) {
- perror(dev);
- printf("Error closing %s\n", dev);
- }
- printf("\n");
-}
-
-/* find Linux name of this partition, assuming that it will have a name */
-static int index_to_linux(int pno, struct disk_desc *z)
-{
- int i, ct = 1;
- struct part_desc *p = &(z->partitions[0]);
-
- for (i = 0; i < pno; i++, p++)
- if (i < 4 || (p->size > 0 && !is_extended(p->p.sys_type)))
- ct++;
- return ct;
-}
-
-static int linux_to_index(int lpno, struct disk_desc *z)
-{
- int i, ct = 0;
- struct part_desc *p = &(z->partitions[0]);
-
- for (i = 0; i < z->partno && ct < lpno; i++, p++)
- if ((i < 4 || (p->size > 0 && !is_extended(p->p.sys_type)))
- && ++ct == lpno)
- return i;
- return -1;
-}
-
-static int asc_to_index(char *pnam, struct disk_desc *z)
-{
- int pnum, pno;
-
- if (*pnam == '#') {
- pno = atoi(pnam + 1);
- } else {
- pnum = atoi(pnam);
- pno = linux_to_index(pnum, z);
- }
- if (!(pno >= 0 && pno < z->partno))
- fatalError("%s: no such partition\n", pnam);
- return pno;
-}
-
-/*
- * List partitions - in terms of sectors, blocks or cylinders
- */
-#define F_SECTOR 1
-#define F_BLOCK 2
-#define F_CYLINDER 3
-#define F_MEGABYTE 4
-
-static int default_format = F_MEGABYTE;
-static int specified_format = 0;
-static int show_extended = 0;
-static int one_only = 0;
-static int one_only_pno;
-static int increment = 0;
-
-static void set_format(char c)
-{
- switch (c) {
- default:
- printf("unrecognized format - using sectors\n");
- case 'S':
- specified_format = F_SECTOR;
- break;
- case 'B':
- specified_format = F_BLOCK;
- break;
- case 'C':
- specified_format = F_CYLINDER;
- break;
- case 'M':
- specified_format = F_MEGABYTE;
- break;
- }
-}
-
-static unsigned long unitsize(int format)
-{
- default_format = (B.cylindersize ? F_CYLINDER : F_MEGABYTE);
- if (!format && !(format = specified_format))
- format = default_format;
-
- switch (format) {
- default:
- case F_CYLINDER:
- if (B.cylindersize)
- return B.cylindersize;
- case F_SECTOR:
- return 1;
- case F_BLOCK:
- return 2;
- case F_MEGABYTE:
- return 2048;
- }
-}
-
-static unsigned long get_disksize(int format)
-{
- unsigned long cs = B.cylinders;
-
- if (cs && leave_last)
- cs--;
- return (cs * B.cylindersize) / unitsize(format);
-}
-
-static void out_partition_header(char *dev, int format, struct geometry G)
-{
- if (dump) {
- printf("# partition table of %s\n", dev);
- printf("unit: sectors\n\n");
- return;
- }
-
- default_format = (G.cylindersize ? F_CYLINDER : F_MEGABYTE);
- if (!format && !(format = specified_format))
- format = default_format;
-
- switch (format) {
- default:
- printf("unimplemented format - using %s\n",
- G.cylindersize ? "cylinders" : "sectors");
- case F_CYLINDER:
- if (G.cylindersize) {
- printf("Units = cylinders of %lu bytes, blocks of 1024 bytes"
- ", counting from %d\n\n",
- G.cylindersize << 9, increment);
- printf
- (" Device Boot Start End #cyls #blocks Id System\n");
- break;
- }
- /* fall through */
- case F_SECTOR:
- printf("Units = sectors of 512 bytes, counting from %d\n\n",
- increment);
- printf
- (" Device Boot Start End #sectors Id System\n");
- break;
- case F_BLOCK:
- printf("Units = blocks of 1024 bytes, counting from %d\n\n",
- increment);
- printf
- (" Device Boot Start End #blocks Id System\n");
- break;
- case F_MEGABYTE:
- printf("Units = megabytes of 1048576 bytes, blocks of 1024 bytes"
- ", counting from %d\n\n", increment);
- printf
- (" Device Boot Start End MB #blocks Id System\n");
- break;
- }
-}
-
-static void
-out_rounddown(int width, unsigned long n, unsigned long unit, int inc)
-{
- printf("%*lu", width, inc + n / unit);
- if (unit != 1)
- putchar((n % unit) ? '+' : ' ');
- putchar(' ');
-}
-
-static void
-out_roundup(int width, unsigned long n, unsigned long unit, int inc)
-{
- if (n == (unsigned long) (-1))
- printf("%*s", width, "-");
- else
- printf("%*lu", width, inc + n / unit);
- if (unit != 1)
- putchar(((n + 1) % unit) ? '-' : ' ');
- putchar(' ');
-}
-
-static void
-out_roundup_size(int width, unsigned long n, unsigned long unit)
-{
- printf("%*lu", width, (n + unit - 1) / unit);
- if (unit != 1)
- putchar((n % unit) ? '-' : ' ');
- putchar(' ');
-}
-
-static int get_fdisk_geometry(struct part_desc *p)
-{
- chs b = p->p.end_chs;
- longchs bb = chs_to_longchs(b);
-
- F.heads = bb.h + 1;
- F.sectors = bb.s;
- F.cylindersize = F.heads * F.sectors;
- return (F.sectors != B.sectors || F.heads != B.heads);
-}
-
-static void
-out_partition(char *dev, int format, struct part_desc *p,
- struct disk_desc *z, struct geometry G)
-{
- unsigned long start, end, size;
- int pno, lpno;
-
- if (!format && !(format = specified_format))
- format = default_format;
-
- pno = p - &(z->partitions[0]); /* our index */
- lpno = index_to_linux(pno, z); /* name of next one that has a name */
- if (pno == linux_to_index(lpno, z)) /* was that us? */
- printf("%8s%-2u", dev, lpno); /* yes */
- else if (show_extended)
- printf(" - ");
- else
- return;
- putchar(dump ? ':' : ' ');
-
- start = p->start;
- end = p->start + p->size - 1;
- size = p->size;
-
- if (dump) {
- printf(" start=%9lu", start);
- printf(", size=%8lu", size);
- if (p->ptype == DOS_TYPE) {
- printf(", Id=%2x", p->p.sys_type);
- if (p->p.bootable == 0x80)
- printf(", bootable");
- }
- printf("\n");
- return;
- }
-
- if (p->ptype != DOS_TYPE || p->p.bootable == 0)
- printf(" ");
- else if (p->p.bootable == 0x80)
- printf(" * ");
- else
- printf(" ? "); /* garbage */
-
- switch (format) {
- case F_CYLINDER:
- if (G.cylindersize) {
- out_rounddown(6, start, G.cylindersize, increment);
- out_roundup(6, end, G.cylindersize, increment);
- out_roundup_size(6, size, G.cylindersize);
- out_rounddown(8, size, 2, 0);
- break;
- }
- /* fall through */
- default:
- case F_SECTOR:
- out_rounddown(9, start, 1, increment);
- out_roundup(9, end, 1, increment);
- out_rounddown(9, size, 1, 0);
- break;
- case F_BLOCK:
-#if 0
- printf("%8lu,%3lu ",
- p->sector / 2, ((p->sector & 1) ? 512 : 0) + p->offset);
-#endif
- out_rounddown(8, start, 2, increment);
- out_roundup(8, end, 2, increment);
- out_rounddown(8, size, 2, 0);
- break;
- case F_MEGABYTE:
- out_rounddown(5, start, 2048, increment);
- out_roundup(5, end, 2048, increment);
- out_roundup_size(5, size, 2048);
- out_rounddown(8, size, 2, 0);
- break;
- }
- if (p->ptype == DOS_TYPE) {
- printf(" %2x %s\n", p->p.sys_type, sysname(p->p.sys_type));
- } else {
- printf("\n");
- }
-
- /* Is chs as we expect? */
- if (!quiet && p->ptype == DOS_TYPE) {
- chs a, b;
- longchs aa, bb;
-
- a = (size ? ulong_to_chs(start, G) : zero_chs);
- b = p->p.begin_chs;
- aa = chs_to_longchs(a);
- bb = chs_to_longchs(b);
- if (a.s && !is_equal_chs(a, b))
- printf
- ("\t\tstart: (c,h,s) expected (%ld,%ld,%ld) found (%ld,%ld,%ld)\n",
- aa.c, aa.h, aa.s, bb.c, bb.h, bb.s);
- a = (size ? ulong_to_chs(end, G) : zero_chs);
- b = p->p.end_chs;
- aa = chs_to_longchs(a);
- bb = chs_to_longchs(b);
- if (a.s && !is_equal_chs(a, b))
- printf
- ("\t\tend: (c,h,s) expected (%ld,%ld,%ld) found (%ld,%ld,%ld)\n",
- aa.c, aa.h, aa.s, bb.c, bb.h, bb.s);
- if (G.cylinders && G.cylinders < 1024 && bb.c > G.cylinders)
- printf
- ("partition ends on cylinder %ld, beyond the end of the disk\n",
- bb.c);
- }
-}
-
-static void out_partitions(char *dev, struct disk_desc *z)
-{
- struct part_desc *p;
- int pno, format = 0;
-
- if (z->partno == 0)
- printf("No partitions found\n");
- else {
- for (pno = 0; pno < z->partno; pno++) {
- p = &(z->partitions[pno]);
- if (p->size != 0 && p->p.sys_type != 0) {
- if (get_fdisk_geometry(p))
- printf
- ("Warning: The first partition looks like it was made\n"
- " for C/H/S=*/%ld/%ld (instead of %ld/%ld/%ld).\n"
- "For this listing I'll assume that geometry.\n",
- F.heads, F.sectors, B.cylinders, B.heads,
- B.sectors);
- break;
- }
- }
- out_partition_header(dev, format, F);
- for (pno = 0; pno < z->partno; pno++) {
- out_partition(dev, format, &(z->partitions[pno]), z, F);
- if (show_extended && pno % 4 == 3)
- printf("\n");
- }
- }
-}
-
-static int disj(struct part_desc *p, struct part_desc *q)
-{
- return ((p->start + p->size <= q->start)
- || (is_extended(p->p.sys_type)
- && q->start + q->size <= p->start + p->size));
-}
-
-static char *pnumber(struct part_desc *p, struct disk_desc *z)
-{
- static char buf[20];
- int this, next;
- struct part_desc *p0 = &(z->partitions[0]);
-
- this = index_to_linux(p - p0, z);
- next = index_to_linux(p - p0 + 1, z);
-
- if (next > this)
- sprintf(buf, "%d", this);
- else
- sprintf(buf, "[%d]", this);
- return buf;
-}
-
-static int partitions_ok(struct disk_desc *z)
-{
- struct part_desc *partitions = &(z->partitions[0]), *p, *q;
- int partno = z->partno;
-
-#define PNO(p) pnumber(p, z)
-
- /* Have at least 4 partitions been defined? */
- if (partno < 4) {
- if (!partno)
- fatalError("no partition table present.\n");
- else
- fatalError("strange, only %d partitions defined.\n", partno);
- return 0;
- }
-
- /* Are the partitions of size 0 marked empty?
- And do they have start = 0? And bootable = 0? */
- for (p = partitions; p - partitions < partno; p++)
- if (p->size == 0) {
- if (p->p.sys_type != EMPTY_PARTITION)
- warn
- ("Warning: partition %s has size 0 but is not marked Empty\n",
- PNO(p));
- else if (p->p.bootable != 0)
- warn("Warning: partition %s has size 0 and is bootable\n",
- PNO(p));
- else if (p->p.start_sect != 0)
- warn
- ("Warning: partition %s has size 0 and nonzero start\n",
- PNO(p));
- /* all this is probably harmless, no error return */
- }
-
- /* Are the logical partitions contained in their extended partitions? */
- for (p = partitions + 4; p < partitions + partno; p++)
- if (p->ptype == DOS_TYPE)
- if (p->size && !is_extended(p->p.sys_type)) {
- q = p->ep;
- if (p->start < q->start
- || p->start + p->size > q->start + q->size) {
- warn("Warning: partition %s ", PNO(p));
- warn("is not contained in partition %s\n", PNO(q));
- return 0;
- }
- }
-
- /* Are the data partitions mutually disjoint? */
- for (p = partitions; p < partitions + partno; p++)
- if (p->size && !is_extended(p->p.sys_type))
- for (q = p + 1; q < partitions + partno; q++)
- if (q->size && !is_extended(q->p.sys_type))
- if (!((p->start > q->start) ? disj(q, p) : disj(p, q))) {
- warn("Warning: partitions %s ", PNO(p));
- warn("and %s overlap\n", PNO(q));
- return 0;
- }
-
- /* Are the data partitions and the extended partition
- table sectors disjoint? */
- for (p = partitions; p < partitions + partno; p++)
- if (p->size && !is_extended(p->p.sys_type))
- for (q = partitions; q < partitions + partno; q++)
- if (is_extended(q->p.sys_type))
- if (p->start <= q->start
- && p->start + p->size > q->start) {
- warn("Warning: partition %s contains part of ",
- PNO(p));
- warn("the partition table (sector %lu),\n",
- q->start);
- warn("and will destroy it when filled\n");
- return 0;
- }
-
- /* Do they start past zero and end before end-of-disk? */
- {
- unsigned long ds = get_disksize(F_SECTOR);
-
- for (p = partitions; p < partitions + partno; p++)
- if (p->size) {
- if (p->start == 0) {
- warn("Warning: partition %s starts at sector 0\n",
- PNO(p));
- return 0;
- }
- if (p->size && p->start + p->size > ds) {
- warn
- ("Warning: partition %s extends past end of disk\n",
- PNO(p));
- return 0;
- }
- }
- }
-
- /* At most one chain of DOS extended partitions ? */
- /* It seems that the OS/2 fdisk has the additional requirement
- that the extended partition must be the fourth one */
- {
- int ect = 0;
-
- for (p = partitions; p < partitions + 4; p++)
- if (p->p.sys_type == EXTENDED_PARTITION)
- ect++;
- if (ect > 1 && !Linux) {
- warn
- ("Among the primary partitions, at most one can be extended\n");
- warn(" (although this is not a problem under Linux)\n");
- return 0;
- }
- }
-
- /*
- * Do all partitions start at a cylinder boundary ?
- * (this is not required for Linux)
- * The first partition starts after MBR.
- * Logical partitions start slightly after the containing extended partn.
- */
- if (B.cylindersize) {
- for (p = partitions; p < partitions + partno; p++)
- if (p->size) {
- if (p->start % B.cylindersize != 0
- && (!p->ep
- || p->start / B.cylindersize !=
- p->ep->start / B.cylindersize)
- && (p->p.start_sect >= B.cylindersize)) {
- warn("Warning: partition %s does not start "
- "at a cylinder boundary\n", PNO(p));
- if (!Linux)
- return 0;
- }
- if ((p->start + p->size) % B.cylindersize) {
- warn("Warning: partition %s does not end "
- "at a cylinder boundary\n", PNO(p));
- if (!Linux)
- return 0;
- }
- }
- }
-
- /* Usually, one can boot only from primary partitions. */
- /* In fact, from a unique one only. */
- /* do not warn about bootable extended partitions -
- often LILO is there */
- {
- int pno = -1;
-
- for (p = partitions; p < partitions + partno; p++)
- if (p->p.bootable) {
- if (pno == -1)
- pno = p - partitions;
- else if (p - partitions < 4) {
- warn
- ("Warning: more than one primary partition is marked "
- "bootable (active)\n"
- "This does not matter for LILO, but the DOS MBR will "
- "not boot this disk.\n");
- break;
- }
- if (p - partitions >= 4) {
- warn
- ("Warning: usually one can boot from primary partitions "
- "only\nLILO disregards the `bootable' flag.\n");
- break;
- }
- }
- if (pno == -1 || pno >= 4)
- warn
- ("Warning: no primary partition is marked bootable (active)\n"
- "This does not matter for LILO, but the DOS MBR will "
- "not boot this disk.\n");
- }
-
- /* Is chs as we expect? */
- for (p = partitions; p < partitions + partno; p++)
- if (p->ptype == DOS_TYPE) {
- chs a, b;
- longchs aa, bb;
-
- a = p->size ? ulong_to_chs(p->start, B) : zero_chs;
- b = p->p.begin_chs;
- aa = chs_to_longchs(a);
- bb = chs_to_longchs(b);
- if (!chs_ok(b, PNO(p), "start"))
- return 0;
- if (a.s && !is_equal_chs(a, b))
- warn
- ("partition %s: start: (c,h,s) expected (%ld,%ld,%ld) found (%ld,%ld,%ld)\n",
- PNO(p), aa.c, aa.h, aa.s, bb.c, bb.h, bb.s);
- a =
- p->size ? ulong_to_chs(p->start + p->size - 1,
- B) : zero_chs;
- b = p->p.end_chs;
- aa = chs_to_longchs(a);
- bb = chs_to_longchs(b);
- if (!chs_ok(b, PNO(p), "end"))
- return 0;
- if (a.s && !is_equal_chs(a, b))
- warn
- ("partition %s: end: (c,h,s) expected (%ld,%ld,%ld) found (%ld,%ld,%ld)\n",
- PNO(p), aa.c, aa.h, aa.s, bb.c, bb.h, bb.s);
- if (B.cylinders && B.cylinders < 1024 && bb.c > B.cylinders)
- warn
- ("partition %s ends on cylinder %ld, beyond the end of the disk\n",
- PNO(p), bb.c);
- }
-
- return 1;
-
-#undef PNO
-}
-
-static void
-extended_partition(char *dev, int fd, struct part_desc *ep,
- struct disk_desc *z)
-{
- char *cp;
- struct sector *s;
- unsigned long start, here, next;
- int i, moretodo = 1;
- struct partition p;
- struct part_desc *partitions = &(z->partitions[0]);
- int pno = z->partno;
-
- here = start = ep->start;
-
- while (moretodo) {
- moretodo = 0;
-
- if (!(s = get_sector(dev, fd, here)))
- break;
-
- if (!msdos_signature(s))
- break;
-
- cp = s->data + 0x1be;
-
- if (pno + 4 >= SIZE(z->partitions)) {
- printf("too many partitions - ignoring those past nr (%d)\n",
- pno - 1);
- break;
- }
-
- next = 0;
-
- for (i = 0; i < 4; i++, cp += sizeof(struct partition)) {
- partitions[pno].sector = here;
- partitions[pno].offset = cp - s->data;
- partitions[pno].ep = ep;
- copy_to_part(cp, &p);
- if (is_extended(p.sys_type)) {
- partitions[pno].start = start + p.start_sect;
- if (next)
- printf("tree of partitions?\n");
- else
- next = partitions[pno].start; /* follow `upper' branch */
- moretodo = 1;
- } else {
- partitions[pno].start = here + p.start_sect;
- }
- partitions[pno].size = p.nr_sects;
- partitions[pno].ptype = DOS_TYPE;
- partitions[pno].p = p;
- pno++;
- }
- here = next;
- }
-
- z->partno = pno;
-}
-
-#define BSD_DISKMAGIC (0x82564557UL)
-#define BSD_MAXPARTITIONS 8
-#define BSD_FS_UNUSED 0
-typedef unsigned char u8;
-typedef unsigned short u16;
-typedef unsigned int u32;
-struct bsd_disklabel {
- u32 d_magic;
- char d_junk1[4];
- char d_typename[16];
- char d_packname[16];
- char d_junk2[92];
- u32 d_magic2;
- char d_junk3[2];
- u16 d_npartitions; /* number of partitions in following */
- char d_junk4[8];
- struct bsd_partition { /* the partition table */
- u32 p_size; /* number of sectors in partition */
- u32 p_offset; /* starting sector */
- u32 p_fsize; /* filesystem basic fragment size */
- u8 p_fstype; /* filesystem type, see below */
- u8 p_frag; /* filesystem fragments per block */
- u16 p_cpg; /* filesystem cylinders per group */
- } d_partitions[BSD_MAXPARTITIONS]; /* actually may be more */
-};
-
-static void
-bsd_partition(char *dev, int fd, struct part_desc *ep, struct disk_desc *z)
-{
- struct bsd_disklabel *l;
- struct bsd_partition *bp, *bp0;
- unsigned long start = ep->start;
- struct sector *s;
- struct part_desc *partitions = &(z->partitions[0]);
- int pno = z->partno;
-
- if (!(s = get_sector(dev, fd, start + 1)))
- return;
- l = (struct bsd_disklabel *) (s->data);
- if (l->d_magic != BSD_DISKMAGIC)
- return;
-
- bp = bp0 = &l->d_partitions[0];
- while (bp - bp0 <= BSD_MAXPARTITIONS) {
- if (pno + 1 >= SIZE(z->partitions)) {
- printf("too many partitions - ignoring those "
- "past nr (%d)\n", pno - 1);
- break;
- }
- if (bp->p_fstype != BSD_FS_UNUSED) {
- partitions[pno].start = bp->p_offset;
- partitions[pno].size = bp->p_size;
- partitions[pno].sector = start + 1;
- partitions[pno].offset = (char *) bp - (char *) bp0;
- partitions[pno].ep = 0;
- partitions[pno].ptype = BSD_TYPE;
- pno++;
- }
- bp++;
- }
- z->partno = pno;
-}
-
-static int
-msdos_partition(char *dev, int fd, unsigned long start,
- struct disk_desc *z)
-{
- int i;
- char *cp;
- struct partition pt;
- struct sector *s;
- struct part_desc *partitions = &(z->partitions[0]);
- int pno = z->partno;
-
- if (!(s = get_sector(dev, fd, start)))
- return 0;
-
- if (!msdos_signature(s))
- return 0;
-
- cp = s->data + 0x1be;
- copy_to_part(cp, &pt);
-
- /* If I am not mistaken, recent kernels will hide this from us,
- so we will never actually see traces of a Disk Manager */
- if (pt.sys_type == DM6_PARTITION
- || pt.sys_type == EZD_PARTITION
- || pt.sys_type == DM6_AUX1PARTITION
- || pt.sys_type == DM6_AUX3PARTITION) {
- printf("detected Disk Manager - unable to handle that\n");
- return 0;
- }
- {
- unsigned int sig = *(unsigned short *) (s->data + 2);
-
- if (sig <= 0x1ae
- && *(unsigned short *) (s->data + sig) == 0x55aa
- && (1 & *(unsigned char *) (s->data + sig + 2))) {
- printf("DM6 signature found - giving up\n");
- return 0;
- }
- }
-
- for (pno = 0; pno < 4; pno++, cp += sizeof(struct partition)) {
- partitions[pno].sector = start;
- partitions[pno].offset = cp - s->data;
- copy_to_part(cp, &pt);
- partitions[pno].start = start + pt.start_sect;
- partitions[pno].size = pt.nr_sects;
- partitions[pno].ep = 0;
- partitions[pno].p = pt;
- }
-
- z->partno = pno;
-
- for (i = 0; i < 4; i++) {
- if (is_extended(partitions[i].p.sys_type)) {
- if (!partitions[i].size) {
- printf("strange..., an extended partition of size 0?\n");
- continue;
- }
- extended_partition(dev, fd, &partitions[i], z);
- }
- if (is_bsd(partitions[i].p.sys_type)) {
- if (!partitions[i].size) {
- printf("strange..., a BSD partition of size 0?\n");
- continue;
- }
- bsd_partition(dev, fd, &partitions[i], z);
- }
- }
- return 1;
-}
-
-static int
-osf_partition(char *dev, int fd, unsigned long start, struct disk_desc *z)
-{
- return 0;
-}
-
-static int
-sun_partition(char *dev, int fd, unsigned long start, struct disk_desc *z)
-{
- return 0;
-}
-
-static int
-amiga_partition(char *dev, int fd, unsigned long start,
- struct disk_desc *z)
-{
- return 0;
-}
-
-static void get_partitions(char *dev, int fd, struct disk_desc *z)
-{
- z->partno = 0;
-
- if (!msdos_partition(dev, fd, 0, z)
- && !osf_partition(dev, fd, 0, z)
- && !sun_partition(dev, fd, 0, z)
- && !amiga_partition(dev, fd, 0, z)) {
- printf(" %s: unrecognized partition\n", dev);
- return;
- }
-}
-
-static int write_partitions(char *dev, int fd, struct disk_desc *z)
-{
- struct sector *s;
- struct part_desc *partitions = &(z->partitions[0]), *p;
- int pno = z->partno;
-
- if (no_write) {
- printf("-n flag was given: Nothing changed\n");
- exit(0);
- }
-
- for (p = partitions; p < partitions + pno; p++) {
- s = get_sector(dev, fd, p->sector);
- if (!s)
- return 0;
- s->to_be_written = 1;
- copy_from_part(&(p->p), s->data + p->offset);
- *(unsigned short *) (&(s->data[0x1fe])) = 0xaa55;
- }
- if (save_sector_file) {
- if (!save_sectors(dev, fd)) {
- fatalError("Failed saving the old sectors - aborting\n");
- return 0;
- }
- }
- if (!write_sectors(dev, fd)) {
- errorMsg("Failed writing the partition on %s\n", dev);
- return 0;
- }
- return 1;
-}
-
-/*
- * F. The standard input
- */
-
-/*
- * Input format:
- * <start> <size> <type> <bootable> <c,h,s> <c,h,s>
- * Fields are separated by whitespace or comma or semicolon possibly
- * followed by whitespace; initial and trailing whitespace is ignored.
- * Numbers can be octal, decimal or hexadecimal, decimal is default
- * The <c,h,s> parts can (and probably should) be omitted.
- * Bootable is specified as [*|-], with as default not-bootable.
- * Type is given in hex, without the 0x prefix, or is [E|S|L|X], where
- * L (LINUX_NATIVE (83)) is the default, S is LINUX_SWAP (82), and E
- * is EXTENDED_PARTITION (5), X is LINUX_EXTENDED (85).
- * The default value of start is the first nonassigned sector/cylinder/...
- * The default value of size is as much as possible (until next
- * partition or end-of-disk).
- * .: end of chain of extended partitions.
- *
- * On interactive input an empty line means: all defaults.
- * Otherwise empty lines are ignored.
- */
-
-static int eof, eob;
-
-struct dumpfld {
- int fldno;
- char *fldname;
- int is_bool;
-} dumpflds[] = {
- {
- 0, "start", 0}, {
- 1, "size", 0}, {
- 2, "Id", 0}, {
- 3, "bootable", 1}, {
- 4, "bh", 0}, {
- 5, "bs", 0}, {
- 6, "bc", 0}, {
- 7, "eh", 0}, {
- 8, "es", 0}, {
- 9, "ec", 0}
-};
-
-/*
- * Read a line, split it into fields
- *
- * (some primitive handwork, but a more elaborate parser seems
- * unnecessary)
- */
-#define RD_EOF (-1)
-#define RD_CMD (-2)
-
-static int
-read_stdin(unsigned char **fields, unsigned char *line, int fieldssize,
- int linesize)
-{
- unsigned char *lp, *ip;
- int c, fno;
-
- /* boolean true and empty string at start */
- line[0] = '*';
- line[1] = 0;
- for (fno = 0; fno < fieldssize; fno++)
- fields[fno] = line + 1;
- fno = 0;
-
- /* read a line from stdin */
- lp = fgets(line + 2, linesize, stdin);
- if (lp == NULL) {
- eof = 1;
- return RD_EOF;
- }
- if (!(lp = index(lp, '\n')))
- fatalError("long or incomplete input line - quitting\n");
- *lp = 0;
-
- /* remove comments, if any */
- if ((lp = index(line + 2, '#')) != 0)
- *lp = 0;
-
- /* recognize a few commands - to be expanded */
- if (!strcmp(line + 2, "unit: sectors")) {
- specified_format = F_SECTOR;
- return RD_CMD;
- }
-
- /* dump style? - then bad input is fatal */
- if ((ip = index(line + 2, ':')) != 0) {
- struct dumpfld *d;
-
- nxtfld:
- ip++;
- while (isspace(*ip))
- ip++;
- if (*ip == 0)
- return fno;
- for (d = dumpflds; d - dumpflds < SIZE(dumpflds); d++) {
- if (!strncmp(ip, d->fldname, strlen(d->fldname))) {
- ip += strlen(d->fldname);
- while (isspace(*ip))
- ip++;
- if (d->is_bool)
- fields[d->fldno] = line;
- else if (*ip == '=') {
- while (isspace(*++ip));
- fields[d->fldno] = ip;
- while (isalnum(*ip)) /* 0x07FF */
- ip++;
- } else
- fatalError("input error: `=' expected after %s field\n",
- d->fldname);
- if (fno <= d->fldno)
- fno = d->fldno + 1;
- if (*ip == 0)
- return fno;
- if (*ip != ',' && *ip != ';')
- fatalError
- ("input error: unexpected character %c after %s field\n",
- *ip, d->fldname);
- *ip = 0;
- goto nxtfld;
- }
- }
- fatalError("unrecognized input: %s\n", ip);
- }
-
- /* split line into fields */
- lp = ip = line + 2;
- fields[fno++] = lp;
- while ((c = *ip++) != 0) {
- if (!lp[-1] && (c == '\t' || c == ' '));
- else if (c == '\t' || c == ' ' || c == ',' || c == ';') {
- *lp++ = 0;
- if (fno < fieldssize)
- fields[fno++] = lp;
- continue;
- } else
- *lp++ = c;
- }
-
- if (lp == fields[fno - 1])
- fno--;
- return fno;
-}
-
-/* read a number, use default if absent */
-static int get_ul(char *u, unsigned long *up, unsigned long def, int base)
-{
- char *nu;
-
- if (*u) {
- errno = 0;
- *up = strtoul(u, &nu, base);
- if (errno == ERANGE) {
- printf("number too big\n");
- return -1;
- }
- if (*nu) {
- printf("trailing junk after number\n");
- return -1;
- }
- } else
- *up = def;
- return 0;
-}
-
-/* There are two common ways to structure extended partitions:
- as nested boxes, and as a chain. Sometimes the partitions
- must be given in order. Sometimes all logical partitions
- must lie inside the outermost extended partition.
-NESTED: every partition is contained in the surrounding partitions
- and is disjoint from all others.
-CHAINED: every data partition is contained in the surrounding partitions
- and disjoint from all others, but extended partitions may lie outside
- (insofar as allowed by all_logicals_inside_outermost_extended).
-ONESECTOR: all data partitions are mutually disjoint; extended partitions
- each use one sector only (except perhaps for the outermost one).
-*/
-static int partitions_in_order = 0;
-static int all_logicals_inside_outermost_extended = 1;
-static enum { NESTED, CHAINED, ONESECTOR } boxes = NESTED;
-
-/* find the default value for <start> - assuming entire units */
-static unsigned long
-first_free(int pno, int is_extended, struct part_desc *ep, int format,
- unsigned long mid, struct disk_desc *z)
-{
- unsigned long ff, fff;
- unsigned long unit = unitsize(format);
- struct part_desc *partitions = &(z->partitions[0]), *pp = 0;
-
- /* if containing ep undefined, look at its container */
- if (ep && ep->p.sys_type == EMPTY_PARTITION)
- ep = ep->ep;
-
- if (ep) {
- if (boxes == NESTED || (boxes == CHAINED && !is_extended))
- pp = ep;
- else if (all_logicals_inside_outermost_extended)
- pp = outer_extended_partition(ep);
- }
-#if 0
- ff = pp ? (pp->start + unit - 1) / unit : 0;
-#else
- /* rounding up wastes almost an entire cylinder - round down
- and leave it to compute_start_sect() to fix the difference */
- ff = pp ? pp->start / unit : 0;
-#endif
- /* MBR and 1st sector of an extended partition are never free */
- if (unit == 1)
- ff++;
-
- again:
- for (pp = partitions; pp < partitions + pno; pp++) {
- if (!is_parent(pp, ep) && pp->size > 0) {
- if ((partitions_in_order || pp->start / unit <= ff
- || (mid && pp->start / unit <= mid))
- && (fff = (pp->start + pp->size + unit - 1) / unit) > ff) {
- ff = fff;
- goto again;
- }
- }
- }
-
- return ff;
-}
-
-/* find the default value for <size> - assuming entire units */
-static unsigned long
-max_length(int pno, int is_extended, struct part_desc *ep, int format,
- unsigned long start, struct disk_desc *z)
-{
- unsigned long fu;
- unsigned long unit = unitsize(format);
- struct part_desc *partitions = &(z->partitions[0]), *pp = 0;
-
- /* if containing ep undefined, look at its container */
- if (ep && ep->p.sys_type == EMPTY_PARTITION)
- ep = ep->ep;
-
- if (ep) {
- if (boxes == NESTED || (boxes == CHAINED && !is_extended))
- pp = ep;
- else if (all_logicals_inside_outermost_extended)
- pp = outer_extended_partition(ep);
- }
- fu = pp ? (pp->start + pp->size) / unit : get_disksize(format);
-
- for (pp = partitions; pp < partitions + pno; pp++)
- if (!is_parent(pp, ep) && pp->size > 0
- && pp->start / unit >= start && pp->start / unit < fu)
- fu = pp->start / unit;
-
- return (fu > start) ? fu - start : 0;
-}
-
-/* compute starting sector of a partition inside an extended one */
-/* ep is 0 or points to surrounding extended partition */
-static int compute_start_sect(struct part_desc *p, struct part_desc *ep)
-{
- unsigned long base;
- int inc = (DOS && B.sectors) ? B.sectors : 1;
- int delta;
-
- if (ep && p->start + p->size >= ep->start + 1)
- delta = p->start - ep->start - inc;
- else if (p->start == 0 && p->size > 0)
- delta = -inc;
- else
- delta = 0;
- if (delta < 0) {
- p->start -= delta;
- p->size += delta;
- if (is_extended(p->p.sys_type) && boxes == ONESECTOR)
- p->size = inc;
- else if ((int) (p->size) <= 0) {
- warn("no room for partition descriptor\n");
- return 0;
- }
- }
- base = (!ep ? 0
- : (is_extended(p->p.sys_type) ?
- outer_extended_partition(ep) : ep)->start);
- p->ep = ep;
- if (p->p.sys_type == EMPTY_PARTITION && p->size == 0) {
- p->p.start_sect = 0;
- p->p.begin_chs = zero_chs;
- p->p.end_chs = zero_chs;
- } else {
- p->p.start_sect = p->start - base;
- p->p.begin_chs = ulong_to_chs(p->start, B);
- p->p.end_chs = ulong_to_chs(p->start + p->size - 1, B);
- }
- p->p.nr_sects = p->size;
- return 1;
-}
-
-/* build the extended partition surrounding a given logical partition */
-static int
-build_surrounding_extended(struct part_desc *p, struct part_desc *ep,
- struct disk_desc *z)
-{
- int inc = (DOS && B.sectors) ? B.sectors : 1;
- int format = F_SECTOR;
- struct part_desc *p0 = &(z->partitions[0]), *eep = ep->ep;
-
- if (boxes == NESTED) {
- ep->start = first_free(ep - p0, 1, eep, format, p->start, z);
- ep->size = max_length(ep - p0, 1, eep, format, ep->start, z);
- if (ep->start > p->start
- || ep->start + ep->size < p->start + p->size) {
- warn("cannot build surrounding extended partition\n");
- return 0;
- }
- } else {
- ep->start = p->start;
- if (boxes == CHAINED)
- ep->size = p->size;
- else
- ep->size = inc;
- }
-
- ep->p.nr_sects = ep->size;
- ep->p.bootable = 0;
- ep->p.sys_type = EXTENDED_PARTITION;
- if (!compute_start_sect(ep, eep) || !compute_start_sect(p, ep)) {
- ep->p.sys_type = EMPTY_PARTITION;
- ep->size = 0;
- return 0;
- }
-
- return 1;
-}
-
-static int
-read_line(int pno, struct part_desc *ep, char *dev, int interactive,
- struct disk_desc *z)
-{
- unsigned char line[1000];
- unsigned char *fields[11];
- int fno, pct = pno % 4;
- struct part_desc p, *orig;
- unsigned long ff, ff1, ul, ml, ml1, def;
- int format, lpno, is_extd;
-
- if (eof || eob)
- return -1;
-
- lpno = index_to_linux(pno, z);
-
- if (interactive) {
- if (pct == 0 && (show_extended || pno == 0))
- warn("\n");
- warn("%8s%d: ", dev, lpno);
- }
-
- /* read input line - skip blank lines when reading from a file */
- do {
- fno = read_stdin(fields, line, SIZE(fields), SIZE(line));
- } while (fno == RD_CMD || (fno == 0 && !interactive));
- if (fno == RD_EOF) {
- return -1;
- } else if (fno > 10 && *(fields[10]) != 0) {
- printf("too many input fields\n");
- return 0;
- }
-
- if (fno == 1 && !strcmp(fields[0], ".")) {
- eob = 1;
- return -1;
- }
-
- /* use specified format, but round to cylinders if F_MEGABYTE specified */
- format = 0;
- if (B.cylindersize && specified_format == F_MEGABYTE)
- format = F_CYLINDER;
-
- orig = (one_only ? &(oldp.partitions[pno]) : 0);
-
- p = zero_part_desc;
- p.ep = ep;
-
- /* first read the type - we need to know whether it is extended */
- /* stop reading when input blank (defaults) and all is full */
- is_extd = 0;
- if (fno == 0) { /* empty line */
- if (orig && is_extended(orig->p.sys_type))
- is_extd = 1;
- ff = first_free(pno, is_extd, ep, format, 0, z);
- ml = max_length(pno, is_extd, ep, format, ff, z);
- if (ml == 0 && is_extd == 0) {
- is_extd = 1;
- ff = first_free(pno, is_extd, ep, format, 0, z);
- ml = max_length(pno, is_extd, ep, format, ff, z);
- }
- if (ml == 0 && pno >= 4) {
- /* no free blocks left - don't read any further */
- warn("No room for more\n");
- return -1;
- }
- }
- if (fno < 3 || !*(fields[2]))
- ul = orig ? orig->p.sys_type :
- (is_extd || (pno > 3 && pct == 1 && show_extended))
- ? EXTENDED_PARTITION : LINUX_NATIVE;
- else if (!strcmp(fields[2], "L"))
- ul = LINUX_NATIVE;
- else if (!strcmp(fields[2], "S"))
- ul = LINUX_SWAP;
- else if (!strcmp(fields[2], "E"))
- ul = EXTENDED_PARTITION;
- else if (!strcmp(fields[2], "X"))
- ul = LINUX_EXTENDED;
- else if (get_ul(fields[2], &ul, LINUX_NATIVE, 16))
- return 0;
- if (ul > 255) {
- warn("Illegal type\n");
- return 0;
- }
- p.p.sys_type = ul;
- is_extd = is_extended(ul);
-
- /* find start */
- ff = first_free(pno, is_extd, ep, format, 0, z);
- ff1 = ff * unitsize(format);
- def = orig ? orig->start : (pno > 4 && pct > 1) ? 0 : ff1;
- if (fno < 1 || !*(fields[0]))
- p.start = def;
- else {
- if (get_ul(fields[0], &ul, def / unitsize(0), 0))
- return 0;
- p.start = ul * unitsize(0);
- p.start -= (p.start % unitsize(format));
- }
-
- /* find length */
- ml =
- max_length(pno, is_extd, ep, format, p.start / unitsize(format),
- z);
- ml1 = ml * unitsize(format);
- def = orig ? orig->size : (pno > 4 && pct > 1) ? 0 : ml1;
- if (fno < 2 || !*(fields[1]))
- p.size = def;
- else {
- if (get_ul(fields[1], &ul, def / unitsize(0), 0))
- return 0;
- p.size = ul * unitsize(0) + unitsize(format) - 1;
- p.size -= (p.size % unitsize(format));
- }
- if (p.size > ml1) {
- warn("Warning: exceeds max allowable size (%lu)\n",
- ml1 / unitsize(0));
- if (!force)
- return 0;
- }
- if (p.size == 0 && pno >= 4 && (fno < 2 || !*(fields[1]))) {
- warn("Warning: empty partition\n");
- if (!force)
- return 0;
- }
- p.p.nr_sects = p.size;
-
- if (p.size == 0 && !orig) {
- if (fno < 1 || !*(fields[0]))
- p.start = 0;
- if (fno < 3 || !*(fields[2]))
- p.p.sys_type = EMPTY_PARTITION;
- }
-
- if (p.start < ff1 && p.size > 0) {
- warn("Warning: bad partition start (earliest %lu)\n",
- (ff1 + unitsize(0) - 1) / unitsize(0));
- if (!force)
- return 0;
- }
-
- if (fno < 4 || !*(fields[3]))
- ul = (orig ? orig->p.bootable : 0);
- else if (!strcmp(fields[3], "-"))
- ul = 0;
- else if (!strcmp(fields[3], "*") || !strcmp(fields[3], "+"))
- ul = 0x80;
- else {
- warn("unrecognized bootable flag - choose - or *\n");
- return 0;
- }
- p.p.bootable = ul;
-
- if (ep && ep->p.sys_type == EMPTY_PARTITION) {
- if (!build_surrounding_extended(&p, ep, z))
- return 0;
- } else if (!compute_start_sect(&p, ep))
- return 0;
-
- {
- longchs aa = chs_to_longchs(p.p.begin_chs), bb;
-
- if (fno < 5) {
- bb = aa;
- } else if (fno < 7) {
- warn("partial c,h,s specification?\n");
- return 0;
- } else if (get_ul(fields[4], &bb.c, aa.c, 0) ||
- get_ul(fields[5], &bb.h, aa.h, 0) ||
- get_ul(fields[6], &bb.s, aa.s, 0))
- return 0;
- p.p.begin_chs = longchs_to_chs(bb, B);
- }
- {
- longchs aa = chs_to_longchs(p.p.end_chs), bb;
-
- if (fno < 8) {
- bb = aa;
- } else if (fno < 10) {
- warn("partial c,h,s specification?\n");
- return 0;
- } else if (get_ul(fields[7], &bb.c, aa.c, 0) ||
- get_ul(fields[8], &bb.h, aa.h, 0) ||
- get_ul(fields[9], &bb.s, aa.s, 0))
- return 0;
- p.p.end_chs = longchs_to_chs(bb, B);
- }
-
- if (pno > 3 && p.size && show_extended
- && p.p.sys_type != EMPTY_PARTITION
- && (is_extended(p.p.sys_type) != (pct == 1))) {
- warn("Extended partition not where expected\n");
- if (!force)
- return 0;
- }
-
- z->partitions[pno] = p;
- if (pno >= z->partno)
- z->partno += 4; /* reqd for out_partition() */
-
- if (interactive)
- out_partition(dev, 0, &(z->partitions[pno]), z, B);
-
- return 1;
-}
-
-/* ep either points to the extended partition to contain this one,
- or to the empty partition that may become extended or is 0 */
-static int
-read_partition(char *dev, int interactive, int pno, struct part_desc *ep,
- struct disk_desc *z)
-{
- struct part_desc *p = &(z->partitions[pno]);
- int i;
-
- if (one_only) {
- *p = oldp.partitions[pno];
- if (one_only_pno != pno)
- goto ret;
- } else if (!show_extended && pno > 4 && pno % 4)
- goto ret;
-
- while (!(i = read_line(pno, ep, dev, interactive, z)))
- if (!interactive)
- fatalError("bad input\n");
- if (i < 0) {
- p->ep = ep;
- return 0;
- }
-
- ret:
- p->ep = ep;
- if (pno >= z->partno)
- z->partno += 4;
- return 1;
-}
-
-static void
-read_partition_chain(char *dev, int interactive, struct part_desc *ep,
- struct disk_desc *z)
-{
- int i, base;
-
- eob = 0;
- while (1) {
- base = z->partno;
- if (base + 4 > SIZE(z->partitions)) {
- printf("too many partitions\n");
- break;
- }
- for (i = 0; i < 4; i++)
- if (!read_partition(dev, interactive, base + i, ep, z))
- return;
- for (i = 0; i < 4; i++) {
- ep = &(z->partitions[base + i]);
- if (is_extended(ep->p.sys_type) && ep->size)
- break;
- }
- if (i == 4) {
- /* nothing found - maybe an empty partition is going
- to be extended */
- if (one_only || show_extended)
- break;
- ep = &(z->partitions[base + 1]);
- if (ep->size || ep->p.sys_type != EMPTY_PARTITION)
- break;
- }
- }
-}
-
-static void read_input(char *dev, int interactive, struct disk_desc *z)
-{
- int i;
- struct part_desc *partitions = &(z->partitions[0]), *ep;
-
- for (i = 0; i < SIZE(z->partitions); i++)
- partitions[i] = zero_part_desc;
- z->partno = 0;
-
- if (interactive)
- warn
- ("Input in the following format; absent fields get a default value.\n"
- "<start> <size> <type [E,S,L,X,hex]> <bootable [-,*]> <c,h,s> <c,h,s>\n"
- "Usually you only need to specify <start> and <size> (and perhaps <type>).\n");
- eof = 0;
-
- for (i = 0; i < 4; i++)
- read_partition(dev, interactive, i, 0, z);
- for (i = 0; i < 4; i++) {
- ep = partitions + i;
- if (is_extended(ep->p.sys_type) && ep->size)
- read_partition_chain(dev, interactive, ep, z);
- }
- add_sector_and_offset(z);
-}
-
-/*
- * G. The command line
- */
-
-static void version(void)
-{
- printf("%s %s %s (aeb@cwi.nl, %s)\n", PROGNAME, "version", VERSION,
- DATE);
-}
-
-static char short_opts[] = "cdfgilnqsu:vx?1A::C:DH:I:LN:O:RS:TU::V";
-
-#define PRINT_ID 0400
-#define CHANGE_ID 01000
-
-static const struct option long_opts[] = {
- {"change-id", no_argument, NULL, 'c' + CHANGE_ID},
- {"print-id", no_argument, NULL, 'c' + PRINT_ID},
- {"id", no_argument, NULL, 'c'},
- {"dump", no_argument, NULL, 'd'},
- {"force", no_argument, NULL, 'f'},
- {"show-geometry", no_argument, NULL, 'g'},
- {"increment", no_argument, NULL, 'i'},
- {"list", no_argument, NULL, 'l'},
- {"quiet", no_argument, NULL, 'q'},
- {"show-size", no_argument, NULL, 's'},
- {"unit", required_argument, NULL, 'u'},
- {"version", no_argument, NULL, 'v'},
- {"show-extended", no_argument, NULL, 'x'},
- {"help", no_argument, NULL, '?'},
- {"one-only", no_argument, NULL, '1'},
- {"cylinders", required_argument, NULL, 'C'},
- {"heads", required_argument, NULL, 'H'},
- {"sectors", required_argument, NULL, 'S'},
- {"activate", optional_argument, NULL, 'A'},
- {"DOS", no_argument, NULL, 'D'},
- {"Linux", no_argument, NULL, 'L'},
- {"re-read", no_argument, NULL, 'R'},
- {"list-types", no_argument, NULL, 'T'},
- {"unhide", optional_argument, NULL, 'U'},
- {"no-reread", no_argument, NULL, 160},
- {"IBM", no_argument, NULL, 161},
- {"leave-last", no_argument, NULL, 161},
-/* undocumented flags - not all completely implemented */
- {"in-order", no_argument, NULL, 128},
- {"not-in-order", no_argument, NULL, 129},
- {"inside-outer", no_argument, NULL, 130},
- {"not-inside-outer", no_argument, NULL, 131},
- {"nested", no_argument, NULL, 132},
- {"chained", no_argument, NULL, 133},
- {"onesector", no_argument, NULL, 134},
- {NULL, 0, NULL, 0}
-};
-
-/* default devices to list */
-static struct devd {
- char *pref, *letters;
-} defdevs[] = {
- {
- "hd", "abcdefgh"}, {
- "sd", "abcde"}, {
- "xd", "ab"}, {
- "ed", "abcd"}
-};
-
-static int is_ide_cdrom(char *device)
-{
- /* No device was given explicitly, and we are trying some
- likely things. But opening /dev/hdc may produce errors like
- "hdc: tray open or drive not ready"
- if it happens to be a CD-ROM drive. So try to be careful.
- This only works since 2.1.73. */
-
- FILE *procf;
- char buf[100];
- struct stat statbuf;
-
- sprintf(buf, "/proc/ide/%s/media", device + 5);
- procf = fopen(buf, "r");
- if (procf != NULL && fgets(buf, sizeof(buf), procf))
- return !strncmp(buf, "cdrom", 5);
-
- /* Now when this proc file does not exist, skip the
- device when it is read-only. */
- if (stat(device, &statbuf) == 0)
- return (statbuf.st_mode & 0222) == 0;
-
- return 0;
-}
-
-static void do_list(char *dev, int silent);
-static void do_size(char *dev, int silent);
-static void do_geom(char *dev, int silent);
-static void do_fdisk(char *dev);
-static void do_reread(char *dev);
-static void do_change_id(char *dev, char *part, char *id);
-static void do_unhide(char **av, int ac, char *arg);
-static void do_activate(char **av, int ac, char *arg);
-
-static int total_size;
-
-extern int sfdisk_main(int argc, char **argv)
-{
- int c;
- char *dev;
- int opt_size = 0;
- int opt_out_geom = 0;
- int opt_reread = 0;
- int activate = 0;
- int do_id = 0;
- int unhide = 0;
- char *activatearg = 0;
- char *unhidearg = 0;
-
- if (argc < 1)
- usage(sfdisk_usage);
-
- while ((c = getopt_long(argc, argv, short_opts, long_opts, NULL)) !=
- -1) {
- switch (c) {
- case 'f':
- force = 1;
- break; /* does not imply quiet */
- case 'g':
- opt_out_geom = 1;
- break;
- case 'i':
- increment = 1;
- break;
- case 'c':
- case 'c' + PRINT_ID:
- case 'c' + CHANGE_ID:
- do_id = c;
- break;
- case 'd':
- dump = 1; /* fall through */
- case 'l':
- opt_list = 1;
- break;
- case 'n':
- no_write = 1;
- break;
- case 'q':
- quiet = 1;
- break;
- case 's':
- opt_size = 1;
- break;
- case 'u':
- set_format(*optarg);
- break;
- case 'v':
- version();
- exit(0);
- case 'x':
- show_extended = 1;
- break;
- case 'A':
- activatearg = optarg;
- activate = 1;
- break;
- case 'C':
- U.cylinders = atoi(optarg);
- break;
- case 'D':
- DOS = 1;
- break;
- case 'H':
- U.heads = atoi(optarg);
- break;
- case 'L':
- Linux = 1;
- break;
- case 'N':
- one_only = atoi(optarg);
- break;
- case 'I':
- restore_sector_file = optarg;
- break;
- case 'O':
- save_sector_file = optarg;
- break;
- case 'R':
- opt_reread = 1;
- break;
- case 'S':
- U.sectors = atoi(optarg);
- break;
- case 'T':
- list_types();
- exit(0);
- case 'U':
- unhidearg = optarg;
- unhide = 1;
- break;
- case 'V':
- verify = 1;
- break;
- case '?':
- default:
- usage(sfdisk_usage);
-
- /* undocumented flags */
- case 128:
- partitions_in_order = 1;
- break;
- case 129:
- partitions_in_order = 0;
- break;
- case 130:
- all_logicals_inside_outermost_extended = 1;
- break;
- case 131:
- all_logicals_inside_outermost_extended = 0;
- break;
- case 132:
- boxes = NESTED;
- break;
- case 133:
- boxes = CHAINED;
- break;
- case 134:
- boxes = ONESECTOR;
- break;
-
- /* more flags */
- case 160:
- no_reread = 1;
- break;
- case 161:
- leave_last = 1;
- break;
- }
- }
-
- if (optind == argc && (opt_list || opt_out_geom || opt_size || verify)) {
- struct devd *dp;
- char *lp;
- char device[10];
-
- total_size = 0;
-
- for (dp = defdevs; dp - defdevs < SIZE(defdevs); dp++) {
- lp = dp->letters;
- while (*lp) {
- sprintf(device, "/dev/%s%c", dp->pref, *lp++);
- if (!strcmp(dp->pref, "hd") && is_ide_cdrom(device))
- continue;
- if (opt_out_geom)
- do_geom(device, 1);
- if (opt_size)
- do_size(device, 1);
- if (opt_list || verify)
- do_list(device, 1);
- }
- }
-
- if (opt_size)
- printf("total: %d blocks\n", total_size);
-
- exit(exit_status);
- }
-
- if (optind == argc)
- usage(sfdisk_usage);
-
- if (opt_list || opt_out_geom || opt_size || verify) {
- while (optind < argc) {
- if (opt_out_geom)
- do_geom(argv[optind], 0);
- if (opt_size)
- do_size(argv[optind], 0);
- if (opt_list || verify)
- do_list(argv[optind], 0);
- optind++;
- }
- exit(exit_status);
- }
-
- if (activate) {
- do_activate(argv + optind, argc - optind, activatearg);
- exit(exit_status);
- }
- if (unhide) {
- do_unhide(argv + optind, argc - optind, unhidearg);
- exit(exit_status);
- }
- if (do_id) {
- if ((do_id & PRINT_ID) != 0 && optind != argc - 2)
- fatalError("usage: sfdisk --print-id device partition-number\n");
- else if ((do_id & CHANGE_ID) != 0 && optind != argc - 3)
- fatalError
- ("usage: sfdisk --change-id device partition-number Id\n");
- else if (optind != argc - 3 && optind != argc - 2)
- fatalError("usage: sfdisk --id device partition-number [Id]\n");
- do_change_id(argv[optind], argv[optind + 1],
- (optind == argc - 2) ? 0 : argv[optind + 2]);
- exit(exit_status);
- }
-
- if (optind != argc - 1)
- fatalError("can specify only one device (except with -l or -s)\n");
- dev = argv[optind];
-
- if (opt_reread)
- do_reread(dev);
- else if (restore_sector_file)
- restore_sectors(dev);
- else
- do_fdisk(dev);
-
- return (TRUE);
-}
-
-/*
- * H. Listing the current situation
- */
-
-static int my_open(char *dev, int rw, int silent)
-{
- int fd, mode;
-
- mode = (rw ? O_RDWR : O_RDONLY);
- fd = open(dev, mode);
- if (fd < 0 && !silent) {
- perror(dev);
- fatalError("cannot open %s %s\n", dev,
- rw ? "read-write" : "for reading");
- }
- return fd;
-}
-
-static void do_list(char *dev, int silent)
-{
- int fd;
- struct disk_desc *z;
-
- fd = my_open(dev, 0, silent);
- if (fd < 0)
- return;
-
- z = &oldp;
-
- free_sectors();
- get_cylindersize(dev, fd, dump ? 1 : opt_list ? 0 : 1);
- get_partitions(dev, fd, z);
-
- if (opt_list)
- out_partitions(dev, z);
-
- if (verify) {
- if (partitions_ok(z))
- warn("%s: OK\n", dev);
- else
- exit_status = 1;
- }
-}
-
-static void do_geom(char *dev, int silent)
-{
- int fd;
- struct hd_geometry g;
-
- fd = my_open(dev, 0, silent);
- if (fd < 0)
- return;
-
- /* get_cylindersize(dev, fd, silent); */
- if (!ioctl(fd, HDIO_GETGEO, &g))
- printf("%s: %d cylinders, %d heads, %d sectors/track\n",
- dev, g.cylinders, g.heads, g.sectors);
- else
- printf("%s: unknown geometry\n", dev);
-}
-
-/* for compatibility with earlier fdisk: provide option -s */
-static void do_size(char *dev, int silent)
-{
- int fd;
- long size;
-
- fd = my_open(dev, 0, silent);
- if (fd < 0)
- return;
-
- if (ioctl(fd, BLKGETSIZE, &size)) {
- if (!silent) {
- perror(dev);
- fatalError("BLKGETSIZE ioctl failed for %s\n", dev);
- }
- return;
- }
-
- size /= 2; /* convert sectors to blocks */
-
- /* a CDROM drive without mounted CD yields MAXINT */
- if (silent && size == ((1 << 30) - 1))
- return;
-
- if (silent)
- printf("%s: %9ld\n", dev, size);
- else
- printf("%ld\n", size);
-
- total_size += size;
-}
-
-/*
- * Activate: usually one wants to have a single primary partition
- * to be active. OS/2 fdisk makes non-bootable logical partitions
- * active - I don't know what that means to OS/2 Boot Manager.
- *
- * Call: activate /dev/hda 2 5 7 make these partitions active
- * and the remaining ones inactive
- * Or: sfdisk -A /dev/hda 2 5 7
- *
- * If only a single partition must be active, one may also use the form
- * sfdisk -A2 /dev/hda
- *
- * With "activate /dev/hda" or "sfdisk -A /dev/hda" the active partitions
- * are listed but not changed. To get zero active partitions, use
- * "activate /dev/hda none" or "sfdisk -A /dev/hda none".
- * Use something like `echo ",,,*" | sfdisk -N2 /dev/hda' to only make
- * /dev/hda2 active, without changing other partitions.
- *
- * A warning will be given if after the change not precisely one primary
- * partition is active.
- *
- * The present syntax was chosen to be (somewhat) compatible with the
- * activate from the LILO package.
- */
-static void set_active(struct disk_desc *z, char *pnam)
-{
- int pno;
-
- pno = asc_to_index(pnam, z);
- z->partitions[pno].p.bootable = 0x80;
-}
-
-static void do_activate(char **av, int ac, char *arg)
-{
- char *dev = av[0];
- int fd;
- int rw, i, pno, lpno;
- struct disk_desc *z;
-
- z = &oldp;
-
- rw = (!no_write && (arg || ac > 1));
- fd = my_open(dev, rw, 0);
-
- free_sectors();
- get_cylindersize(dev, fd, 1);
- get_partitions(dev, fd, z);
-
- if (!arg && ac == 1) {
- /* list active partitions */
- for (pno = 0; pno < z->partno; pno++) {
- if (z->partitions[pno].p.bootable) {
- lpno = index_to_linux(pno, z);
- if (pno == linux_to_index(lpno, z))
- printf("%s%d\n", dev, lpno);
- else
- printf("%s#%d\n", dev, pno);
- if (z->partitions[pno].p.bootable != 0x80)
- warn("bad active byte: 0x%x instead of 0x80\n",
- z->partitions[pno].p.bootable);
- }
- }
- } else {
- /* clear `active byte' everywhere */
- for (pno = 0; pno < z->partno; pno++)
- z->partitions[pno].p.bootable = 0;
-
- /* then set where desired */
- if (ac == 1)
- set_active(z, arg);
- else
- for (i = 1; i < ac; i++)
- set_active(z, av[i]);
-
- /* then write to disk */
- if (write_partitions(dev, fd, z))
- warn("Done\n\n");
- else
- exit_status = 1;
- }
- i = 0;
- for (pno = 0; pno < z->partno && pno < 4; pno++)
- if (z->partitions[pno].p.bootable)
- i++;
- if (i != 1)
- warn
- ("You have %d active primary partitions. This does not matter for LILO,\n"
- "but the DOS MBR will only boot a disk with 1 active partition.\n",
- i);
-}
-
-static void set_unhidden(struct disk_desc *z, char *pnam)
-{
- int pno;
- unsigned char id;
-
- pno = asc_to_index(pnam, z);
- id = z->partitions[pno].p.sys_type;
- if (id == 0x11 || id == 0x14 || id == 0x16 || id == 0x17)
- id -= 0x10;
- else
- fatalError("partition %s has id %x and is not hidden\n", pnam, id);
- z->partitions[pno].p.sys_type = id;
-}
-
-/*
- * maybe remove and make part of --change-id
- */
-static void do_unhide(char **av, int ac, char *arg)
-{
- char *dev = av[0];
- int fd, rw, i;
- struct disk_desc *z;
-
- z = &oldp;
-
- rw = !no_write;
- fd = my_open(dev, rw, 0);
-
- free_sectors();
- get_cylindersize(dev, fd, 1);
- get_partitions(dev, fd, z);
-
- /* unhide where desired */
- if (ac == 1)
- set_unhidden(z, arg);
- else
- for (i = 1; i < ac; i++)
- set_unhidden(z, av[i]);
-
- /* then write to disk */
- if (write_partitions(dev, fd, z))
- warn("Done\n\n");
- else
- exit_status = 1;
-}
-
-static void do_change_id(char *dev, char *pnam, char *id)
-{
- int fd, rw, pno;
- struct disk_desc *z;
- unsigned long i;
-
- z = &oldp;
-
- rw = !no_write;
- fd = my_open(dev, rw, 0);
-
- free_sectors();
- get_cylindersize(dev, fd, 1);
- get_partitions(dev, fd, z);
-
- pno = asc_to_index(pnam, z);
- if (id == 0) {
- printf("%x\n", z->partitions[pno].p.sys_type);
- return;
- }
- i = strtoul(id, NULL, 16);
- if (i > 255)
- fatalError("Bad Id %lx\n", i);
- z->partitions[pno].p.sys_type = i;
-
- if (write_partitions(dev, fd, z))
- warn("Done\n\n");
- else
- exit_status = 1;
-}
-
-static void do_reread(char *dev)
-{
- int fd;
-
- fd = my_open(dev, 0, 0);
- if (reread_ioctl(fd))
- printf("This disk is currently in use.\n");
-}
-
-/*
- * I. Writing the new situation
- */
-
-static void do_fdisk(char *dev)
-{
- int fd;
- int c, answer;
- struct stat statbuf;
- int interactive = isatty(0);
- struct disk_desc *z;
-
- if (stat(dev, &statbuf) < 0) {
- perror(dev);
- fatalError("Fatal error: cannot find %s\n", dev);
- }
- if (!S_ISBLK(statbuf.st_mode)) {
- warn("Warning: %s is not a block device\n", dev);
- no_reread = 1;
- }
- fd = my_open(dev, !no_write, 0);
-
- if (!no_write && !no_reread) {
- warn("Checking that no-one is using this disk right now ...\n");
- if (reread_ioctl(fd)) {
- printf
- ("\nThis disk is currently in use - repartitioning is probably a bad idea."
- "Umount all file systems, and swapoff all swap partitions on this disk."
- "Use the --no-reread flag to suppress this check.\n");
- if (!force) {
- printf("Use the --force flag to overrule all checks.\n");
- exit(1);
- }
- } else
- warn("OK");
- }
-
- z = &oldp;
-
- free_sectors();
- get_cylindersize(dev, fd, 0);
- get_partitions(dev, fd, z);
-
- printf("Old situation:\n");
- out_partitions(dev, z);
-
- if (one_only && (one_only_pno = linux_to_index(one_only, z)) < 0)
- fatalError("Partition %d does not exist, cannot change it\n", one_only);
-
- z = &newp;
-
- while (1) {
-
- read_input(dev, interactive, z);
-
- printf("New situation:\n");
- out_partitions(dev, z);
-
- if (!partitions_ok(z) && !force) {
- if (!interactive)
- fatalError("I don't like these partitions - nothing changed.\n"
- "(If you really want this, use the --force option.)\n");
- else
- printf
- ("I don't like this - probably you should answer No\n");
- }
- ask:
- if (interactive) {
- if (no_write)
- printf("Are you satisfied with this? [ynq] ");
- else
- printf("Do you want to write this to disk? [ynq] ");
- answer = c = getchar();
- while (c != '\n' && c != EOF)
- c = getchar();
- if (c == EOF)
- printf("\nsfdisk: premature end of input\n");
- if (c == EOF || answer == 'q' || answer == 'Q') {
- fatalError("Quitting - nothing changed\n");
- } else if (answer == 'n' || answer == 'N') {
- continue;
- } else if (answer == 'y' || answer == 'Y') {
- break;
- } else {
- printf("Please answer one of y,n,q\n");
- goto ask;
- }
- } else
- break;
- }
-
- if (write_partitions(dev, fd, z))
- printf("Successfully wrote the new partition table\n\n");
- else
- exit_status = 1;
-
- reread_disk_partition(dev, fd);
-
- warn
- ("If you created or changed a DOS partition, /dev/foo7, say, then use dd(1)\n"
- "to zero the first 512 bytes: dd if=/dev/zero of=/dev/foo7 bs=512 count=1\n"
- "(See fdisk(8).)\n");
-
- sync(); /* superstition */
- sleep(3);
- exit(exit_status);
-}