2006-12-06 17:25:34 -06:00
|
|
|
/*
|
|
|
|
* 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
|
2006-12-06 17:25:39 -06:00
|
|
|
*
|
|
|
|
* Changes:
|
|
|
|
* 19990319 - Arnaldo Carvalho de Melo <acme@conectiva.com.br> - i18n
|
2006-12-06 17:26:22 -06:00
|
|
|
* 20040428 - Jeroen Dobbelaere <jeroen.dobbelaere@acunia.com> - added PACKED
|
2006-12-06 17:26:16 -06:00
|
|
|
* 20040824 - David A. Wheeler <dwheeler@dwheeler.com> - warnings to stderr
|
2006-12-06 17:25:34 -06:00
|
|
|
*/
|
|
|
|
|
|
|
|
#define PROGNAME "sfdisk"
|
|
|
|
|
|
|
|
#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 */
|
2009-08-17 00:27:39 -05:00
|
|
|
#include <string.h> /* strchr(), strrchr() */
|
2006-12-06 17:25:34 -06:00
|
|
|
#include <ctype.h>
|
|
|
|
#include <getopt.h>
|
|
|
|
#include <sys/ioctl.h>
|
|
|
|
#include <sys/stat.h>
|
2006-12-06 17:25:43 -06:00
|
|
|
#include <sys/utsname.h>
|
2009-10-15 18:15:19 -05:00
|
|
|
|
|
|
|
#include "c.h"
|
2006-12-06 17:25:39 -06:00
|
|
|
#include "nls.h"
|
2007-11-07 12:05:31 -06:00
|
|
|
#include "blkdev.h"
|
2007-11-07 17:27:51 -06:00
|
|
|
#include "linux_version.h"
|
2006-12-06 17:25:39 -06:00
|
|
|
#include "common.h"
|
2009-03-11 08:00:21 -05:00
|
|
|
#include "wholedisk.h"
|
2007-05-31 07:31:51 -05:00
|
|
|
#include "gpt.h"
|
2010-12-16 18:28:59 -06:00
|
|
|
#include "pathnames.h"
|
|
|
|
#include "canonicalize.h"
|
2007-05-31 07:31:51 -05:00
|
|
|
|
2006-12-06 17:25:34 -06:00
|
|
|
/*
|
|
|
|
* 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
|
|
|
|
*/
|
|
|
|
int exit_status = 0;
|
|
|
|
|
|
|
|
int force = 0; /* 1: do what I say, even if it is stupid ... */
|
|
|
|
int quiet = 0; /* 1: suppress all warnings */
|
2006-12-06 17:25:43 -06:00
|
|
|
/* IA-64 gcc spec file currently does -DLinux... */
|
|
|
|
#undef Linux
|
2006-12-06 17:25:34 -06:00
|
|
|
int Linux = 0; /* 1: suppress warnings irrelevant for Linux */
|
|
|
|
int DOS = 0; /* 1: shift extended partitions by #sectors, not 1 */
|
2006-12-06 17:25:43 -06:00
|
|
|
int DOS_extended = 0; /* 1: use starting cylinder boundary of extd partn */
|
2006-12-06 17:25:34 -06:00
|
|
|
int dump = 0; /* 1: list in a format suitable for later input */
|
|
|
|
int verify = 0; /* 1: check that listed partition is reasonable */
|
|
|
|
int no_write = 0; /* 1: do not actually write to disk */
|
|
|
|
int no_reread = 0; /* 1: skip the BLKRRPART ioctl test at startup */
|
|
|
|
int leave_last = 0; /* 1: don't allocate the last cylinder */
|
|
|
|
int opt_list = 0;
|
|
|
|
char *save_sector_file = NULL;
|
|
|
|
char *restore_sector_file = NULL;
|
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
static void
|
2006-12-06 17:26:16 -06:00
|
|
|
do_warn(char *s, ...) {
|
2006-12-06 17:25:34 -06:00
|
|
|
va_list p;
|
|
|
|
|
|
|
|
va_start(p, s);
|
|
|
|
fflush(stdout);
|
2006-12-06 17:26:16 -06:00
|
|
|
vfprintf(stderr, s, p);
|
|
|
|
fflush(stderr);
|
|
|
|
va_end(p);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2011-01-31 11:58:26 -06:00
|
|
|
my_warn(char *s, ...) {
|
2006-12-06 17:26:16 -06:00
|
|
|
va_list p;
|
|
|
|
|
|
|
|
va_start(p, s);
|
2006-12-06 17:26:22 -06:00
|
|
|
if (!quiet) {
|
|
|
|
fflush(stdout);
|
|
|
|
vfprintf(stderr, s, p);
|
|
|
|
fflush(stderr);
|
|
|
|
}
|
2006-12-06 17:25:34 -06:00
|
|
|
va_end(p);
|
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
static void
|
2006-12-06 17:25:34 -06:00
|
|
|
error(char *s, ...) {
|
|
|
|
va_list p;
|
|
|
|
|
|
|
|
va_start(p, s);
|
|
|
|
fflush(stdout);
|
|
|
|
fprintf(stderr, "\n" PROGNAME ": ");
|
|
|
|
vfprintf(stderr, s, p);
|
2006-12-06 17:26:16 -06:00
|
|
|
fflush(stderr);
|
2006-12-06 17:25:34 -06:00
|
|
|
va_end(p);
|
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
static void
|
2006-12-06 17:25:34 -06:00
|
|
|
fatal(char *s, ...) {
|
|
|
|
va_list p;
|
|
|
|
|
|
|
|
va_start(p, s);
|
|
|
|
fflush(stdout);
|
|
|
|
fprintf(stderr, "\n" PROGNAME ": ");
|
|
|
|
vfprintf(stderr, s, p);
|
2006-12-06 17:26:16 -06:00
|
|
|
fflush(stderr);
|
2006-12-06 17:25:34 -06:00
|
|
|
va_end(p);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
2006-12-06 17:26:22 -06:00
|
|
|
/*
|
|
|
|
* arm needs PACKED - use it everywhere?
|
|
|
|
*/
|
2006-12-06 17:26:28 -06:00
|
|
|
#if defined(__GNUC__) && (defined(__arm__) || defined(__alpha__))
|
2006-12-06 17:26:22 -06:00
|
|
|
# define PACKED __attribute__ ((packed))
|
|
|
|
#else
|
|
|
|
# define PACKED
|
|
|
|
#endif
|
2006-12-06 17:26:19 -06:00
|
|
|
|
2006-12-06 17:25:34 -06:00
|
|
|
/*
|
|
|
|
* A. About seeking
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* sseek: seek to specified sector - return 0 on failure
|
|
|
|
*
|
2006-12-06 17:25:43 -06:00
|
|
|
* Note: we use 512-byte sectors here, irrespective of the hardware ss.
|
2006-12-06 17:25:34 -06:00
|
|
|
*/
|
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
static int
|
2006-12-06 17:25:34 -06:00
|
|
|
sseek(char *dev, unsigned int fd, unsigned long s) {
|
2006-12-06 17:27:13 -06:00
|
|
|
off_t in, out;
|
|
|
|
in = ((off_t) s << 9);
|
2006-12-06 17:25:34 -06:00
|
|
|
out = 1;
|
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
if ((out = lseek(fd, in, SEEK_SET)) != in) {
|
2006-12-06 17:27:13 -06:00
|
|
|
perror("lseek");
|
2006-12-06 17:25:39 -06:00
|
|
|
error(_("seek error on %s - cannot seek to %lu\n"), dev, s);
|
2006-12-06 17:25:34 -06:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (in != out) {
|
2006-12-06 17:25:39 -06:00
|
|
|
error(_("seek error: wanted 0x%08x%08x, got 0x%08x%08x\n"),
|
2006-12-06 17:26:12 -06:00
|
|
|
(unsigned int)(in>>32), (unsigned int)(in & 0xffffffff),
|
|
|
|
(unsigned int)(out>>32), (unsigned int)(out & 0xffffffff));
|
2006-12-06 17:25:34 -06:00
|
|
|
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;
|
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
static void
|
2006-12-06 17:25:34 -06:00
|
|
|
free_sectors(void) {
|
|
|
|
struct sector *s;
|
|
|
|
|
|
|
|
while (sectorhead) {
|
|
|
|
s = sectorhead;
|
|
|
|
sectorhead = s->next;
|
|
|
|
free(s);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
static struct sector *
|
2006-12-06 17:25:34 -06:00
|
|
|
get_sector(char *dev, int fd, unsigned long sno) {
|
|
|
|
struct sector *s;
|
|
|
|
|
|
|
|
for(s = sectorhead; s; s = s->next)
|
2006-12-06 17:26:16 -06:00
|
|
|
if (s->sectornumber == sno)
|
2006-12-06 17:25:34 -06:00
|
|
|
return s;
|
|
|
|
|
|
|
|
if (!sseek(dev, fd, sno))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (!(s = (struct sector *) malloc(sizeof(struct sector))))
|
2006-12-06 17:25:39 -06:00
|
|
|
fatal(_("out of memory - giving up\n"));
|
2006-12-06 17:25:34 -06:00
|
|
|
|
|
|
|
if (read(fd, s->data, sizeof(s->data)) != sizeof(s->data)) {
|
2006-12-06 17:25:43 -06:00
|
|
|
if (errno) /* 0 in case we read past end-of-disk */
|
|
|
|
perror("read");
|
2006-12-06 17:25:39 -06:00
|
|
|
error(_("read error on %s - cannot read sector %lu\n"), dev, sno);
|
2006-12-06 17:25:34 -06:00
|
|
|
free(s);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
s->next = sectorhead;
|
|
|
|
sectorhead = s;
|
|
|
|
s->sectornumber = sno;
|
|
|
|
s->to_be_written = 0;
|
|
|
|
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
static int
|
2006-12-06 17:25:34 -06:00
|
|
|
msdos_signature (struct sector *s) {
|
2007-10-15 19:38:57 -05:00
|
|
|
unsigned char *data = (unsigned char *)s->data;
|
2006-12-06 17:25:48 -06:00
|
|
|
if (data[510] == 0x55 && data[511] == 0xaa)
|
|
|
|
return 1;
|
|
|
|
error(_("ERROR: sector %lu does not have an msdos signature\n"),
|
|
|
|
s->sectornumber);
|
|
|
|
return 0;
|
2006-12-06 17:25:34 -06:00
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
static int
|
2006-12-06 17:25:34 -06:00
|
|
|
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");
|
2006-12-06 17:25:39 -06:00
|
|
|
error(_("write error on %s - cannot write sector %lu\n"),
|
2006-12-06 17:25:34 -06:00
|
|
|
dev, s->sectornumber);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
s->to_be_written = 0;
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
static void
|
2006-12-06 17:25:34 -06:00
|
|
|
ulong_to_chars(unsigned long u, char *uu) {
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for(i=0; i<4; i++) {
|
|
|
|
uu[i] = (u & 0xff);
|
|
|
|
u >>= 8;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
static unsigned long
|
2006-12-06 17:25:34 -06:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
static int
|
2006-12-06 17:25:34 -06:00
|
|
|
save_sectors(char *dev, int fdin) {
|
|
|
|
struct sector *s;
|
|
|
|
char ss[516];
|
2007-10-21 22:25:39 -05:00
|
|
|
int fdout = -1;
|
2006-12-06 17:25:34 -06:00
|
|
|
|
|
|
|
fdout = open(save_sector_file, O_WRONLY | O_CREAT, 0444);
|
|
|
|
if (fdout < 0) {
|
|
|
|
perror(save_sector_file);
|
2006-12-06 17:25:39 -06:00
|
|
|
error(_("cannot open partition sector save file (%s)\n"),
|
2006-12-06 17:25:34 -06:00
|
|
|
save_sector_file);
|
2007-10-21 22:25:39 -05:00
|
|
|
goto err;
|
2006-12-06 17:25:34 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
for (s = sectorhead; s; s = s->next)
|
|
|
|
if (s->to_be_written) {
|
|
|
|
ulong_to_chars(s->sectornumber, ss);
|
|
|
|
if (!sseek(dev, fdin, s->sectornumber))
|
2007-10-21 22:25:39 -05:00
|
|
|
goto err;
|
2006-12-06 17:25:34 -06:00
|
|
|
if (read(fdin, ss+4, 512) != 512) {
|
|
|
|
perror("read");
|
2006-12-06 17:25:39 -06:00
|
|
|
error(_("read error on %s - cannot read sector %lu\n"),
|
2006-12-06 17:25:34 -06:00
|
|
|
dev, s->sectornumber);
|
2007-10-21 22:25:39 -05:00
|
|
|
goto err;
|
2006-12-06 17:25:34 -06:00
|
|
|
}
|
|
|
|
if (write(fdout, ss, sizeof(ss)) != sizeof(ss)) {
|
|
|
|
perror("write");
|
2006-12-06 17:25:39 -06:00
|
|
|
error(_("write error on %s\n"), save_sector_file);
|
2007-10-21 22:25:39 -05:00
|
|
|
goto err;
|
2006-12-06 17:25:34 -06:00
|
|
|
}
|
|
|
|
}
|
2007-10-21 22:25:39 -05:00
|
|
|
|
|
|
|
close(fdout);
|
2006-12-06 17:25:34 -06:00
|
|
|
return 1;
|
2007-10-21 22:25:39 -05:00
|
|
|
|
|
|
|
err:
|
|
|
|
if (fdout >= 0)
|
|
|
|
close(fdout);
|
|
|
|
return 0;
|
2006-12-06 17:25:34 -06:00
|
|
|
}
|
|
|
|
|
2011-05-03 08:47:38 -05:00
|
|
|
static int reread_disk_partition(char *dev, int fd);
|
2006-12-06 17:25:34 -06:00
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
static int
|
2006-12-06 17:25:34 -06:00
|
|
|
restore_sectors(char *dev) {
|
2007-10-21 22:25:39 -05:00
|
|
|
int fdin = -1, fdout = -1;
|
|
|
|
int ct;
|
2006-12-06 17:25:34 -06:00
|
|
|
struct stat statbuf;
|
|
|
|
char *ss0, *ss;
|
|
|
|
unsigned long sno;
|
|
|
|
|
|
|
|
if (stat(restore_sector_file, &statbuf) < 0) {
|
|
|
|
perror(restore_sector_file);
|
2006-12-06 17:25:39 -06:00
|
|
|
error(_("cannot stat partition restore file (%s)\n"),
|
2006-12-06 17:25:34 -06:00
|
|
|
restore_sector_file);
|
2007-10-21 22:25:39 -05:00
|
|
|
goto err;
|
2006-12-06 17:25:34 -06:00
|
|
|
}
|
|
|
|
if (statbuf.st_size % 516) {
|
2006-12-06 17:25:39 -06:00
|
|
|
error(_("partition restore file has wrong size - not restoring\n"));
|
2007-10-21 22:25:39 -05:00
|
|
|
goto err;
|
2006-12-06 17:25:34 -06:00
|
|
|
}
|
|
|
|
if (!(ss = (char *) malloc(statbuf.st_size))) {
|
2006-12-06 17:25:39 -06:00
|
|
|
error(_("out of memory?\n"));
|
2007-10-21 22:25:39 -05:00
|
|
|
goto err;
|
2006-12-06 17:25:34 -06:00
|
|
|
}
|
|
|
|
fdin = open(restore_sector_file, O_RDONLY);
|
|
|
|
if (fdin < 0) {
|
|
|
|
perror(restore_sector_file);
|
2006-12-06 17:25:39 -06:00
|
|
|
error(_("cannot open partition restore file (%s)\n"),
|
2006-12-06 17:25:34 -06:00
|
|
|
restore_sector_file);
|
2007-10-21 22:25:39 -05:00
|
|
|
goto err;
|
2006-12-06 17:25:34 -06:00
|
|
|
}
|
|
|
|
if (read(fdin, ss, statbuf.st_size) != statbuf.st_size) {
|
|
|
|
perror("read");
|
2006-12-06 17:25:39 -06:00
|
|
|
error(_("error reading %s\n"), restore_sector_file);
|
2007-10-21 22:25:39 -05:00
|
|
|
goto err;
|
2006-12-06 17:25:34 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
fdout = open(dev, O_WRONLY);
|
|
|
|
if (fdout < 0) {
|
|
|
|
perror(dev);
|
2006-12-06 17:25:39 -06:00
|
|
|
error(_("cannot open device %s for writing\n"), dev);
|
2007-10-21 22:25:39 -05:00
|
|
|
goto err;
|
2006-12-06 17:25:34 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
ss0 = ss;
|
|
|
|
ct = statbuf.st_size/516;
|
|
|
|
while(ct--) {
|
2007-10-15 19:38:57 -05:00
|
|
|
sno = chars_to_ulong((unsigned char *) ss);
|
2006-12-06 17:25:34 -06:00
|
|
|
if (!sseek(dev, fdout, sno))
|
2007-10-21 22:25:39 -05:00
|
|
|
goto err;
|
2006-12-06 17:25:34 -06:00
|
|
|
if (write(fdout, ss+4, 512) != 512) {
|
|
|
|
perror(dev);
|
2006-12-06 17:25:39 -06:00
|
|
|
error(_("error writing sector %lu on %s\n"), sno, dev);
|
2007-10-21 22:25:39 -05:00
|
|
|
goto err;
|
2006-12-06 17:25:34 -06:00
|
|
|
}
|
|
|
|
ss += 516;
|
|
|
|
}
|
|
|
|
free(ss0);
|
|
|
|
|
2011-05-03 08:47:38 -05:00
|
|
|
if (!reread_disk_partition(dev, fdout))
|
|
|
|
goto err;
|
2007-10-21 22:25:39 -05:00
|
|
|
close(fdin);
|
2006-12-06 17:25:34 -06:00
|
|
|
|
|
|
|
return 1;
|
2007-10-21 22:25:39 -05:00
|
|
|
|
|
|
|
err:
|
|
|
|
if (fdin >= 0)
|
|
|
|
close(fdin);
|
|
|
|
if (fdout >= 0)
|
|
|
|
close(fdout);
|
|
|
|
|
|
|
|
return 0;
|
2006-12-06 17:25:34 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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;
|
|
|
|
* };
|
2006-12-06 17:25:43 -06:00
|
|
|
*
|
|
|
|
* For large disks g.cylinders is truncated, so we use BLKGETSIZE.
|
2006-12-06 17:25:34 -06:00
|
|
|
*/
|
|
|
|
|
2006-12-06 17:25:39 -06:00
|
|
|
/*
|
|
|
|
* 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 {
|
2006-12-06 17:26:22 -06:00
|
|
|
unsigned long long total_size; /* in sectors */
|
|
|
|
unsigned long cylindersize; /* in sectors */
|
2006-12-06 17:25:39 -06:00
|
|
|
unsigned long heads, sectors, cylinders;
|
2006-12-06 17:25:43 -06:00
|
|
|
unsigned long start;
|
2006-12-06 17:25:39 -06:00
|
|
|
} B, F, U;
|
2006-12-06 17:25:34 -06:00
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
static struct geometry
|
|
|
|
get_geometry(char *dev, int fd, int silent) {
|
2006-12-06 17:25:34 -06:00
|
|
|
struct hd_geometry g;
|
2006-12-06 17:26:18 -06:00
|
|
|
unsigned long cyls;
|
|
|
|
unsigned long long sectors;
|
2006-12-06 17:25:43 -06:00
|
|
|
struct geometry R;
|
2006-12-06 17:25:34 -06:00
|
|
|
|
2008-07-23 17:46:05 -05:00
|
|
|
#ifdef HDIO_GETGEO
|
|
|
|
if (ioctl(fd, HDIO_GETGEO, &g))
|
|
|
|
#endif
|
|
|
|
{
|
2006-12-06 17:25:43 -06:00
|
|
|
g.heads = g.sectors = g.cylinders = g.start = 0;
|
|
|
|
if (!silent)
|
2006-12-06 17:26:16 -06:00
|
|
|
do_warn(_("Disk %s: cannot get geometry\n"), dev);
|
2006-12-06 17:25:43 -06:00
|
|
|
}
|
2006-12-06 17:26:18 -06:00
|
|
|
|
|
|
|
R.start = g.start;
|
2006-12-06 17:25:43 -06:00
|
|
|
R.heads = g.heads;
|
|
|
|
R.sectors = g.sectors;
|
|
|
|
R.cylindersize = R.heads * R.sectors;
|
2006-12-06 17:26:18 -06:00
|
|
|
R.cylinders = 0;
|
2006-12-06 17:26:22 -06:00
|
|
|
R.total_size = 0;
|
2006-12-06 17:26:18 -06:00
|
|
|
|
2007-11-07 12:05:31 -06:00
|
|
|
if (blkdev_get_sectors(fd, §ors) == -1) {
|
2006-12-06 17:26:22 -06:00
|
|
|
/* maybe an ordinary file */
|
|
|
|
struct stat s;
|
|
|
|
|
|
|
|
if (fstat(fd, &s) == 0 && S_ISREG(s.st_mode))
|
|
|
|
R.total_size = (s.st_size >> 9);
|
|
|
|
else if (!silent)
|
2006-12-06 17:26:18 -06:00
|
|
|
do_warn(_("Disk %s: cannot get size\n"), dev);
|
2006-12-06 17:26:22 -06:00
|
|
|
} else
|
|
|
|
R.total_size = sectors;
|
|
|
|
|
|
|
|
if (R.cylindersize && R.total_size) {
|
2006-12-06 17:26:18 -06:00
|
|
|
sectors /= R.cylindersize;
|
|
|
|
cyls = sectors;
|
|
|
|
if (cyls != sectors)
|
|
|
|
cyls = ~0;
|
|
|
|
R.cylinders = cyls;
|
|
|
|
}
|
2006-12-06 17:26:22 -06:00
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
return R;
|
|
|
|
}
|
2006-12-06 17:25:34 -06:00
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
static void
|
|
|
|
get_cylindersize(char *dev, int fd, int silent) {
|
|
|
|
struct geometry R;
|
2006-12-06 17:25:34 -06:00
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
R = get_geometry(dev, fd, silent);
|
2006-12-06 17:25:34 -06:00
|
|
|
|
2007-03-08 21:07:52 -06:00
|
|
|
B.heads = (U.heads ? U.heads : R.heads ? R.heads : 255);
|
|
|
|
B.sectors = (U.sectors ? U.sectors : R.sectors ? R.sectors : 63);
|
2006-12-06 17:25:43 -06:00
|
|
|
B.cylinders = (U.cylinders ? U.cylinders : R.cylinders);
|
2006-12-06 17:25:34 -06:00
|
|
|
|
2006-12-06 17:25:39 -06:00
|
|
|
B.cylindersize = B.heads * B.sectors;
|
2006-12-06 17:26:22 -06:00
|
|
|
B.total_size = R.total_size;
|
|
|
|
|
|
|
|
if (B.cylinders == 0 && B.cylindersize != 0)
|
|
|
|
B.cylinders = B.total_size / B.cylindersize;
|
2006-12-06 17:25:34 -06:00
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
if (R.start && !force) {
|
2011-01-31 11:58:26 -06:00
|
|
|
my_warn(
|
2006-12-06 17:25:44 -06:00
|
|
|
_("Warning: start=%lu - this looks like a partition rather than\n"
|
2006-12-06 17:25:43 -06:00
|
|
|
"the entire disk. Using fdisk on it is probably meaningless.\n"
|
|
|
|
"[Use the --force option if you really want this]\n"), R.start);
|
|
|
|
exit(1);
|
|
|
|
}
|
2006-12-06 17:26:36 -06:00
|
|
|
#if 0
|
2006-12-06 17:25:43 -06:00
|
|
|
if (R.heads && B.heads != R.heads)
|
2011-01-31 11:58:26 -06:00
|
|
|
my_warn(_("Warning: HDIO_GETGEO says that there are %lu heads\n"),
|
2006-12-06 17:25:43 -06:00
|
|
|
R.heads);
|
|
|
|
if (R.sectors && B.sectors != R.sectors)
|
2011-01-31 11:58:26 -06:00
|
|
|
my_warn(_("Warning: HDIO_GETGEO says that there are %lu sectors\n"),
|
2006-12-06 17:25:43 -06:00
|
|
|
R.sectors);
|
|
|
|
if (R.cylinders && B.cylinders != R.cylinders
|
|
|
|
&& B.cylinders < 65536 && R.cylinders < 65536)
|
2011-01-31 11:58:26 -06:00
|
|
|
my_warn(_("Warning: BLKGETSIZE/HDIO_GETGEO says that there are %lu cylinders\n"),
|
2006-12-06 17:25:43 -06:00
|
|
|
R.cylinders);
|
2006-12-06 17:26:36 -06:00
|
|
|
#endif
|
2006-12-06 17:25:43 -06:00
|
|
|
|
2006-12-06 17:25:39 -06:00
|
|
|
if (B.sectors > 63)
|
2011-01-31 11:58:26 -06:00
|
|
|
my_warn(_("Warning: unlikely number of sectors (%lu) - usually at most 63\n"
|
2006-12-06 17:25:39 -06:00
|
|
|
"This will give problems with all software that uses C/H/S addressing.\n"),
|
|
|
|
B.sectors);
|
2006-12-06 17:25:34 -06:00
|
|
|
if (!silent)
|
2006-12-06 17:25:39 -06:00
|
|
|
printf(_("\nDisk %s: %lu cylinders, %lu heads, %lu sectors/track\n"),
|
|
|
|
dev, B.cylinders, B.heads, B.sectors);
|
2006-12-06 17:25:34 -06:00
|
|
|
}
|
|
|
|
|
2006-12-06 17:26:22 -06:00
|
|
|
typedef struct { unsigned char h,s,c; } PACKED chs; /* has some c bits in s */
|
2006-12-06 17:25:34 -06:00
|
|
|
chs zero_chs = { 0,0,0 };
|
|
|
|
|
|
|
|
typedef struct { unsigned long h,s,c; } longchs;
|
|
|
|
longchs zero_longchs;
|
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
static chs
|
2006-12-06 17:25:39 -06:00
|
|
|
longchs_to_chs (longchs aa, struct geometry G) {
|
2006-12-06 17:25:34 -06:00
|
|
|
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);
|
2006-12-06 17:25:39 -06:00
|
|
|
} else if (G.heads && G.sectors) {
|
|
|
|
a.h = G.heads - 1;
|
|
|
|
a.s = G.sectors | 0xc0;
|
2006-12-06 17:25:34 -06:00
|
|
|
a.c = 0xff;
|
|
|
|
} else
|
2006-12-06 17:25:39 -06:00
|
|
|
a = zero_chs;
|
2006-12-06 17:25:34 -06:00
|
|
|
return a;
|
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
static longchs
|
2006-12-06 17:25:34 -06:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
static longchs
|
2006-12-06 17:25:39 -06:00
|
|
|
ulong_to_longchs (unsigned long sno, struct geometry G) {
|
2006-12-06 17:25:34 -06:00
|
|
|
longchs aa;
|
|
|
|
|
2006-12-06 17:25:39 -06:00
|
|
|
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;
|
2006-12-06 17:25:34 -06:00
|
|
|
return aa;
|
|
|
|
} else {
|
|
|
|
return zero_longchs;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
static chs
|
2006-12-06 17:25:39 -06:00
|
|
|
ulong_to_chs (unsigned long sno, struct geometry G) {
|
|
|
|
return longchs_to_chs(ulong_to_longchs(sno, G), G);
|
2006-12-06 17:25:34 -06:00
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
#if 0
|
|
|
|
static unsigned long
|
|
|
|
longchs_to_ulong (longchs aa, struct geometry G) {
|
|
|
|
return (aa.c*G.cylindersize + aa.h*G.sectors + aa.s - 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
static unsigned long
|
2006-12-06 17:25:39 -06:00
|
|
|
chs_to_ulong (chs a, struct geometry G) {
|
|
|
|
return longchs_to_ulong(chs_to_longchs(a), G);
|
2006-12-06 17:25:34 -06:00
|
|
|
}
|
2006-12-06 17:25:43 -06:00
|
|
|
#endif
|
2006-12-06 17:25:34 -06:00
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
static int
|
2006-12-06 17:25:34 -06:00
|
|
|
is_equal_chs (chs a, chs b) {
|
|
|
|
return (a.h == b.h && a.s == b.s && a.c == b.c);
|
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
static int
|
2006-12-06 17:25:34 -06:00
|
|
|
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;
|
2006-12-06 17:25:39 -06:00
|
|
|
if (B.heads && aa.h >= B.heads) {
|
2011-01-31 11:58:26 -06:00
|
|
|
my_warn(_("%s of partition %s has impossible value for head: "
|
2006-12-06 17:25:44 -06:00
|
|
|
"%lu (should be in 0-%lu)\n"), w, v, aa.h, B.heads-1);
|
2006-12-06 17:25:34 -06:00
|
|
|
ret = 0;
|
|
|
|
}
|
2006-12-06 17:25:39 -06:00
|
|
|
if (B.sectors && (aa.s == 0 || aa.s > B.sectors)) {
|
2011-01-31 11:58:26 -06:00
|
|
|
my_warn(_("%s of partition %s has impossible value for sector: "
|
2006-12-06 17:25:44 -06:00
|
|
|
"%lu (should be in 1-%lu)\n"), w, v, aa.s, B.sectors);
|
2006-12-06 17:25:34 -06:00
|
|
|
ret = 0;
|
|
|
|
}
|
2006-12-06 17:25:39 -06:00
|
|
|
if (B.cylinders && aa.c >= B.cylinders) {
|
2011-01-31 11:58:26 -06:00
|
|
|
my_warn(_("%s of partition %s has impossible value for cylinders: "
|
2006-12-06 17:25:44 -06:00
|
|
|
"%lu (should be in 0-%lu)\n"), w, v, aa.c, B.cylinders-1);
|
2006-12-06 17:25:34 -06:00
|
|
|
ret = 0;
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* D. About system Ids
|
|
|
|
*/
|
|
|
|
|
|
|
|
#define EMPTY_PARTITION 0
|
|
|
|
#define EXTENDED_PARTITION 5
|
2006-12-06 17:25:35 -06:00
|
|
|
#define WIN98_EXTENDED 0x0f
|
2006-12-06 17:25:34 -06:00
|
|
|
#define DM6_AUX1PARTITION 0x51
|
|
|
|
#define DM6_AUX3PARTITION 0x53
|
2006-12-06 17:25:35 -06:00
|
|
|
#define DM6_PARTITION 0x54
|
|
|
|
#define EZD_PARTITION 0x55
|
2006-12-06 17:25:34 -06:00
|
|
|
#define LINUX_SWAP 0x82
|
|
|
|
#define LINUX_NATIVE 0x83
|
|
|
|
#define LINUX_EXTENDED 0x85
|
2006-12-06 17:25:35 -06:00
|
|
|
#define BSD_PARTITION 0xa5
|
2006-12-06 17:25:49 -06:00
|
|
|
#define NETBSD_PARTITION 0xa9
|
2006-12-06 17:25:34 -06:00
|
|
|
|
2006-12-06 17:25:39 -06:00
|
|
|
/* List of partition types now in i386_sys_types.c */
|
2006-12-06 17:25:34 -06:00
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
static const char *
|
2006-12-06 17:25:34 -06:00
|
|
|
sysname(unsigned char type) {
|
|
|
|
struct systypes *s;
|
|
|
|
|
2006-12-06 17:25:39 -06:00
|
|
|
for (s = i386_sys_types; s->name; s++)
|
2006-12-06 17:25:34 -06:00
|
|
|
if (s->type == type)
|
2006-12-06 17:25:39 -06:00
|
|
|
return _(s->name);
|
|
|
|
return _("Unknown");
|
2006-12-06 17:25:34 -06:00
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
static void
|
2006-12-06 17:25:34 -06:00
|
|
|
list_types(void) {
|
|
|
|
struct systypes *s;
|
|
|
|
|
2006-12-06 17:25:39 -06:00
|
|
|
printf(_("Id Name\n\n"));
|
|
|
|
for (s = i386_sys_types; s->name; s++)
|
|
|
|
printf("%2x %s\n", s->type, _(s->name));
|
2006-12-06 17:25:34 -06:00
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
static int
|
2006-12-06 17:25:34 -06:00
|
|
|
is_extended(unsigned char type) {
|
2006-12-06 17:25:35 -06:00
|
|
|
return (type == EXTENDED_PARTITION
|
|
|
|
|| type == LINUX_EXTENDED
|
|
|
|
|| type == WIN98_EXTENDED);
|
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
static int
|
2006-12-06 17:25:35 -06:00
|
|
|
is_bsd(unsigned char type) {
|
2006-12-06 17:25:49 -06:00
|
|
|
return (type == BSD_PARTITION || type == NETBSD_PARTITION);
|
2006-12-06 17:25:34 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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 */
|
2006-12-06 17:26:22 -06:00
|
|
|
unsigned int nr_sects; /* nr of sectors in partition */
|
|
|
|
} PACKED;
|
2006-12-06 17:25:34 -06:00
|
|
|
|
|
|
|
/* Unfortunately, partitions are not aligned, and non-Intel machines
|
|
|
|
are unhappy with non-aligned integers. So, we need a copy by hand. */
|
2006-12-06 17:25:43 -06:00
|
|
|
static int
|
2006-12-06 17:25:34 -06:00
|
|
|
copy_to_int(unsigned char *cp) {
|
|
|
|
unsigned int m;
|
|
|
|
|
|
|
|
m = *cp++;
|
|
|
|
m += (*cp++ << 8);
|
|
|
|
m += (*cp++ << 16);
|
|
|
|
m += (*cp++ << 24);
|
|
|
|
return m;
|
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
static void
|
2006-12-06 17:25:34 -06:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
static void
|
2006-12-06 17:25:34 -06:00
|
|
|
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++;
|
2007-10-15 19:38:57 -05:00
|
|
|
p->start_sect = copy_to_int((unsigned char *) cp);
|
|
|
|
p->nr_sects = copy_to_int((unsigned char *) cp+4);
|
2006-12-06 17:25:34 -06:00
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
static void
|
2006-12-06 17:25:34 -06:00
|
|
|
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 */
|
2006-12-06 17:25:35 -06:00
|
|
|
int ptype;
|
|
|
|
#define DOS_TYPE 0
|
|
|
|
#define BSD_TYPE 1
|
2006-12-06 17:25:34 -06:00
|
|
|
} zero_part_desc;
|
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
static struct part_desc *
|
2006-12-06 17:25:34 -06:00
|
|
|
outer_extended_partition(struct part_desc *p) {
|
|
|
|
while (p->ep)
|
|
|
|
p = p->ep;
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
static int
|
2006-12-06 17:25:34 -06:00
|
|
|
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 {
|
2006-12-06 17:25:49 -06:00
|
|
|
struct part_desc partitions[512];
|
2006-12-06 17:25:34 -06:00
|
|
|
int partno;
|
|
|
|
} oldp, newp;
|
|
|
|
|
|
|
|
/* determine where on the disk this information goes */
|
2006-12-06 17:25:43 -06:00
|
|
|
static void
|
2006-12-06 17:25:34 -06:00
|
|
|
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 */
|
2006-12-06 17:25:43 -06:00
|
|
|
static int
|
2006-12-06 17:25:39 -06:00
|
|
|
reread_ioctl(int fd) {
|
2008-07-23 17:46:05 -05:00
|
|
|
#ifdef BLKRRPART
|
|
|
|
if (ioctl(fd, BLKRRPART))
|
|
|
|
#else
|
|
|
|
errno = ENOSYS;
|
|
|
|
#endif
|
|
|
|
{
|
2010-10-04 20:01:30 -05:00
|
|
|
/* perror might change errno */
|
|
|
|
int err = errno;
|
|
|
|
|
2006-12-06 17:25:34 -06:00
|
|
|
perror("BLKRRPART");
|
2006-12-06 17:26:24 -06:00
|
|
|
|
|
|
|
/* 2.6.8 returns EIO for a zero table */
|
2010-10-04 20:01:30 -05:00
|
|
|
if (err == EBUSY)
|
2006-12-06 17:26:24 -06:00
|
|
|
return -1;
|
2006-12-06 17:25:34 -06:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
static int
|
2008-10-22 23:21:14 -05:00
|
|
|
is_blockdev(int fd) {
|
2006-12-06 17:25:39 -06:00
|
|
|
struct stat statbuf;
|
|
|
|
|
|
|
|
return(fstat(fd, &statbuf) == 0 && S_ISBLK(statbuf.st_mode));
|
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:34 -06:00
|
|
|
/* reread after writing */
|
2011-05-03 08:47:38 -05:00
|
|
|
static int
|
2006-12-06 17:25:34 -06:00
|
|
|
reread_disk_partition(char *dev, int fd) {
|
2006-12-06 17:25:39 -06:00
|
|
|
printf(_("Re-reading the partition table ...\n"));
|
2006-12-06 17:25:34 -06:00
|
|
|
fflush(stdout);
|
|
|
|
sync();
|
|
|
|
|
2011-05-03 08:47:38 -05:00
|
|
|
if (reread_ioctl(fd) && is_blockdev(fd)) {
|
2008-09-16 06:08:12 -05:00
|
|
|
do_warn(_("The command to re-read the partition table failed.\n"
|
|
|
|
"Run partprobe(8), kpartx(8) or reboot your system now,\n"
|
|
|
|
"before using mkfs\n"));
|
2011-05-03 08:47:38 -05:00
|
|
|
return 0;
|
|
|
|
}
|
2006-12-06 17:25:34 -06:00
|
|
|
|
2010-01-06 04:12:43 -06:00
|
|
|
if (fsync(fd) || close(fd)) {
|
2011-05-03 08:47:38 -05:00
|
|
|
perror(dev);
|
|
|
|
do_warn(_("Error closing %s\n"), dev);
|
|
|
|
return 0;
|
2006-12-06 17:25:34 -06:00
|
|
|
}
|
|
|
|
printf("\n");
|
2011-05-03 08:47:38 -05:00
|
|
|
|
|
|
|
return 1;
|
2006-12-06 17:25:34 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
/* find Linux name of this partition, assuming that it will have a name */
|
2006-12-06 17:25:43 -06:00
|
|
|
static int
|
2006-12-06 17:25:34 -06:00
|
|
|
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++)
|
2006-12-06 17:26:16 -06:00
|
|
|
if (i < 4 || (p->size > 0 && !is_extended(p->p.sys_type)))
|
2006-12-06 17:25:34 -06:00
|
|
|
ct++;
|
|
|
|
return ct;
|
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
static int
|
2006-12-06 17:25:34 -06:00
|
|
|
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++)
|
2006-12-06 17:26:16 -06:00
|
|
|
if ((i < 4 || (p->size > 0 && !is_extended(p->p.sys_type)))
|
2006-12-06 17:25:34 -06:00
|
|
|
&& ++ct == lpno)
|
|
|
|
return i;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
static int
|
2006-12-06 17:25:34 -06:00
|
|
|
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))
|
2006-12-06 17:25:39 -06:00
|
|
|
fatal(_("%s: no such partition\n"), pnam);
|
2006-12-06 17:25:34 -06:00
|
|
|
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
|
|
|
|
|
|
|
|
int default_format = F_MEGABYTE;
|
|
|
|
int specified_format = 0;
|
|
|
|
int show_extended = 0;
|
|
|
|
int one_only = 0;
|
|
|
|
int one_only_pno;
|
|
|
|
int increment = 0;
|
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
static void
|
2006-12-06 17:25:34 -06:00
|
|
|
set_format(char c) {
|
|
|
|
switch(c) {
|
|
|
|
default:
|
2006-12-06 17:26:16 -06:00
|
|
|
do_warn(_("unrecognized format - using sectors\n"));
|
2006-12-06 17:25:34 -06:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
static unsigned long
|
2006-12-06 17:25:34 -06:00
|
|
|
unitsize(int format) {
|
2006-12-06 17:25:39 -06:00
|
|
|
default_format = (B.cylindersize ? F_CYLINDER : F_MEGABYTE);
|
2006-12-06 17:25:34 -06:00
|
|
|
if (!format && !(format = specified_format))
|
|
|
|
format = default_format;
|
|
|
|
|
|
|
|
switch(format) {
|
|
|
|
default:
|
|
|
|
case F_CYLINDER:
|
2006-12-06 17:26:16 -06:00
|
|
|
if (B.cylindersize)
|
2006-12-06 17:25:39 -06:00
|
|
|
return B.cylindersize;
|
2006-12-06 17:25:34 -06:00
|
|
|
case F_SECTOR:
|
|
|
|
return 1;
|
|
|
|
case F_BLOCK:
|
|
|
|
return 2;
|
|
|
|
case F_MEGABYTE:
|
|
|
|
return 2048;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
static unsigned long
|
2006-12-06 17:25:34 -06:00
|
|
|
get_disksize(int format) {
|
sfdisk: confused about disk size
The size of disk in the sfdisk command is based on number of cylinders
(this is probably legacy from CHS epoch). That's wrong because
partitions are addressed in sectors (LBA), so cylinders don't provide
necessary resolution (granularity).
On Sat, Jan 02, 2010 at 01:01:16PM +0100, Giulio wrote:
> $ cat /sys/block/sda/size
> 184549376
>
> $ sfdisk -d /dev/sda > part.dump
> $ cat part.dump
> # partition table of /dev/sda
> unit: sectors
>
> /dev/sda1 : start= 2048, size= 2097152, Id=83
> /dev/sda2 : start= 2099200, size= 12582912, Id=83
> /dev/sda3 : start= 14682112, size= 84934656, Id=83
> /dev/sda4 : start= 99616768, size= 84932608, Id=83
>
>
> $ sfdisk -L /dev/sda < part.dump
> Checking that no-one is using this disk right now ...
> OK
>
> Disk /dev/sda: 11487 cylinders, 255 heads, 63 sectors/track
> Old situation:
> Units = cylinders of 8225280 bytes, blocks of 1024 bytes, counting from 0
>
> Device Boot Start End #cyls #blocks Id System
> /dev/sda1 0+ 130- 131- 1048576 83 Linux
> /dev/sda2 130+ 913- 784- 6291456 83 Linux
> /dev/sda3 913+ 6200- 5287- 42467328 83 Linux
> /dev/sda4 6200+ 11487- 5287- 42466304 83 Linux
> Warning: given size (84932608) exceeds max allowable size (84921887)
disk size:
based on number of cylinders: 11487 * 8225280 = 94483791360 bytes
based on number of sectors: 184549376 * 512 = 94489280512 bytes
end of 4th partition (LBA in bytes):
(99616768 + 84932608) * 512 = 94489280512
Reported-by: Giulio <giulioo@gmail.com>
Signed-off-by: Karel Zak <kzak@redhat.com>
2010-01-04 04:34:13 -06:00
|
|
|
if (B.total_size && leave_last)
|
|
|
|
/* don't use last cylinder (--leave-last option) */
|
|
|
|
return (B.total_size - B.cylindersize) / unitsize(format);
|
|
|
|
|
|
|
|
return B.total_size / unitsize(format);
|
2006-12-06 17:25:34 -06:00
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
static void
|
2006-12-06 17:25:39 -06:00
|
|
|
out_partition_header(char *dev, int format, struct geometry G) {
|
2006-12-06 17:25:34 -06:00
|
|
|
if (dump) {
|
2009-09-11 07:00:50 -05:00
|
|
|
printf("# partition table of %s\n", dev);
|
|
|
|
printf("unit: sectors\n\n");
|
2006-12-06 17:25:34 -06:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:39 -06:00
|
|
|
default_format = (G.cylindersize ? F_CYLINDER : F_MEGABYTE);
|
2006-12-06 17:25:34 -06:00
|
|
|
if (!format && !(format = specified_format))
|
|
|
|
format = default_format;
|
|
|
|
|
|
|
|
switch(format) {
|
|
|
|
default:
|
2006-12-06 17:26:16 -06:00
|
|
|
do_warn(_("unimplemented format - using %s\n"),
|
2006-12-06 17:25:39 -06:00
|
|
|
G.cylindersize ? _("cylinders") : _("sectors"));
|
2006-12-06 17:25:34 -06:00
|
|
|
case F_CYLINDER:
|
2006-12-06 17:25:39 -06:00
|
|
|
if (G.cylindersize) {
|
|
|
|
printf(_("Units = cylinders of %lu bytes, blocks of 1024 bytes"
|
|
|
|
", counting from %d\n\n"),
|
|
|
|
G.cylindersize<<9, increment);
|
2006-12-06 17:25:53 -06:00
|
|
|
printf(_(" Device Boot Start End #cyls #blocks Id System\n"));
|
2006-12-06 17:25:34 -06:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
/* fall through */
|
|
|
|
case F_SECTOR:
|
2006-12-06 17:25:39 -06:00
|
|
|
printf(_("Units = sectors of 512 bytes, counting from %d\n\n"),
|
2006-12-06 17:25:34 -06:00
|
|
|
increment);
|
2006-12-06 17:25:53 -06:00
|
|
|
printf(_(" Device Boot Start End #sectors Id System\n"));
|
2006-12-06 17:25:34 -06:00
|
|
|
break;
|
|
|
|
case F_BLOCK:
|
2006-12-06 17:25:39 -06:00
|
|
|
printf(_("Units = blocks of 1024 bytes, counting from %d\n\n"),
|
2006-12-06 17:25:34 -06:00
|
|
|
increment);
|
2006-12-06 17:25:53 -06:00
|
|
|
printf(_(" Device Boot Start End #blocks Id System\n"));
|
2006-12-06 17:25:34 -06:00
|
|
|
break;
|
|
|
|
case F_MEGABYTE:
|
2006-12-06 17:26:12 -06:00
|
|
|
printf(_("Units = mebibytes of 1048576 bytes, blocks of 1024 bytes"
|
2006-12-06 17:25:39 -06:00
|
|
|
", counting from %d\n\n"), increment);
|
2006-12-06 17:26:12 -06:00
|
|
|
printf(_(" Device Boot Start End MiB #blocks Id System\n"));
|
2006-12-06 17:25:34 -06:00
|
|
|
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(' ');
|
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:53 -06:00
|
|
|
static struct geometry
|
|
|
|
get_fdisk_geometry_one(struct part_desc *p) {
|
|
|
|
struct geometry G;
|
|
|
|
|
2007-07-02 08:30:27 -05:00
|
|
|
memset(&G, 0, sizeof(struct geometry));
|
2006-12-06 17:25:39 -06:00
|
|
|
chs b = p->p.end_chs;
|
|
|
|
longchs bb = chs_to_longchs(b);
|
2006-12-06 17:25:53 -06:00
|
|
|
G.heads = bb.h+1;
|
|
|
|
G.sectors = bb.s;
|
|
|
|
G.cylindersize = G.heads*G.sectors;
|
|
|
|
return G;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
get_fdisk_geometry(struct disk_desc *z) {
|
|
|
|
struct part_desc *p;
|
|
|
|
int pno, agree;
|
|
|
|
struct geometry G0, G;
|
|
|
|
|
2007-07-02 08:30:27 -05:00
|
|
|
memset(&G0, 0, sizeof(struct geometry));
|
2006-12-06 17:25:53 -06:00
|
|
|
agree = 0;
|
|
|
|
for (pno=0; pno < z->partno; pno++) {
|
|
|
|
p = &(z->partitions[pno]);
|
|
|
|
if (p->size != 0 && p->p.sys_type != 0) {
|
|
|
|
G = get_fdisk_geometry_one(p);
|
|
|
|
if (!G0.heads) {
|
|
|
|
G0 = G;
|
|
|
|
agree = 1;
|
|
|
|
} else if (G.heads != G0.heads || G.sectors != G0.sectors) {
|
|
|
|
agree = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
F = (agree ? G0 : B);
|
2006-12-06 17:25:39 -06:00
|
|
|
return (F.sectors != B.sectors || F.heads != B.heads);
|
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
static void
|
2006-12-06 17:25:39 -06:00
|
|
|
out_partition(char *dev, int format, struct part_desc *p,
|
|
|
|
struct disk_desc *z, struct geometry G) {
|
2006-12-06 17:25:34 -06:00
|
|
|
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 */
|
2006-12-06 17:26:16 -06:00
|
|
|
if (pno == linux_to_index(lpno, z)) /* was that us? */
|
2006-12-06 17:25:43 -06:00
|
|
|
printf("%s", partname(dev, lpno, 10)); /* yes */
|
2006-12-06 17:26:16 -06:00
|
|
|
else if (show_extended)
|
2006-12-06 17:25:34 -06:00
|
|
|
printf(" - ");
|
|
|
|
else
|
|
|
|
return;
|
|
|
|
putchar(dump ? ':' : ' ');
|
|
|
|
|
|
|
|
start = p->start;
|
|
|
|
end = p->start + p->size - 1;
|
|
|
|
size = p->size;
|
|
|
|
|
|
|
|
if (dump) {
|
2009-09-11 07:00:50 -05:00
|
|
|
printf(" start=%9lu", start);
|
|
|
|
printf(", size=%9lu", size);
|
2006-12-06 17:25:35 -06:00
|
|
|
if (p->ptype == DOS_TYPE) {
|
2006-12-06 17:25:41 -06:00
|
|
|
printf(", Id=%2x", p->p.sys_type);
|
2006-12-06 17:25:35 -06:00
|
|
|
if (p->p.bootable == 0x80)
|
2009-09-11 07:00:50 -05:00
|
|
|
printf(", bootable");
|
2006-12-06 17:25:35 -06:00
|
|
|
}
|
2006-12-06 17:25:34 -06:00
|
|
|
printf("\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2006-12-06 17:26:16 -06:00
|
|
|
if (p->ptype != DOS_TYPE || p->p.bootable == 0)
|
2006-12-06 17:25:34 -06:00
|
|
|
printf(" ");
|
2006-12-06 17:26:16 -06:00
|
|
|
else if (p->p.bootable == 0x80)
|
2006-12-06 17:25:35 -06:00
|
|
|
printf(" * ");
|
2006-12-06 17:25:34 -06:00
|
|
|
else
|
|
|
|
printf(" ? "); /* garbage */
|
|
|
|
|
|
|
|
switch(format) {
|
|
|
|
case F_CYLINDER:
|
2006-12-06 17:25:39 -06:00
|
|
|
if (G.cylindersize) {
|
|
|
|
out_rounddown(6, start, G.cylindersize, increment);
|
|
|
|
out_roundup(6, end, G.cylindersize, increment);
|
|
|
|
out_roundup_size(6, size, G.cylindersize);
|
2006-12-06 17:25:53 -06:00
|
|
|
out_rounddown(9, size, 2, 0);
|
2006-12-06 17:25:34 -06:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
/* fall through */
|
|
|
|
default:
|
|
|
|
case F_SECTOR:
|
|
|
|
out_rounddown(9, start, 1, increment);
|
|
|
|
out_roundup(9, end, 1, increment);
|
2006-12-06 17:25:53 -06:00
|
|
|
out_rounddown(10, size, 1, 0);
|
2006-12-06 17:25:34 -06:00
|
|
|
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);
|
2006-12-06 17:25:53 -06:00
|
|
|
out_rounddown(9, size, 2, 0);
|
2006-12-06 17:25:34 -06:00
|
|
|
break;
|
|
|
|
case F_MEGABYTE:
|
|
|
|
out_rounddown(5, start, 2048, increment);
|
|
|
|
out_roundup(5, end, 2048, increment);
|
|
|
|
out_roundup_size(5, size, 2048);
|
2006-12-06 17:25:53 -06:00
|
|
|
out_rounddown(9, size, 2, 0);
|
2006-12-06 17:25:34 -06:00
|
|
|
break;
|
|
|
|
}
|
2006-12-06 17:25:35 -06:00
|
|
|
if (p->ptype == DOS_TYPE) {
|
2006-12-06 17:25:53 -06:00
|
|
|
printf(" %2x %s\n",
|
2006-12-06 17:25:34 -06:00
|
|
|
p->p.sys_type, sysname(p->p.sys_type));
|
2006-12-06 17:25:35 -06:00
|
|
|
} else {
|
|
|
|
printf("\n");
|
|
|
|
}
|
2006-12-06 17:25:34 -06:00
|
|
|
|
|
|
|
/* Is chs as we expect? */
|
2006-12-06 17:25:35 -06:00
|
|
|
if (!quiet && p->ptype == DOS_TYPE) {
|
2006-12-06 17:25:34 -06:00
|
|
|
chs a, b;
|
|
|
|
longchs aa, bb;
|
2006-12-06 17:25:39 -06:00
|
|
|
a = (size ? ulong_to_chs(start,G) : zero_chs);
|
2006-12-06 17:25:34 -06:00
|
|
|
b = p->p.begin_chs;
|
|
|
|
aa = chs_to_longchs(a);
|
|
|
|
bb = chs_to_longchs(b);
|
2006-12-06 17:26:16 -06:00
|
|
|
if (a.s && !is_equal_chs(a, b))
|
|
|
|
do_warn(_("\t\tstart: (c,h,s) expected (%ld,%ld,%ld) found (%ld,%ld,%ld)\n"),
|
2006-12-06 17:25:34 -06:00
|
|
|
aa.c, aa.h, aa.s, bb.c, bb.h, bb.s);
|
2006-12-06 17:25:39 -06:00
|
|
|
a = (size ? ulong_to_chs(end,G) : zero_chs);
|
2006-12-06 17:25:34 -06:00
|
|
|
b = p->p.end_chs;
|
|
|
|
aa = chs_to_longchs(a);
|
|
|
|
bb = chs_to_longchs(b);
|
2006-12-06 17:26:16 -06:00
|
|
|
if (a.s && !is_equal_chs(a, b))
|
|
|
|
do_warn(_("\t\tend: (c,h,s) expected (%ld,%ld,%ld) found (%ld,%ld,%ld)\n"),
|
2006-12-06 17:25:34 -06:00
|
|
|
aa.c, aa.h, aa.s, bb.c, bb.h, bb.s);
|
2006-12-06 17:26:16 -06:00
|
|
|
if (G.cylinders && G.cylinders < 1024 && bb.c > G.cylinders)
|
|
|
|
do_warn(_("partition ends on cylinder %ld, beyond the end of the disk\n"),
|
2006-12-06 17:25:34 -06:00
|
|
|
bb.c);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
static void
|
2006-12-06 17:25:34 -06:00
|
|
|
out_partitions(char *dev, struct disk_desc *z) {
|
|
|
|
int pno, format = 0;
|
|
|
|
|
|
|
|
if (z->partno == 0)
|
2006-12-06 17:26:16 -06:00
|
|
|
do_warn(_("No partitions found\n"));
|
2006-12-06 17:25:34 -06:00
|
|
|
else {
|
2006-12-06 17:25:53 -06:00
|
|
|
if (get_fdisk_geometry(z) && !dump) {
|
2006-12-06 17:26:16 -06:00
|
|
|
do_warn(
|
2006-12-06 17:25:53 -06:00
|
|
|
_("Warning: The partition table 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);
|
2006-12-06 17:25:41 -06:00
|
|
|
}
|
2006-12-06 17:25:53 -06:00
|
|
|
|
2006-12-06 17:25:39 -06:00
|
|
|
out_partition_header(dev, format, F);
|
2006-12-06 17:25:34 -06:00
|
|
|
for(pno=0; pno < z->partno; pno++) {
|
2006-12-06 17:25:39 -06:00
|
|
|
out_partition(dev, format, &(z->partitions[pno]), z, F);
|
2006-12-06 17:26:16 -06:00
|
|
|
if (show_extended && pno%4==3)
|
2006-12-06 17:25:34 -06:00
|
|
|
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));
|
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
static char *
|
2006-12-06 17:25:34 -06:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
static int
|
2006-12-06 17:25:34 -06:00
|
|
|
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) {
|
2006-12-06 17:25:53 -06:00
|
|
|
if (!partno)
|
2006-12-06 17:25:39 -06:00
|
|
|
fatal(_("no partition table present.\n"));
|
2006-12-06 17:25:34 -06:00
|
|
|
else
|
2006-12-06 17:25:39 -06:00
|
|
|
fatal(_("strange, only %d partitions defined.\n"), partno);
|
2006-12-06 17:25:34 -06:00
|
|
|
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) {
|
2006-12-06 17:26:16 -06:00
|
|
|
if (p->p.sys_type != EMPTY_PARTITION)
|
2011-01-31 11:58:26 -06:00
|
|
|
my_warn(_("Warning: partition %s has size 0 but is not marked Empty\n"),
|
2006-12-06 17:25:34 -06:00
|
|
|
PNO(p));
|
2006-12-06 17:26:16 -06:00
|
|
|
else if (p->p.bootable != 0)
|
2011-01-31 11:58:26 -06:00
|
|
|
my_warn(_("Warning: partition %s has size 0 and is bootable\n"),
|
2006-12-06 17:25:34 -06:00
|
|
|
PNO(p));
|
2006-12-06 17:26:16 -06:00
|
|
|
else if (p->p.start_sect != 0)
|
2011-01-31 11:58:26 -06:00
|
|
|
my_warn(_("Warning: partition %s has size 0 and nonzero start\n"),
|
2006-12-06 17:25:34 -06:00
|
|
|
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++)
|
2006-12-06 17:25:35 -06:00
|
|
|
if (p->ptype == DOS_TYPE)
|
2006-12-06 17:25:34 -06:00
|
|
|
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) {
|
2011-01-31 11:58:26 -06:00
|
|
|
my_warn(_("Warning: partition %s "), PNO(p));
|
|
|
|
my_warn(_("is not contained in partition %s\n"), PNO(q));
|
2006-12-06 17:25:34 -06:00
|
|
|
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))
|
2006-12-06 17:26:16 -06:00
|
|
|
if (!((p->start > q-> start) ? disj(q,p) : disj(p,q))) {
|
2011-01-31 11:58:26 -06:00
|
|
|
my_warn(_("Warning: partitions %s "), PNO(p));
|
|
|
|
my_warn(_("and %s overlap\n"), PNO(q));
|
2006-12-06 17:25:34 -06:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:35 -06:00
|
|
|
/* 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))
|
2006-12-06 17:25:53 -06:00
|
|
|
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) {
|
2011-01-31 11:58:26 -06:00
|
|
|
my_warn(_("Warning: partition %s contains part of "
|
2006-12-06 17:25:48 -06:00
|
|
|
"the partition table (sector %lu),\n"
|
|
|
|
"and will destroy it when filled\n"),
|
|
|
|
PNO(p), q->start);
|
2006-12-06 17:25:35 -06:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:34 -06:00
|
|
|
/* 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) {
|
2006-12-06 17:26:16 -06:00
|
|
|
if (p->start == 0) {
|
2011-01-31 11:58:26 -06:00
|
|
|
my_warn(_("Warning: partition %s starts at sector 0\n"), PNO(p));
|
2006-12-06 17:25:34 -06:00
|
|
|
return 0;
|
2006-12-06 17:25:53 -06:00
|
|
|
}
|
|
|
|
if (p->size && p->start + p->size > ds) {
|
2011-01-31 11:58:26 -06:00
|
|
|
my_warn(_("Warning: partition %s extends past end of disk\n"),
|
2006-12-06 17:25:48 -06:00
|
|
|
PNO(p));
|
2006-12-06 17:25:34 -06:00
|
|
|
return 0;
|
2006-12-06 17:25:53 -06:00
|
|
|
}
|
2006-12-06 17:25:34 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* 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) {
|
2011-01-31 11:58:26 -06:00
|
|
|
my_warn(_("Among the primary partitions, at most one can be extended\n"
|
2006-12-06 17:25:48 -06:00
|
|
|
" (although this is not a problem under Linux)\n"));
|
2006-12-06 17:25:34 -06:00
|
|
|
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.
|
|
|
|
*/
|
2006-12-06 17:25:39 -06:00
|
|
|
if (B.cylindersize) {
|
2006-12-06 17:25:34 -06:00
|
|
|
for(p = partitions; p < partitions+partno; p++)
|
|
|
|
if (p->size) {
|
2006-12-06 17:26:16 -06:00
|
|
|
if (p->start % B.cylindersize != 0
|
2006-12-06 17:25:39 -06:00
|
|
|
&& (!p->ep || p->start / B.cylindersize != p->ep->start / B.cylindersize)
|
|
|
|
&& (p->p.start_sect >= B.cylindersize)) {
|
2011-01-31 11:58:26 -06:00
|
|
|
my_warn(_("Warning: partition %s does not start "
|
2006-12-06 17:25:39 -06:00
|
|
|
"at a cylinder boundary\n"), PNO(p));
|
2006-12-06 17:25:34 -06:00
|
|
|
if (!Linux)
|
|
|
|
return 0;
|
|
|
|
}
|
2006-12-06 17:26:16 -06:00
|
|
|
if ((p->start + p->size) % B.cylindersize) {
|
2011-01-31 11:58:26 -06:00
|
|
|
my_warn(_("Warning: partition %s does not end "
|
2006-12-06 17:25:39 -06:00
|
|
|
"at a cylinder boundary\n"), PNO(p));
|
2006-12-06 17:25:34 -06:00
|
|
|
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) {
|
2011-01-31 11:58:26 -06:00
|
|
|
my_warn(_("Warning: more than one primary partition is marked "
|
2006-12-06 17:25:34 -06:00
|
|
|
"bootable (active)\n"
|
|
|
|
"This does not matter for LILO, but the DOS MBR will "
|
2006-12-06 17:25:39 -06:00
|
|
|
"not boot this disk.\n"));
|
2006-12-06 17:25:34 -06:00
|
|
|
break;
|
2006-12-06 17:25:53 -06:00
|
|
|
}
|
2006-12-06 17:25:34 -06:00
|
|
|
if (p - partitions >= 4) {
|
2011-01-31 11:58:26 -06:00
|
|
|
my_warn(_("Warning: usually one can boot from primary partitions "
|
2006-12-06 17:25:39 -06:00
|
|
|
"only\nLILO disregards the `bootable' flag.\n"));
|
2006-12-06 17:25:34 -06:00
|
|
|
break;
|
2006-12-06 17:25:53 -06:00
|
|
|
}
|
2006-12-06 17:25:34 -06:00
|
|
|
}
|
|
|
|
if (pno == -1 || pno >= 4)
|
2011-01-31 11:58:26 -06:00
|
|
|
my_warn(_("Warning: no primary partition is marked bootable (active)\n"
|
2006-12-06 17:25:34 -06:00
|
|
|
"This does not matter for LILO, but the DOS MBR will "
|
2006-12-06 17:25:39 -06:00
|
|
|
"not boot this disk.\n"));
|
2006-12-06 17:25:34 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Is chs as we expect? */
|
2006-12-06 17:25:35 -06:00
|
|
|
for(p = partitions; p < partitions+partno; p++)
|
2006-12-06 17:26:16 -06:00
|
|
|
if (p->ptype == DOS_TYPE) {
|
2006-12-06 17:25:34 -06:00
|
|
|
chs a, b;
|
|
|
|
longchs aa, bb;
|
2006-12-06 17:25:39 -06:00
|
|
|
a = p->size ? ulong_to_chs(p->start,B) : zero_chs;
|
2006-12-06 17:25:34 -06:00
|
|
|
b = p->p.begin_chs;
|
|
|
|
aa = chs_to_longchs(a);
|
|
|
|
bb = chs_to_longchs(b);
|
2006-12-06 17:26:12 -06:00
|
|
|
if (!chs_ok(b, PNO(p), _("start")))
|
2006-12-06 17:25:34 -06:00
|
|
|
return 0;
|
2006-12-06 17:26:16 -06:00
|
|
|
if (a.s && !is_equal_chs(a, b))
|
2011-01-31 11:58:26 -06:00
|
|
|
my_warn(_("partition %s: start: (c,h,s) expected (%ld,%ld,%ld) found (%ld,%ld,%ld)\n"),
|
2006-12-06 17:25:34 -06:00
|
|
|
PNO(p), aa.c, aa.h, aa.s, bb.c, bb.h, bb.s);
|
2006-12-06 17:25:39 -06:00
|
|
|
a = p->size ? ulong_to_chs(p->start + p->size - 1, B) : zero_chs;
|
2006-12-06 17:25:34 -06:00
|
|
|
b = p->p.end_chs;
|
|
|
|
aa = chs_to_longchs(a);
|
|
|
|
bb = chs_to_longchs(b);
|
2006-12-06 17:26:12 -06:00
|
|
|
if (!chs_ok(b, PNO(p), _("end")))
|
2006-12-06 17:25:34 -06:00
|
|
|
return 0;
|
2006-12-06 17:26:16 -06:00
|
|
|
if (a.s && !is_equal_chs(a, b))
|
2011-01-31 11:58:26 -06:00
|
|
|
my_warn(_("partition %s: end: (c,h,s) expected (%ld,%ld,%ld) found (%ld,%ld,%ld)\n"),
|
2006-12-06 17:25:34 -06:00
|
|
|
PNO(p), aa.c, aa.h, aa.s, bb.c, bb.h, bb.s);
|
2006-12-06 17:26:16 -06:00
|
|
|
if (B.cylinders && B.cylinders < 1024 && bb.c > B.cylinders)
|
2011-01-31 11:58:26 -06:00
|
|
|
my_warn(_("partition %s ends on cylinder %ld, beyond the end of the disk\n"),
|
2006-12-06 17:25:34 -06:00
|
|
|
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]);
|
2011-06-06 13:39:17 -05:00
|
|
|
size_t pno = z->partno;
|
2006-12-06 17:25:34 -06:00
|
|
|
|
|
|
|
here = start = ep->start;
|
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
if (B.cylindersize && start % B.cylindersize) {
|
|
|
|
/* This is BAD */
|
|
|
|
if (DOS_extended) {
|
|
|
|
here = start -= (start % B.cylindersize);
|
2006-12-06 17:26:16 -06:00
|
|
|
do_warn(_("Warning: shifted start of the extd partition "
|
2006-12-06 17:25:48 -06:00
|
|
|
"from %ld to %ld\n"
|
|
|
|
"(For listing purposes only. "
|
|
|
|
"Do not change its contents.)\n"),
|
2006-12-06 17:25:43 -06:00
|
|
|
ep->start, start);
|
|
|
|
} else {
|
2006-12-06 17:26:16 -06:00
|
|
|
do_warn(_("Warning: extended partition does not start at a "
|
2006-12-06 17:25:48 -06:00
|
|
|
"cylinder boundary.\n"
|
|
|
|
"DOS and Linux will interpret the contents differently.\n"));
|
2006-12-06 17:25:43 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:34 -06:00
|
|
|
while (moretodo) {
|
|
|
|
moretodo = 0;
|
|
|
|
|
|
|
|
if (!(s = get_sector(dev, fd, here)))
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (!msdos_signature(s))
|
|
|
|
break;
|
|
|
|
|
|
|
|
cp = s->data + 0x1be;
|
|
|
|
|
2009-10-15 18:15:19 -05:00
|
|
|
if (pno+4 >= ARRAY_SIZE(z->partitions)) {
|
2006-12-06 17:26:16 -06:00
|
|
|
do_warn(_("too many partitions - ignoring those past nr (%d)\n"),
|
2006-12-06 17:25:34 -06:00
|
|
|
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)) {
|
2006-12-06 17:25:39 -06:00
|
|
|
partitions[pno].start = start + p.start_sect;
|
2006-12-06 17:25:34 -06:00
|
|
|
if (next)
|
2006-12-06 17:26:16 -06:00
|
|
|
do_warn(_("tree of partitions?\n"));
|
2006-12-06 17:25:39 -06:00
|
|
|
else
|
|
|
|
next = partitions[pno].start; /* follow `upper' branch */
|
2006-12-06 17:25:34 -06:00
|
|
|
moretodo = 1;
|
|
|
|
} else {
|
|
|
|
partitions[pno].start = here + p.start_sect;
|
|
|
|
}
|
|
|
|
partitions[pno].size = p.nr_sects;
|
2006-12-06 17:25:35 -06:00
|
|
|
partitions[pno].ptype = DOS_TYPE;
|
|
|
|
partitions[pno].p = p;
|
|
|
|
pno++;
|
2006-12-06 17:25:53 -06:00
|
|
|
}
|
2006-12-06 17:25:34 -06:00
|
|
|
here = next;
|
|
|
|
}
|
|
|
|
|
|
|
|
z->partno = pno;
|
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:35 -06:00
|
|
|
#define BSD_DISKMAGIC (0x82564557UL)
|
2006-12-06 17:25:58 -06:00
|
|
|
#define BSD_MAXPARTITIONS 16
|
2006-12-06 17:25:53 -06:00
|
|
|
#define BSD_FS_UNUSED 0
|
2006-12-06 17:25:35 -06:00
|
|
|
typedef unsigned char u8;
|
|
|
|
typedef unsigned short u16;
|
|
|
|
typedef unsigned int u32;
|
|
|
|
struct bsd_disklabel {
|
|
|
|
u32 d_magic;
|
|
|
|
char d_junk1[4];
|
2006-12-06 17:25:53 -06:00
|
|
|
char d_typename[16];
|
|
|
|
char d_packname[16];
|
2006-12-06 17:25:35 -06:00
|
|
|
char d_junk2[92];
|
2006-12-06 17:25:53 -06:00
|
|
|
u32 d_magic2;
|
2006-12-06 17:25:35 -06:00
|
|
|
char d_junk3[2];
|
2006-12-06 17:25:53 -06:00
|
|
|
u16 d_npartitions; /* number of partitions in following */
|
2006-12-06 17:25:35 -06:00
|
|
|
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]);
|
2011-06-06 13:39:17 -05:00
|
|
|
size_t pno = z->partno;
|
2006-12-06 17:25:35 -06:00
|
|
|
|
|
|
|
if (!(s = get_sector(dev,fd,start+1)))
|
|
|
|
return;
|
|
|
|
l = (struct bsd_disklabel *) (s->data);
|
2006-12-06 17:25:58 -06:00
|
|
|
if (l->d_magic != BSD_DISKMAGIC || l->d_magic2 != BSD_DISKMAGIC)
|
2006-12-06 17:25:35 -06:00
|
|
|
return;
|
|
|
|
|
|
|
|
bp = bp0 = &l->d_partitions[0];
|
2006-12-06 17:25:58 -06:00
|
|
|
while (bp - bp0 < BSD_MAXPARTITIONS && bp - bp0 < l->d_npartitions) {
|
2009-10-15 18:15:19 -05:00
|
|
|
if (pno+1 >= ARRAY_SIZE(z->partitions)) {
|
2006-12-06 17:26:16 -06:00
|
|
|
do_warn(_("too many partitions - ignoring those "
|
2006-12-06 17:25:39 -06:00
|
|
|
"past nr (%d)\n"), pno-1);
|
2006-12-06 17:25:35 -06:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:34 -06:00
|
|
|
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;
|
2008-04-21 20:11:48 -05:00
|
|
|
int bsd_later = 1;
|
|
|
|
#ifdef __linux__
|
|
|
|
bsd_later = (get_linux_version() >= KERNEL_VERSION(2,3,40));
|
|
|
|
#endif
|
2006-12-06 17:25:34 -06:00
|
|
|
|
|
|
|
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) {
|
2006-12-06 17:26:16 -06:00
|
|
|
do_warn(_("detected Disk Manager - unable to handle that\n"));
|
2006-12-06 17:25:34 -06:00
|
|
|
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))) {
|
2006-12-06 17:26:16 -06:00
|
|
|
do_warn(_("DM6 signature found - giving up\n"));
|
2006-12-06 17:25:34 -06:00
|
|
|
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;
|
|
|
|
|
2006-12-06 17:25:35 -06:00
|
|
|
for (i=0; i<4; i++) {
|
2006-12-06 17:25:34 -06:00
|
|
|
if (is_extended(partitions[i].p.sys_type)) {
|
|
|
|
if (!partitions[i].size) {
|
2006-12-06 17:26:16 -06:00
|
|
|
do_warn(_("strange..., an extended partition of size 0?\n"));
|
2006-12-06 17:25:34 -06:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
extended_partition(dev, fd, &partitions[i], z);
|
|
|
|
}
|
2006-12-06 17:25:43 -06:00
|
|
|
if (!bsd_later && is_bsd(partitions[i].p.sys_type)) {
|
2006-12-06 17:25:35 -06:00
|
|
|
if (!partitions[i].size) {
|
2006-12-06 17:26:16 -06:00
|
|
|
do_warn(_("strange..., a BSD partition of size 0?\n"));
|
2006-12-06 17:25:35 -06:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
bsd_partition(dev, fd, &partitions[i], z);
|
|
|
|
}
|
|
|
|
}
|
2006-12-06 17:25:43 -06:00
|
|
|
|
|
|
|
if (bsd_later) {
|
|
|
|
for (i=0; i<4; i++) {
|
|
|
|
if (is_bsd(partitions[i].p.sys_type)) {
|
|
|
|
if (!partitions[i].size) {
|
2006-12-06 17:26:16 -06:00
|
|
|
do_warn(_("strange..., a BSD partition of size 0?\n"));
|
2006-12-06 17:25:43 -06:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
bsd_partition(dev, fd, &partitions[i], z);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2008-09-16 06:08:12 -05:00
|
|
|
|
2006-12-06 17:25:34 -06:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2011-05-29 11:40:29 -05:00
|
|
|
osf_partition(char *dev __attribute__ ((__unused__)),
|
|
|
|
int fd __attribute__ ((__unused__)),
|
|
|
|
unsigned long start __attribute__ ((__unused__)),
|
|
|
|
struct disk_desc *z __attribute__ ((__unused__)))
|
|
|
|
{
|
2006-12-06 17:25:34 -06:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:35 -06:00
|
|
|
static int
|
2011-05-29 11:40:29 -05:00
|
|
|
sun_partition(char *dev __attribute__ ((__unused__)),
|
|
|
|
int fd __attribute__ ((__unused__)),
|
|
|
|
unsigned long start __attribute__ ((__unused__)),
|
|
|
|
struct disk_desc *z __attribute__ ((__unused__)))
|
|
|
|
{
|
2006-12-06 17:25:35 -06:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2011-05-29 11:40:29 -05:00
|
|
|
amiga_partition(char *dev __attribute__ ((__unused__)),
|
|
|
|
int fd __attribute__ ((__unused__)),
|
|
|
|
unsigned long start __attribute__ ((__unused__)),
|
|
|
|
struct disk_desc *z __attribute__ ((__unused__)))
|
|
|
|
{
|
2006-12-06 17:25:35 -06:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
static void
|
2006-12-06 17:25:34 -06:00
|
|
|
get_partitions(char *dev, int fd, struct disk_desc *z) {
|
|
|
|
z->partno = 0;
|
|
|
|
|
2006-12-06 17:25:35 -06:00
|
|
|
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)) {
|
2006-12-06 17:26:16 -06:00
|
|
|
do_warn(_(" %s: unrecognized partition table type\n"), dev);
|
2006-12-06 17:25:34 -06:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
static int
|
2006-12-06 17:25:34 -06:00
|
|
|
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) {
|
2006-12-06 17:26:16 -06:00
|
|
|
do_warn(_("-n flag was given: Nothing changed\n"));
|
2006-12-06 17:25:34 -06:00
|
|
|
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;
|
2006-12-06 17:26:12 -06:00
|
|
|
if (p->ptype == DOS_TYPE) {
|
|
|
|
copy_from_part(&(p->p), s->data + p->offset);
|
|
|
|
s->data[510] = 0x55;
|
2011-05-30 15:19:53 -05:00
|
|
|
s->data[511] = (unsigned char) 0xaa;
|
2006-12-06 17:26:12 -06:00
|
|
|
}
|
2006-12-06 17:25:34 -06:00
|
|
|
}
|
|
|
|
if (save_sector_file) {
|
|
|
|
if (!save_sectors(dev, fd)) {
|
2006-12-06 17:25:39 -06:00
|
|
|
fatal(_("Failed saving the old sectors - aborting\n"));
|
2006-12-06 17:25:34 -06:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!write_sectors(dev, fd)) {
|
2006-12-06 17:25:39 -06:00
|
|
|
error(_("Failed writing the partition on %s\n"), dev);
|
2006-12-06 17:25:34 -06:00
|
|
|
return 0;
|
|
|
|
}
|
2010-02-18 14:39:22 -06:00
|
|
|
if (fsync(fd)) {
|
|
|
|
perror(dev);
|
|
|
|
error(_("Failed writing the partition on %s\n"), dev);
|
|
|
|
return 0;
|
|
|
|
}
|
2006-12-06 17:25:34 -06:00
|
|
|
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.
|
|
|
|
*/
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
static int
|
2007-10-15 19:38:57 -05:00
|
|
|
read_stdin(char **fields, char *line, int fieldssize, int linesize) {
|
|
|
|
char *lp, *ip;
|
2006-12-06 17:25:34 -06:00
|
|
|
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 */
|
2006-12-06 17:26:54 -06:00
|
|
|
lp = fgets(line+2, linesize-2, stdin);
|
2006-12-06 17:25:34 -06:00
|
|
|
if (lp == NULL) {
|
|
|
|
eof = 1;
|
|
|
|
return RD_EOF;
|
|
|
|
}
|
2009-08-17 00:27:39 -05:00
|
|
|
if (!(lp = strchr(lp, '\n')))
|
2006-12-06 17:25:39 -06:00
|
|
|
fatal(_("long or incomplete input line - quitting\n"));
|
2006-12-06 17:25:34 -06:00
|
|
|
*lp = 0;
|
|
|
|
|
|
|
|
/* remove comments, if any */
|
2009-08-17 00:27:39 -05:00
|
|
|
if ((lp = strchr(line+2, '#')) != 0)
|
2006-12-06 17:25:34 -06:00
|
|
|
*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 */
|
2009-08-17 00:27:39 -05:00
|
|
|
if ((ip = strchr(line+2, ':')) != 0) {
|
2006-12-06 17:25:34 -06:00
|
|
|
struct dumpfld *d;
|
|
|
|
|
|
|
|
nxtfld:
|
|
|
|
ip++;
|
|
|
|
while(isspace(*ip))
|
|
|
|
ip++;
|
|
|
|
if (*ip == 0)
|
|
|
|
return fno;
|
2011-06-06 13:39:17 -05:00
|
|
|
for(d = dumpflds; (size_t) (d - dumpflds) < ARRAY_SIZE(dumpflds); d++) {
|
2006-12-06 17:26:16 -06:00
|
|
|
if (!strncmp(ip, d->fldname, strlen(d->fldname))) {
|
2006-12-06 17:25:34 -06:00
|
|
|
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
|
2006-12-06 17:25:39 -06:00
|
|
|
fatal(_("input error: `=' expected after %s field\n"),
|
2006-12-06 17:25:34 -06:00
|
|
|
d->fldname);
|
|
|
|
if (fno <= d->fldno)
|
|
|
|
fno = d->fldno + 1;
|
2006-12-06 17:26:16 -06:00
|
|
|
if (*ip == 0)
|
2006-12-06 17:25:34 -06:00
|
|
|
return fno;
|
2006-12-06 17:26:16 -06:00
|
|
|
if (*ip != ',' && *ip != ';')
|
2006-12-06 17:25:39 -06:00
|
|
|
fatal(_("input error: unexpected character %c after %s field\n"),
|
2006-12-06 17:25:34 -06:00
|
|
|
*ip, d->fldname);
|
|
|
|
*ip = 0;
|
|
|
|
goto nxtfld;
|
|
|
|
}
|
|
|
|
}
|
2006-12-06 17:25:39 -06:00
|
|
|
fatal(_("unrecognized input: %s\n"), ip);
|
2006-12-06 17:25:34 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
/* 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 */
|
2006-12-06 17:25:48 -06:00
|
|
|
/* a sign gives an offset from the default */
|
2006-12-06 17:25:43 -06:00
|
|
|
static int
|
2006-12-06 17:25:34 -06:00
|
|
|
get_ul(char *u, unsigned long *up, unsigned long def, int base) {
|
|
|
|
char *nu;
|
2006-12-06 17:25:48 -06:00
|
|
|
int sign = 0;
|
|
|
|
unsigned long val;
|
2006-12-06 17:25:34 -06:00
|
|
|
|
2006-12-06 17:25:48 -06:00
|
|
|
if (*u == '+') {
|
|
|
|
sign = 1;
|
|
|
|
u++;
|
|
|
|
} else if (*u == '-') {
|
|
|
|
sign = -1;
|
|
|
|
u++;
|
|
|
|
}
|
2006-12-06 17:25:34 -06:00
|
|
|
if (*u) {
|
|
|
|
errno = 0;
|
2006-12-06 17:25:48 -06:00
|
|
|
val = strtoul(u, &nu, base);
|
2006-12-06 17:25:34 -06:00
|
|
|
if (errno == ERANGE) {
|
2006-12-06 17:26:16 -06:00
|
|
|
do_warn(_("number too big\n"));
|
2006-12-06 17:25:34 -06:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (*nu) {
|
2006-12-06 17:26:16 -06:00
|
|
|
do_warn(_("trailing junk after number\n"));
|
2006-12-06 17:25:34 -06:00
|
|
|
return -1;
|
|
|
|
}
|
2006-12-06 17:25:48 -06:00
|
|
|
if (sign == 1)
|
|
|
|
val = def + val;
|
|
|
|
else if (sign == -1)
|
|
|
|
val = def - val;
|
|
|
|
*up = val;
|
2006-12-06 17:25:34 -06:00
|
|
|
} 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).
|
|
|
|
*/
|
|
|
|
int partitions_in_order = 0;
|
|
|
|
int all_logicals_inside_outermost_extended = 1;
|
|
|
|
enum { NESTED, CHAINED, ONESECTOR } boxes = NESTED;
|
|
|
|
|
|
|
|
/* find the default value for <start> - assuming entire units */
|
2006-12-06 17:25:43 -06:00
|
|
|
static unsigned long
|
2006-12-06 17:25:34 -06:00
|
|
|
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 */
|
2006-12-06 17:25:43 -06:00
|
|
|
static unsigned long
|
2006-12-06 17:25:34 -06:00
|
|
|
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);
|
2008-09-16 06:08:12 -05:00
|
|
|
|
2006-12-06 17:25:34 -06:00
|
|
|
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 */
|
2006-12-06 17:26:19 -06:00
|
|
|
/* return 0 on failure */
|
2006-12-06 17:25:34 -06:00
|
|
|
/* ep is 0 or points to surrounding extended partition */
|
2006-12-06 17:25:43 -06:00
|
|
|
static int
|
2006-12-06 17:25:34 -06:00
|
|
|
compute_start_sect(struct part_desc *p, struct part_desc *ep) {
|
|
|
|
unsigned long base;
|
2006-12-06 17:25:39 -06:00
|
|
|
int inc = (DOS && B.sectors) ? B.sectors : 1;
|
2006-12-06 17:25:34 -06:00
|
|
|
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;
|
2006-12-06 17:26:19 -06:00
|
|
|
|
2006-12-06 17:25:34 -06:00
|
|
|
if (delta < 0) {
|
2007-08-20 07:12:53 -05:00
|
|
|
unsigned long old_size = p->size;
|
2006-12-06 17:25:34 -06:00
|
|
|
p->start -= delta;
|
|
|
|
p->size += delta;
|
|
|
|
if (is_extended(p->p.sys_type) && boxes == ONESECTOR)
|
|
|
|
p->size = inc;
|
2011-06-06 13:39:17 -05:00
|
|
|
else if ((ssize_t) old_size <= (ssize_t) -delta) {
|
2011-01-31 11:58:26 -06:00
|
|
|
my_warn(_("no room for partition descriptor\n"));
|
2006-12-06 17:25:34 -06:00
|
|
|
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;
|
2006-12-06 17:25:39 -06:00
|
|
|
p->p.begin_chs = ulong_to_chs(p->start,B);
|
|
|
|
p->p.end_chs = ulong_to_chs(p->start + p->size - 1,B);
|
2006-12-06 17:25:34 -06:00
|
|
|
}
|
|
|
|
p->p.nr_sects = p->size;
|
|
|
|
return 1;
|
2008-09-16 06:08:12 -05:00
|
|
|
}
|
2006-12-06 17:25:34 -06:00
|
|
|
|
|
|
|
/* build the extended partition surrounding a given logical partition */
|
2006-12-06 17:25:43 -06:00
|
|
|
static int
|
2006-12-06 17:25:34 -06:00
|
|
|
build_surrounding_extended(struct part_desc *p, struct part_desc *ep,
|
|
|
|
struct disk_desc *z) {
|
2006-12-06 17:25:39 -06:00
|
|
|
int inc = (DOS && B.sectors) ? B.sectors : 1;
|
2006-12-06 17:25:34 -06:00
|
|
|
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) {
|
2011-01-31 11:58:26 -06:00
|
|
|
my_warn(_("cannot build surrounding extended partition\n"));
|
2006-12-06 17:25:34 -06:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
ep->start = p->start;
|
2006-12-06 17:26:16 -06:00
|
|
|
if (boxes == CHAINED)
|
2006-12-06 17:25:34 -06:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
static int
|
2006-12-06 17:25:34 -06:00
|
|
|
read_line(int pno, struct part_desc *ep, char *dev, int interactive,
|
|
|
|
struct disk_desc *z) {
|
2007-10-15 19:38:57 -05:00
|
|
|
char line[1000];
|
|
|
|
char *fields[11];
|
2006-12-06 17:25:34 -06:00
|
|
|
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))
|
2011-01-31 11:58:26 -06:00
|
|
|
my_warn("\n");
|
|
|
|
my_warn("%s:", partname(dev, lpno, 10));
|
2006-12-06 17:25:34 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
/* read input line - skip blank lines when reading from a file */
|
|
|
|
do {
|
2009-10-15 18:15:19 -05:00
|
|
|
fno = read_stdin(fields, line, ARRAY_SIZE(fields), ARRAY_SIZE(line));
|
2006-12-06 17:25:34 -06:00
|
|
|
} while(fno == RD_CMD || (fno == 0 && !interactive));
|
|
|
|
if (fno == RD_EOF) {
|
|
|
|
return -1;
|
|
|
|
} else if (fno > 10 && *(fields[10]) != 0) {
|
2006-12-06 17:26:16 -06:00
|
|
|
do_warn(_("too many input fields\n"));
|
2006-12-06 17:25:34 -06:00
|
|
|
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;
|
2006-12-06 17:25:39 -06:00
|
|
|
if (B.cylindersize && specified_format == F_MEGABYTE)
|
2006-12-06 17:25:34 -06:00
|
|
|
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 */
|
2011-01-31 11:58:26 -06:00
|
|
|
my_warn(_("No room for more\n"));
|
2006-12-06 17:25:34 -06:00
|
|
|
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;
|
2006-12-06 17:26:16 -06:00
|
|
|
else if (!strcmp(fields[2], "L"))
|
2006-12-06 17:25:34 -06:00
|
|
|
ul = LINUX_NATIVE;
|
2006-12-06 17:26:16 -06:00
|
|
|
else if (!strcmp(fields[2], "S"))
|
2006-12-06 17:25:34 -06:00
|
|
|
ul = LINUX_SWAP;
|
2006-12-06 17:26:16 -06:00
|
|
|
else if (!strcmp(fields[2], "E"))
|
2006-12-06 17:25:34 -06:00
|
|
|
ul = EXTENDED_PARTITION;
|
2006-12-06 17:26:16 -06:00
|
|
|
else if (!strcmp(fields[2], "X"))
|
2006-12-06 17:25:34 -06:00
|
|
|
ul = LINUX_EXTENDED;
|
|
|
|
else if (get_ul(fields[2], &ul, LINUX_NATIVE, 16))
|
|
|
|
return 0;
|
|
|
|
if (ul > 255) {
|
2011-01-31 11:58:26 -06:00
|
|
|
my_warn(_("Illegal type\n"));
|
2006-12-06 17:25:34 -06:00
|
|
|
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;
|
sfdisk: add option to use maximum partition size
Based on patch from Alex Bligh <alex@alex.org.uk>, Alex wrote:
By default, omitting a size parameter means that the maximum sized partition
is used. However, this option is not available in conjunction with the -N
flag, as under such circumstances the default is the current size of the
partition. This patch allows a size to be specified as "+" in which case
the maximum sized partition is used, irrespective of the setting of the -N
flag.
This allows partitions to be programatically resized to their maximum size,
by (for instance):
echo ",+," | sfdisk -N1 /dev/sda
This is non-trivial to do without the patch, as -N makes the default size
the existing size. As there is (without this patch) no way of reading the
maximum size, the only option is to delete the partition and recreate it.
This is undesirable for a number of reasons (e.g. errors between delete
and recreate).
Addresses: https://bugs.launchpad.net/ubuntu/+source/util-linux/+bug/686124
Signed-off-by: Karel Zak <kzak@redhat.com>
2010-12-09 16:13:58 -06:00
|
|
|
else if (!strcmp(fields[1], "+"))
|
|
|
|
p.size = ml1;
|
2006-12-06 17:25:34 -06:00
|
|
|
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) {
|
2011-01-31 11:58:26 -06:00
|
|
|
my_warn(_("Warning: given size (%lu) exceeds max allowable size (%lu)\n"),
|
2006-12-06 17:25:43 -06:00
|
|
|
(p.size + unitsize(0) - 1) / unitsize(0), ml1 / unitsize(0));
|
2006-12-06 17:25:34 -06:00
|
|
|
if (!force)
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if (p.size == 0 && pno >= 4 && (fno < 2 || !*(fields[1]))) {
|
2011-01-31 11:58:26 -06:00
|
|
|
my_warn(_("Warning: empty partition\n"));
|
2006-12-06 17:25:34 -06:00
|
|
|
if (!force)
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
p.p.nr_sects = p.size;
|
|
|
|
|
|
|
|
if (p.size == 0 && !orig) {
|
2006-12-06 17:26:16 -06:00
|
|
|
if (fno < 1 || !*(fields[0]))
|
2006-12-06 17:25:34 -06:00
|
|
|
p.start = 0;
|
2006-12-06 17:26:16 -06:00
|
|
|
if (fno < 3 || !*(fields[2]))
|
2006-12-06 17:25:34 -06:00
|
|
|
p.p.sys_type = EMPTY_PARTITION;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (p.start < ff1 && p.size > 0) {
|
2011-01-31 11:58:26 -06:00
|
|
|
my_warn(_("Warning: bad partition start (earliest %lu)\n"),
|
2006-12-06 17:25:34 -06:00
|
|
|
(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 {
|
2011-01-31 11:58:26 -06:00
|
|
|
my_warn(_("unrecognized bootable flag - choose - or *\n"));
|
2006-12-06 17:25:34 -06:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
p.p.bootable = ul;
|
|
|
|
|
|
|
|
if (ep && ep->p.sys_type == EMPTY_PARTITION) {
|
2006-12-06 17:26:16 -06:00
|
|
|
if (!build_surrounding_extended(&p, ep, z))
|
2006-12-06 17:25:34 -06:00
|
|
|
return 0;
|
|
|
|
} else
|
2006-12-06 17:26:16 -06:00
|
|
|
if (!compute_start_sect(&p, ep))
|
2006-12-06 17:25:34 -06:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
{ longchs aa = chs_to_longchs(p.p.begin_chs), bb;
|
|
|
|
|
|
|
|
if (fno < 5) {
|
|
|
|
bb = aa;
|
|
|
|
} else if (fno < 7) {
|
2011-01-31 11:58:26 -06:00
|
|
|
my_warn(_("partial c,h,s specification?\n"));
|
2006-12-06 17:25:34 -06:00
|
|
|
return 0;
|
2006-12-06 17:26:16 -06:00
|
|
|
} else if (get_ul(fields[4], &bb.c, aa.c, 0) ||
|
2006-12-06 17:25:34 -06:00
|
|
|
get_ul(fields[5], &bb.h, aa.h, 0) ||
|
|
|
|
get_ul(fields[6], &bb.s, aa.s, 0))
|
|
|
|
return 0;
|
2006-12-06 17:25:39 -06:00
|
|
|
p.p.begin_chs = longchs_to_chs(bb,B);
|
2006-12-06 17:25:34 -06:00
|
|
|
}
|
|
|
|
{ longchs aa = chs_to_longchs(p.p.end_chs), bb;
|
|
|
|
|
|
|
|
if (fno < 8) {
|
|
|
|
bb = aa;
|
|
|
|
} else if (fno < 10) {
|
2011-01-31 11:58:26 -06:00
|
|
|
my_warn(_("partial c,h,s specification?\n"));
|
2006-12-06 17:25:34 -06:00
|
|
|
return 0;
|
2006-12-06 17:26:16 -06:00
|
|
|
} else if (get_ul(fields[7], &bb.c, aa.c, 0) ||
|
2006-12-06 17:25:34 -06:00
|
|
|
get_ul(fields[8], &bb.h, aa.h, 0) ||
|
|
|
|
get_ul(fields[9], &bb.s, aa.s, 0))
|
|
|
|
return 0;
|
2006-12-06 17:25:39 -06:00
|
|
|
p.p.end_chs = longchs_to_chs(bb, B);
|
2006-12-06 17:25:34 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
if (pno > 3 && p.size && show_extended && p.p.sys_type != EMPTY_PARTITION
|
|
|
|
&& (is_extended(p.p.sys_type) != (pct == 1))) {
|
2011-01-31 11:58:26 -06:00
|
|
|
my_warn(_("Extended partition not where expected\n"));
|
2006-12-06 17:25:34 -06:00
|
|
|
if (!force)
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
z->partitions[pno] = p;
|
|
|
|
if (pno >= z->partno)
|
|
|
|
z->partno += 4; /* reqd for out_partition() */
|
|
|
|
|
|
|
|
if (interactive)
|
2006-12-06 17:25:39 -06:00
|
|
|
out_partition(dev, 0, &(z->partitions[pno]), z, B);
|
2006-12-06 17:25:34 -06:00
|
|
|
|
|
|
|
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 */
|
2006-12-06 17:25:43 -06:00
|
|
|
static int
|
2006-12-06 17:25:34 -06:00
|
|
|
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)
|
2006-12-06 17:25:39 -06:00
|
|
|
fatal(_("bad input\n"));
|
2006-12-06 17:25:34 -06:00
|
|
|
if (i < 0) {
|
|
|
|
p->ep = ep;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret:
|
|
|
|
p->ep = ep;
|
|
|
|
if (pno >= z->partno)
|
|
|
|
z->partno += 4;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
static void
|
2006-12-06 17:25:34 -06:00
|
|
|
read_partition_chain(char *dev, int interactive, struct part_desc *ep,
|
|
|
|
struct disk_desc *z) {
|
2011-06-06 13:39:17 -05:00
|
|
|
int i;
|
|
|
|
size_t base;
|
2006-12-06 17:25:34 -06:00
|
|
|
|
|
|
|
eob = 0;
|
|
|
|
while (1) {
|
|
|
|
base = z->partno;
|
2009-10-15 18:15:19 -05:00
|
|
|
if (base+4 > ARRAY_SIZE(z->partitions)) {
|
2006-12-06 17:26:16 -06:00
|
|
|
do_warn(_("too many partitions\n"));
|
2006-12-06 17:25:34 -06:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
static void
|
2006-12-06 17:25:34 -06:00
|
|
|
read_input(char *dev, int interactive, struct disk_desc *z) {
|
2011-06-06 13:39:17 -05:00
|
|
|
size_t i;
|
2006-12-06 17:25:34 -06:00
|
|
|
struct part_desc *partitions = &(z->partitions[0]), *ep;
|
|
|
|
|
2009-10-15 18:15:19 -05:00
|
|
|
for (i=0; i < ARRAY_SIZE(z->partitions); i++)
|
2006-12-06 17:25:34 -06:00
|
|
|
partitions[i] = zero_part_desc;
|
|
|
|
z->partno = 0;
|
|
|
|
|
|
|
|
if (interactive)
|
2011-01-31 11:58:26 -06:00
|
|
|
my_warn(_("Input in the following format; absent fields get a default value.\n"
|
2006-12-06 17:25:39 -06:00
|
|
|
"<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"));
|
2006-12-06 17:25:34 -06:00
|
|
|
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
|
|
|
|
*/
|
2011-05-29 13:26:22 -05:00
|
|
|
static void usage(FILE * out)
|
|
|
|
{
|
2006-12-06 17:25:34 -06:00
|
|
|
|
2011-05-29 13:26:22 -05:00
|
|
|
fprintf(out, _("\nUsage:\n"
|
|
|
|
" %s [options] device [...]\n"),
|
|
|
|
program_invocation_short_name);
|
|
|
|
fprintf(out, _("Device is something like /dev/hda or /dev/sda\n"));
|
|
|
|
|
|
|
|
fprintf(out, _("\nOptions:\n"
|
|
|
|
" -s, --show-size list size of a partition\n"
|
|
|
|
" -c, --id change or print partition Id\n"
|
2011-05-29 14:35:15 -05:00
|
|
|
" --change-id change Id\n"
|
|
|
|
" --print-id print Id\n"
|
2011-05-29 13:26:22 -05:00
|
|
|
" -l, --list list partitions of each device\n"
|
|
|
|
" -d, --dump idem, but in a format suitable for later input\n"
|
|
|
|
" -i, --increment number cylinders etc. from 1 instead of from 0\n"
|
|
|
|
" -u, --unit=[SBCM] units in sectors, blocks, cylinders or MB\n"
|
2011-05-29 14:35:15 -05:00
|
|
|
" -1, --one-only reserved option that does nothing currently\n"
|
2011-05-29 13:26:22 -05:00
|
|
|
" -T, --list-types list the known partition types\n"
|
|
|
|
" -D, --DOS for DOS-compatibility: waste a little space\n"
|
2011-05-29 14:35:15 -05:00
|
|
|
" -E, --DOS-extended DOS extended partition compatibility\n"
|
2011-05-29 13:26:22 -05:00
|
|
|
" -R, --re-read make kernel reread partition table\n"
|
|
|
|
" -N=NUM change only the partition with number NUM\n"
|
|
|
|
" -n do not actually write to disk\n"
|
|
|
|
" -O FILE save the sectors that will be overwritten to file\n"
|
|
|
|
" -I FILE restore sectors from file\n"
|
2011-05-29 14:35:15 -05:00
|
|
|
" -V, --verify check that listed partition is reasonable\n"
|
2011-05-29 13:26:22 -05:00
|
|
|
" -v, --version print version\n"
|
|
|
|
" -h, --help print this message\n"));
|
|
|
|
|
|
|
|
fprintf(out, _("\nDangerous options:\n"
|
|
|
|
" -f, --force disable all consistency checking\n"
|
|
|
|
" -g, --show-geometry print the kernel's idea of the geometry\n"
|
2011-05-29 14:35:15 -05:00
|
|
|
" -A, --activate[=device] activate bootable flag\n"
|
2011-05-29 13:26:22 -05:00
|
|
|
" -G, --show-pt-geometry print geometry guessed from the partition table\n"
|
2011-05-29 14:35:15 -05:00
|
|
|
" -U, --unhide[=device] set partition unhidden\n"
|
|
|
|
" --no-reread skip partition re-read at boot\n"
|
2011-05-29 13:26:22 -05:00
|
|
|
" -x, --show-extended also list extended partitions on output\n"
|
|
|
|
" or expect descriptors for them on input\n"
|
2011-05-29 14:35:15 -05:00
|
|
|
" --leave-last do not allocate the last cylinder\n"
|
|
|
|
" --IBM same as --leave-last\n"
|
|
|
|
" --in-order partitions are in order\n"
|
|
|
|
" --not-in-order partitions are not in order\n"
|
|
|
|
" --inside-order all logicals inside outermost extended\n"
|
|
|
|
" --not-inside-order not all logicals inside outermost extended\n"
|
|
|
|
" --nested every partition is disjoint from all others\n"
|
|
|
|
" --chained like nested, but extended partitions may lie outside\n"
|
|
|
|
" --onesector partitions are mutually disjoint\n"
|
2011-05-29 13:26:22 -05:00
|
|
|
" -L, --Linux do not complain about things irrelevant for Linux\n"
|
|
|
|
" -q, --quiet suppress warning messages\n"
|
|
|
|
"\n Override the detected geometry using:\n"
|
|
|
|
" -C, --cylinders=NUM set the number of cylinders to use\n"
|
|
|
|
" -H, --heads=NUM set the number of heads to use\n"
|
|
|
|
" -S, --sectors=NUM set the number of sectors to use\n\n"));
|
|
|
|
|
|
|
|
exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
|
2006-12-06 17:25:34 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
activate_usage(char *progn) {
|
2006-12-06 17:25:39 -06:00
|
|
|
puts (_("Usage:"));
|
|
|
|
printf(_("%s device list active partitions on device\n"), progn);
|
|
|
|
printf(_("%s device n1 n2 ... activate partitions n1 ..., inactivate the rest\n"), progn);
|
|
|
|
printf(_("%s -An device activate partition n, inactivate the other ones\n"), PROGNAME);
|
2006-12-06 17:25:34 -06:00
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2011-05-29 11:40:29 -05:00
|
|
|
unhide_usage(char *progn __attribute__ ((__unused__))) {
|
2006-12-06 17:25:34 -06:00
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
2011-05-29 13:26:22 -05:00
|
|
|
static const char short_opts[] = "cdfghilnqsu:vx1A::C:DGH:I:LN:O:RS:TU::V";
|
2006-12-06 17:25:34 -06:00
|
|
|
|
|
|
|
#define PRINT_ID 0400
|
|
|
|
#define CHANGE_ID 01000
|
|
|
|
|
2011-05-29 14:35:15 -05:00
|
|
|
enum {
|
|
|
|
OPT_NO_REREAD = CHAR_MAX + 1,
|
|
|
|
OPT_LEAVE_LAST,
|
|
|
|
OPT_IN_ORDER,
|
|
|
|
OPT_NOT_IN_ORDER,
|
|
|
|
OPT_INSIDE_OUTER,
|
|
|
|
OPT_NOT_INSIDE_OUTER,
|
|
|
|
OPT_NESTED,
|
|
|
|
OPT_CHAINED,
|
|
|
|
OPT_ONESECTOR
|
|
|
|
};
|
|
|
|
|
2006-12-06 17:25:34 -06:00
|
|
|
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' },
|
2011-05-29 13:26:22 -05:00
|
|
|
{ "help", no_argument, NULL, 'h' },
|
2006-12-06 17:25:34 -06:00
|
|
|
{ "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' },
|
|
|
|
{ "one-only", no_argument, NULL, '1' },
|
|
|
|
{ "cylinders", required_argument, NULL, 'C' },
|
|
|
|
{ "heads", required_argument, NULL, 'H' },
|
|
|
|
{ "sectors", required_argument, NULL, 'S' },
|
2006-12-06 17:26:36 -06:00
|
|
|
{ "show-pt-geometry", no_argument, NULL, 'G' },
|
2006-12-06 17:25:34 -06:00
|
|
|
{ "activate", optional_argument, NULL, 'A' },
|
|
|
|
{ "DOS", no_argument, NULL, 'D' },
|
2006-12-06 17:25:43 -06:00
|
|
|
{ "DOS-extended", no_argument, NULL, 'E' },
|
2006-12-06 17:25:34 -06:00
|
|
|
{ "Linux", no_argument, NULL, 'L' },
|
|
|
|
{ "re-read", no_argument, NULL, 'R' },
|
|
|
|
{ "list-types", no_argument, NULL, 'T' },
|
|
|
|
{ "unhide", optional_argument, NULL, 'U' },
|
2011-05-29 14:35:15 -05:00
|
|
|
{ "no-reread", no_argument, NULL, OPT_NO_REREAD },
|
|
|
|
{ "IBM", no_argument, NULL, OPT_LEAVE_LAST },
|
|
|
|
{ "leave-last", no_argument, NULL, OPT_LEAVE_LAST },
|
|
|
|
/* dangerous flags - not all completely implemented */
|
|
|
|
{ "in-order", no_argument, NULL, OPT_IN_ORDER },
|
|
|
|
{ "not-in-order", no_argument, NULL, OPT_NOT_IN_ORDER },
|
|
|
|
{ "inside-outer", no_argument, NULL, OPT_INSIDE_OUTER },
|
|
|
|
{ "not-inside-outer", no_argument, NULL, OPT_NOT_INSIDE_OUTER },
|
|
|
|
{ "nested", no_argument, NULL, OPT_NESTED },
|
|
|
|
{ "chained", no_argument, NULL, OPT_CHAINED },
|
|
|
|
{ "onesector", no_argument, NULL, OPT_ONESECTOR },
|
2006-12-06 17:25:34 -06:00
|
|
|
{ NULL, 0, NULL, 0 }
|
|
|
|
};
|
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
static int
|
2006-12-06 17:25:48 -06:00
|
|
|
is_ide_cdrom_or_tape(char *device) {
|
2006-12-06 17:25:49 -06:00
|
|
|
FILE *procf;
|
|
|
|
char buf[100];
|
|
|
|
struct stat statbuf;
|
|
|
|
int is_ide = 0;
|
2006-12-06 17:25:35 -06:00
|
|
|
|
2006-12-06 17:25:49 -06:00
|
|
|
/* 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. It even happens that
|
|
|
|
the process hangs on the attempt to read a music CD.
|
|
|
|
So try to be careful. This only works since 2.1.73. */
|
2006-12-06 17:25:35 -06:00
|
|
|
|
2006-12-06 17:25:49 -06:00
|
|
|
if (strncmp("/dev/hd", device, 7))
|
|
|
|
return 0;
|
2006-12-06 17:25:35 -06:00
|
|
|
|
2006-12-06 17:25:49 -06:00
|
|
|
snprintf(buf, sizeof(buf), "/proc/ide/%s/media", device+5);
|
|
|
|
procf = fopen(buf, "r");
|
|
|
|
if (procf != NULL && fgets(buf, sizeof(buf), procf))
|
|
|
|
is_ide = (!strncmp(buf, "cdrom", 5) ||
|
|
|
|
!strncmp(buf, "tape", 4));
|
|
|
|
else
|
|
|
|
/* Now when this proc file does not exist, skip the
|
|
|
|
device when it is read-only. */
|
|
|
|
if (stat(device, &statbuf) == 0)
|
|
|
|
is_ide = ((statbuf.st_mode & 0222) == 0);
|
2006-12-06 17:25:35 -06:00
|
|
|
|
2006-12-06 17:25:49 -06:00
|
|
|
if (procf)
|
|
|
|
fclose(procf);
|
|
|
|
return is_ide;
|
2006-12-06 17:25:35 -06:00
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:53 -06:00
|
|
|
static char *
|
2007-10-21 22:25:39 -05:00
|
|
|
nextproc(FILE *procf) {
|
2009-04-29 07:33:52 -05:00
|
|
|
static char devname[256];
|
|
|
|
char line[1024], ptname[128];
|
|
|
|
int ma, mi;
|
|
|
|
unsigned long long sz;
|
2006-12-06 17:25:53 -06:00
|
|
|
|
|
|
|
if (procf == NULL)
|
|
|
|
return NULL;
|
|
|
|
while (fgets(line, sizeof(line), procf) != NULL) {
|
2009-04-29 07:33:52 -05:00
|
|
|
if (sscanf (line, " %d %d %llu %128[^\n ]",
|
2006-12-06 17:25:53 -06:00
|
|
|
&ma, &mi, &sz, ptname) != 4)
|
|
|
|
continue;
|
|
|
|
snprintf(devname, sizeof(devname), "/dev/%s", ptname);
|
2009-03-11 08:00:21 -05:00
|
|
|
if (!is_whole_disk(devname))
|
2006-12-06 17:26:18 -06:00
|
|
|
continue;
|
2010-12-16 18:28:59 -06:00
|
|
|
return canonicalize_path(devname);
|
2006-12-06 17:25:53 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
2007-10-21 22:25:39 -05:00
|
|
|
}
|
2006-12-06 17:25:53 -06:00
|
|
|
|
2007-05-31 07:31:51 -05:00
|
|
|
static void
|
|
|
|
gpt_warning(char *dev, int warn_only)
|
|
|
|
{
|
|
|
|
if (force)
|
|
|
|
warn_only = 1;
|
|
|
|
|
|
|
|
if (dev && gpt_probe_signature_devname(dev)) {
|
|
|
|
fflush(stdout);
|
|
|
|
fprintf(stderr, _("\nWARNING: GPT (GUID Partition Table) detected on '%s'! "
|
|
|
|
"The util sfdisk doesn't support GPT. Use GNU Parted.\n\n"), dev);
|
|
|
|
if (!warn_only) {
|
|
|
|
fprintf(stderr, _("Use the --force flag to overrule this check.\n"));
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
static void do_list(char *dev, int silent);
|
|
|
|
static void do_size(char *dev, int silent);
|
|
|
|
static void do_geom(char *dev, int silent);
|
2006-12-06 17:26:36 -06:00
|
|
|
static void do_pt_geom(char *dev, int silent);
|
2006-12-06 17:25:43 -06:00
|
|
|
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);
|
2006-12-06 17:25:34 -06:00
|
|
|
|
2006-12-06 17:26:18 -06:00
|
|
|
unsigned long long total_size;
|
2006-12-06 17:25:34 -06:00
|
|
|
|
|
|
|
int
|
|
|
|
main(int argc, char **argv) {
|
|
|
|
char *progn;
|
|
|
|
int c;
|
|
|
|
char *dev;
|
|
|
|
int opt_size = 0;
|
|
|
|
int opt_out_geom = 0;
|
2006-12-06 17:26:36 -06:00
|
|
|
int opt_out_pt_geom = 0;
|
2006-12-06 17:25:34 -06:00
|
|
|
int opt_reread = 0;
|
|
|
|
int activate = 0;
|
|
|
|
int do_id = 0;
|
|
|
|
int unhide = 0;
|
|
|
|
int fdisk = 0;
|
|
|
|
char *activatearg = 0;
|
|
|
|
char *unhidearg = 0;
|
|
|
|
|
2006-12-06 17:25:39 -06:00
|
|
|
setlocale(LC_ALL, "");
|
|
|
|
bindtextdomain(PACKAGE, LOCALEDIR);
|
|
|
|
textdomain(PACKAGE);
|
|
|
|
|
2006-12-06 17:25:34 -06:00
|
|
|
if (argc < 1)
|
2006-12-06 17:25:39 -06:00
|
|
|
fatal(_("no command?\n"));
|
2009-08-17 00:27:39 -05:00
|
|
|
if ((progn = strrchr(argv[0], '/')) == NULL)
|
2006-12-06 17:25:34 -06:00
|
|
|
progn = argv[0];
|
|
|
|
else
|
|
|
|
progn++;
|
|
|
|
if (!strcmp(progn, "activate"))
|
2006-12-06 17:25:37 -06:00
|
|
|
activate = 1; /* equivalent to `sfdisk -A' */
|
2006-12-06 17:25:34 -06:00
|
|
|
#if 0 /* not important enough to deserve a name */
|
|
|
|
else if (!strcmp(progn, "unhide"))
|
2006-12-06 17:25:37 -06:00
|
|
|
unhide = 1; /* equivalent to `sfdisk -U' */
|
2006-12-06 17:25:34 -06:00
|
|
|
#endif
|
|
|
|
else
|
|
|
|
fdisk = 1;
|
|
|
|
|
|
|
|
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;
|
2006-12-06 17:26:36 -06:00
|
|
|
case 'G':
|
|
|
|
opt_out_pt_geom = 1; break;
|
2006-12-06 17:25:34 -06:00
|
|
|
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':
|
2011-05-29 13:26:22 -05:00
|
|
|
printf(_("%s from %s\n"), program_invocation_short_name,
|
|
|
|
PACKAGE_STRING);
|
|
|
|
return EXIT_SUCCESS;
|
|
|
|
case 'h':
|
|
|
|
usage(stdout);
|
|
|
|
return EXIT_SUCCESS;
|
2006-12-06 17:25:34 -06:00
|
|
|
case 'x':
|
|
|
|
show_extended = 1; break;
|
|
|
|
case 'A':
|
|
|
|
activatearg = optarg;
|
|
|
|
activate = 1; break;
|
|
|
|
case 'C':
|
2006-12-06 17:25:39 -06:00
|
|
|
U.cylinders = atoi(optarg); break;
|
2006-12-06 17:25:34 -06:00
|
|
|
case 'D':
|
|
|
|
DOS = 1; break;
|
2006-12-06 17:25:43 -06:00
|
|
|
case 'E':
|
|
|
|
DOS_extended = 1; break;
|
2006-12-06 17:25:34 -06:00
|
|
|
case 'H':
|
2006-12-06 17:25:39 -06:00
|
|
|
U.heads = atoi(optarg); break;
|
2006-12-06 17:25:34 -06:00
|
|
|
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':
|
2006-12-06 17:25:39 -06:00
|
|
|
U.sectors = atoi(optarg); break;
|
2006-12-06 17:25:34 -06:00
|
|
|
case 'T':
|
|
|
|
list_types();
|
|
|
|
exit(0);
|
|
|
|
case 'U':
|
|
|
|
unhidearg = optarg;
|
|
|
|
unhide = 1; break;
|
|
|
|
case 'V':
|
|
|
|
verify = 1; break;
|
|
|
|
default:
|
2011-05-29 13:26:22 -05:00
|
|
|
usage(stderr); break;
|
2006-12-06 17:25:34 -06:00
|
|
|
|
2011-05-29 14:35:15 -05:00
|
|
|
/* dangerous flags */
|
|
|
|
case OPT_IN_ORDER:
|
2006-12-06 17:25:34 -06:00
|
|
|
partitions_in_order = 1; break;
|
2011-05-29 14:35:15 -05:00
|
|
|
case OPT_NOT_IN_ORDER:
|
2006-12-06 17:25:34 -06:00
|
|
|
partitions_in_order = 0; break;
|
2011-05-29 14:35:15 -05:00
|
|
|
case OPT_INSIDE_OUTER:
|
2006-12-06 17:25:34 -06:00
|
|
|
all_logicals_inside_outermost_extended = 1; break;
|
2011-05-29 14:35:15 -05:00
|
|
|
case OPT_NOT_INSIDE_OUTER:
|
2006-12-06 17:25:34 -06:00
|
|
|
all_logicals_inside_outermost_extended = 0; break;
|
2011-05-29 14:35:15 -05:00
|
|
|
case OPT_NESTED:
|
2006-12-06 17:25:34 -06:00
|
|
|
boxes = NESTED; break;
|
2011-05-29 14:35:15 -05:00
|
|
|
case OPT_CHAINED:
|
2006-12-06 17:25:34 -06:00
|
|
|
boxes = CHAINED; break;
|
2011-05-29 14:35:15 -05:00
|
|
|
case OPT_ONESECTOR:
|
2006-12-06 17:25:34 -06:00
|
|
|
boxes = ONESECTOR; break;
|
|
|
|
|
|
|
|
/* more flags */
|
2011-05-29 14:35:15 -05:00
|
|
|
case OPT_NO_REREAD:
|
2006-12-06 17:25:34 -06:00
|
|
|
no_reread = 1; break;
|
2011-05-29 14:35:15 -05:00
|
|
|
case OPT_LEAVE_LAST:
|
2006-12-06 17:25:34 -06:00
|
|
|
leave_last = 1; break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-12-06 17:26:36 -06:00
|
|
|
if (optind == argc &&
|
|
|
|
(opt_list || opt_out_geom || opt_out_pt_geom || opt_size || verify)) {
|
2007-10-21 22:25:39 -05:00
|
|
|
FILE *procf;
|
|
|
|
|
2006-12-06 17:25:53 -06:00
|
|
|
/* try all known devices */
|
2006-12-06 17:25:34 -06:00
|
|
|
total_size = 0;
|
2007-10-21 22:25:39 -05:00
|
|
|
|
2010-12-16 18:28:59 -06:00
|
|
|
procf = fopen(_PATH_PROC_PARTITIONS, "r");
|
2007-10-21 22:25:39 -05:00
|
|
|
if (!procf)
|
2010-12-16 18:28:59 -06:00
|
|
|
fprintf(stderr, _("cannot open %s\n"), _PATH_PROC_PARTITIONS);
|
2007-10-21 22:25:39 -05:00
|
|
|
else {
|
|
|
|
while ((dev = nextproc(procf)) != NULL) {
|
2010-12-16 18:28:59 -06:00
|
|
|
if (!is_ide_cdrom_or_tape(dev)) {
|
|
|
|
gpt_warning(dev, 1);
|
|
|
|
if (opt_out_geom)
|
|
|
|
do_geom(dev, 1);
|
|
|
|
if (opt_out_pt_geom)
|
|
|
|
do_pt_geom(dev, 1);
|
|
|
|
if (opt_size)
|
|
|
|
do_size(dev, 1);
|
|
|
|
if (opt_list || verify)
|
|
|
|
do_list(dev, 1);
|
|
|
|
}
|
|
|
|
free(dev);
|
2007-10-21 22:25:39 -05:00
|
|
|
}
|
|
|
|
fclose(procf);
|
2006-12-06 17:25:34 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
if (opt_size)
|
2006-12-06 17:26:18 -06:00
|
|
|
printf(_("total: %llu blocks\n"), total_size);
|
2006-12-06 17:25:34 -06:00
|
|
|
|
|
|
|
exit(exit_status);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (optind == argc) {
|
|
|
|
if (activate)
|
2006-12-06 17:25:37 -06:00
|
|
|
activate_usage(fdisk ? "sfdisk -A" : progn);
|
2006-12-06 17:25:34 -06:00
|
|
|
else if (unhide)
|
2006-12-06 17:25:37 -06:00
|
|
|
unhide_usage(fdisk ? "sfdisk -U" : progn);
|
2006-12-06 17:25:34 -06:00
|
|
|
else
|
2011-05-29 13:26:22 -05:00
|
|
|
usage(stderr);
|
2006-12-06 17:25:34 -06:00
|
|
|
}
|
|
|
|
|
2006-12-06 17:26:36 -06:00
|
|
|
if (opt_list || opt_out_geom || opt_out_pt_geom || opt_size || verify) {
|
2006-12-06 17:25:34 -06:00
|
|
|
while (optind < argc) {
|
2007-05-31 07:31:51 -05:00
|
|
|
gpt_warning(argv[optind], 1);
|
2006-12-06 17:25:34 -06:00
|
|
|
if (opt_out_geom)
|
|
|
|
do_geom(argv[optind], 0);
|
2006-12-06 17:26:36 -06:00
|
|
|
if (opt_out_pt_geom)
|
|
|
|
do_pt_geom(argv[optind], 0);
|
2006-12-06 17:25:34 -06:00
|
|
|
if (opt_size)
|
|
|
|
do_size(argv[optind], 0);
|
|
|
|
if (opt_list || verify)
|
|
|
|
do_list(argv[optind], 0);
|
|
|
|
optind++;
|
|
|
|
}
|
|
|
|
exit(exit_status);
|
|
|
|
}
|
|
|
|
|
2007-05-31 07:31:51 -05:00
|
|
|
if (optind != argc-1)
|
|
|
|
gpt_warning(argv[optind], 0);
|
|
|
|
|
2006-12-06 17:25:34 -06:00
|
|
|
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)
|
2006-12-06 17:25:39 -06:00
|
|
|
fatal(_("usage: sfdisk --print-id device partition-number\n"));
|
2006-12-06 17:25:34 -06:00
|
|
|
else if ((do_id & CHANGE_ID) != 0 && optind != argc-3)
|
2006-12-06 17:25:39 -06:00
|
|
|
fatal(_("usage: sfdisk --change-id device partition-number Id\n"));
|
2006-12-06 17:25:34 -06:00
|
|
|
else if (optind != argc-3 && optind != argc-2)
|
2006-12-06 17:25:39 -06:00
|
|
|
fatal(_("usage: sfdisk --id device partition-number [Id]\n"));
|
2006-12-06 17:25:34 -06:00
|
|
|
do_change_id(argv[optind], argv[optind+1],
|
|
|
|
(optind == argc-2) ? 0 : argv[optind+2]);
|
|
|
|
exit(exit_status);
|
|
|
|
}
|
2007-05-31 07:31:51 -05:00
|
|
|
|
2006-12-06 17:25:34 -06:00
|
|
|
if (optind != argc-1)
|
2006-12-06 17:25:39 -06:00
|
|
|
fatal(_("can specify only one device (except with -l or -s)\n"));
|
2006-12-06 17:25:34 -06:00
|
|
|
dev = argv[optind];
|
|
|
|
|
|
|
|
if (opt_reread)
|
|
|
|
do_reread(dev);
|
|
|
|
else if (restore_sector_file)
|
|
|
|
restore_sectors(dev);
|
|
|
|
else
|
|
|
|
do_fdisk(dev);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* H. Listing the current situation
|
|
|
|
*/
|
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
static int
|
2006-12-06 17:25:34 -06:00
|
|
|
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);
|
2006-12-06 17:25:49 -06:00
|
|
|
if (rw)
|
|
|
|
fatal(_("cannot open %s read-write\n"), dev);
|
|
|
|
else
|
|
|
|
fatal(_("cannot open %s for reading\n"), dev);
|
2006-12-06 17:25:34 -06:00
|
|
|
}
|
|
|
|
return fd;
|
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
static void
|
2006-12-06 17:25:34 -06:00
|
|
|
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))
|
2011-01-31 11:58:26 -06:00
|
|
|
my_warn(_("%s: OK\n"), dev);
|
2006-12-06 17:25:34 -06:00
|
|
|
else
|
|
|
|
exit_status = 1;
|
|
|
|
}
|
2007-10-21 22:25:39 -05:00
|
|
|
|
|
|
|
close(fd);
|
2006-12-06 17:25:34 -06:00
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
static void
|
2006-12-06 17:25:34 -06:00
|
|
|
do_geom (char *dev, int silent) {
|
|
|
|
int fd;
|
2006-12-06 17:25:43 -06:00
|
|
|
struct geometry R;
|
2006-12-06 17:25:34 -06:00
|
|
|
|
|
|
|
fd = my_open(dev, 0, silent);
|
|
|
|
if (fd < 0)
|
|
|
|
return;
|
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
R = get_geometry(dev, fd, silent);
|
|
|
|
if (R.cylinders)
|
|
|
|
printf(_("%s: %ld cylinders, %ld heads, %ld sectors/track\n"),
|
|
|
|
dev, R.cylinders, R.heads, R.sectors);
|
2007-10-21 22:25:39 -05:00
|
|
|
|
|
|
|
close(fd);
|
2006-12-06 17:25:34 -06:00
|
|
|
}
|
|
|
|
|
2006-12-06 17:26:36 -06:00
|
|
|
static void
|
|
|
|
do_pt_geom (char *dev, int silent) {
|
|
|
|
int fd;
|
|
|
|
struct disk_desc *z;
|
|
|
|
struct geometry R;
|
|
|
|
|
|
|
|
fd = my_open(dev, 0, silent);
|
|
|
|
if (fd < 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
z = &oldp;
|
|
|
|
|
|
|
|
free_sectors();
|
|
|
|
get_cylindersize(dev, fd, 1);
|
|
|
|
get_partitions(dev, fd, z);
|
|
|
|
|
|
|
|
R = B;
|
|
|
|
|
|
|
|
if (z->partno != 0 && get_fdisk_geometry(z)) {
|
|
|
|
R.heads = F.heads;
|
|
|
|
R.sectors = F.sectors;
|
|
|
|
R.cylindersize = R.heads * R.sectors;
|
|
|
|
R.cylinders = (R.cylindersize == 0) ? 0 :
|
|
|
|
R.total_size / R.cylindersize;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (R.cylinders)
|
|
|
|
printf(_("%s: %ld cylinders, %ld heads, %ld sectors/track\n"),
|
|
|
|
dev, R.cylinders, R.heads, R.sectors);
|
2007-10-21 22:25:39 -05:00
|
|
|
|
|
|
|
close(fd);
|
2006-12-06 17:26:36 -06:00
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:34 -06:00
|
|
|
/* for compatibility with earlier fdisk: provide option -s */
|
2006-12-06 17:25:43 -06:00
|
|
|
static void
|
2006-12-06 17:25:34 -06:00
|
|
|
do_size (char *dev, int silent) {
|
2006-12-06 17:25:39 -06:00
|
|
|
int fd;
|
2006-12-06 17:26:18 -06:00
|
|
|
unsigned long long size;
|
2006-12-06 17:25:34 -06:00
|
|
|
|
|
|
|
fd = my_open(dev, 0, silent);
|
|
|
|
if (fd < 0)
|
|
|
|
return;
|
|
|
|
|
2007-11-07 12:05:31 -06:00
|
|
|
if (blkdev_get_sectors(fd, &size) == -1) {
|
2006-12-06 17:26:16 -06:00
|
|
|
if (!silent) {
|
2006-12-06 17:25:34 -06:00
|
|
|
perror(dev);
|
2006-12-06 17:26:18 -06:00
|
|
|
fatal(_("Cannot get size of %s\n"), dev);
|
2006-12-06 17:25:34 -06:00
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
size /= 2; /* convert sectors to blocks */
|
2006-12-06 17:25:37 -06:00
|
|
|
|
|
|
|
/* a CDROM drive without mounted CD yields MAXINT */
|
|
|
|
if (silent && size == ((1<<30)-1))
|
|
|
|
return;
|
|
|
|
|
2006-12-06 17:25:34 -06:00
|
|
|
if (silent)
|
2006-12-06 17:26:18 -06:00
|
|
|
printf("%s: %9llu\n", dev, size);
|
2006-12-06 17:25:34 -06:00
|
|
|
else
|
2006-12-06 17:26:18 -06:00
|
|
|
printf("%llu\n", size);
|
2006-12-06 17:25:34 -06:00
|
|
|
|
|
|
|
total_size += size;
|
2007-10-21 22:25:39 -05:00
|
|
|
|
|
|
|
close(fd);
|
2006-12-06 17:25:34 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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
|
2006-12-06 17:25:37 -06:00
|
|
|
* Or: sfdisk -A /dev/hda 2 5 7
|
2006-12-06 17:25:34 -06:00
|
|
|
*
|
|
|
|
* If only a single partition must be active, one may also use the form
|
2006-12-06 17:25:37 -06:00
|
|
|
* sfdisk -A2 /dev/hda
|
2006-12-06 17:25:34 -06:00
|
|
|
*
|
2006-12-06 17:25:37 -06:00
|
|
|
* With "activate /dev/hda" or "sfdisk -A /dev/hda" the active partitions
|
2006-12-06 17:25:34 -06:00
|
|
|
* are listed but not changed. To get zero active partitions, use
|
2006-12-06 17:25:37 -06:00
|
|
|
* "activate /dev/hda none" or "sfdisk -A /dev/hda none".
|
|
|
|
* Use something like `echo ",,,*" | sfdisk -N2 /dev/hda' to only make
|
2006-12-06 17:25:34 -06:00
|
|
|
* /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.
|
|
|
|
*/
|
2006-12-06 17:25:43 -06:00
|
|
|
static void
|
2006-12-06 17:25:34 -06:00
|
|
|
set_active (struct disk_desc *z, char *pnam) {
|
|
|
|
int pno;
|
|
|
|
|
|
|
|
pno = asc_to_index(pnam, z);
|
2006-12-06 17:26:12 -06:00
|
|
|
if (z->partitions[pno].ptype == DOS_TYPE)
|
|
|
|
z->partitions[pno].p.bootable = 0x80;
|
2006-12-06 17:25:34 -06:00
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
static void
|
2006-12-06 17:25:34 -06:00
|
|
|
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))
|
2006-12-06 17:25:43 -06:00
|
|
|
printf("%s\n", partname(dev, lpno, 0));
|
2006-12-06 17:25:34 -06:00
|
|
|
else
|
|
|
|
printf("%s#%d\n", dev, pno);
|
|
|
|
if (z->partitions[pno].p.bootable != 0x80)
|
2011-01-31 11:58:26 -06:00
|
|
|
my_warn(_("bad active byte: 0x%x instead of 0x80\n"),
|
2006-12-06 17:25:34 -06:00
|
|
|
z->partitions[pno].p.bootable);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* clear `active byte' everywhere */
|
|
|
|
for (pno=0; pno < z->partno; pno++)
|
2006-12-06 17:26:12 -06:00
|
|
|
if (z->partitions[pno].ptype == DOS_TYPE)
|
|
|
|
z->partitions[pno].p.bootable = 0;
|
2006-12-06 17:25:34 -06:00
|
|
|
|
|
|
|
/* 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 */
|
2006-12-06 17:26:16 -06:00
|
|
|
if (write_partitions(dev, fd, z))
|
2011-01-31 11:58:26 -06:00
|
|
|
my_warn(_("Done\n\n"));
|
2006-12-06 17:25:34 -06:00
|
|
|
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)
|
2011-01-31 11:58:26 -06:00
|
|
|
my_warn(_("You have %d active primary partitions. This does not matter for LILO,\n"
|
2006-12-06 17:25:39 -06:00
|
|
|
"but the DOS MBR will only boot a disk with 1 active partition.\n"), i);
|
2007-10-21 22:25:39 -05:00
|
|
|
|
|
|
|
close(fd);
|
2006-12-06 17:25:34 -06:00
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
static void
|
2006-12-06 17:25:34 -06:00
|
|
|
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
|
2006-12-06 17:25:39 -06:00
|
|
|
fatal(_("partition %s has id %x and is not hidden\n"), pnam, id);
|
2006-12-06 17:25:34 -06:00
|
|
|
z->partitions[pno].p.sys_type = id;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* maybe remove and make part of --change-id
|
|
|
|
*/
|
2006-12-06 17:25:43 -06:00
|
|
|
static void
|
2006-12-06 17:25:34 -06:00
|
|
|
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 */
|
2006-12-06 17:26:16 -06:00
|
|
|
if (write_partitions(dev, fd, z))
|
2011-01-31 11:58:26 -06:00
|
|
|
my_warn(_("Done\n\n"));
|
2006-12-06 17:25:34 -06:00
|
|
|
else
|
|
|
|
exit_status = 1;
|
2007-10-21 22:25:39 -05:00
|
|
|
|
|
|
|
close(fd);
|
2006-12-06 17:25:34 -06:00
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
static void
|
|
|
|
do_change_id(char *dev, char *pnam, char *id) {
|
2006-12-06 17:25:34 -06:00
|
|
|
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)
|
2006-12-06 17:25:44 -06:00
|
|
|
fatal(_("Bad Id %lx\n"), i);
|
2006-12-06 17:25:34 -06:00
|
|
|
z->partitions[pno].p.sys_type = i;
|
|
|
|
|
2006-12-06 17:26:16 -06:00
|
|
|
if (write_partitions(dev, fd, z))
|
2011-01-31 11:58:26 -06:00
|
|
|
my_warn(_("Done\n\n"));
|
2006-12-06 17:25:34 -06:00
|
|
|
else
|
|
|
|
exit_status = 1;
|
2007-10-21 22:25:39 -05:00
|
|
|
|
|
|
|
close(fd);
|
2006-12-06 17:25:34 -06:00
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
static void
|
2006-12-06 17:25:34 -06:00
|
|
|
do_reread(char *dev) {
|
|
|
|
int fd;
|
|
|
|
|
|
|
|
fd = my_open(dev, 0, 0);
|
2011-05-03 08:47:38 -05:00
|
|
|
if (reread_ioctl(fd)) {
|
2006-12-06 17:26:16 -06:00
|
|
|
do_warn(_("This disk is currently in use.\n"));
|
2011-05-03 08:47:38 -05:00
|
|
|
exit(1);
|
|
|
|
}
|
2007-10-21 22:25:39 -05:00
|
|
|
|
|
|
|
close(fd);
|
2006-12-06 17:25:34 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* I. Writing the new situation
|
|
|
|
*/
|
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
static void
|
2006-12-06 17:25:34 -06:00
|
|
|
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);
|
2006-12-06 17:25:39 -06:00
|
|
|
fatal(_("Fatal error: cannot find %s\n"), dev);
|
2006-12-06 17:25:34 -06:00
|
|
|
}
|
|
|
|
if (!S_ISBLK(statbuf.st_mode)) {
|
2006-12-06 17:26:22 -06:00
|
|
|
do_warn(_("Warning: %s is not a block device\n"), dev);
|
2006-12-06 17:25:39 -06:00
|
|
|
no_reread = 1;
|
2006-12-06 17:25:34 -06:00
|
|
|
}
|
|
|
|
fd = my_open(dev, !no_write, 0);
|
|
|
|
|
2006-12-06 17:26:16 -06:00
|
|
|
if (!no_write && !no_reread) {
|
2011-01-31 11:58:26 -06:00
|
|
|
my_warn(_("Checking that no-one is using this disk right now ...\n"));
|
2006-12-06 17:26:16 -06:00
|
|
|
if (reread_ioctl(fd)) {
|
|
|
|
do_warn(_("\nThis disk is currently in use - repartitioning is probably a bad idea.\n"
|
2006-12-06 17:25:43 -06:00
|
|
|
"Umount all file systems, and swapoff all swap partitions on this disk.\n"
|
2006-12-06 17:25:39 -06:00
|
|
|
"Use the --no-reread flag to suppress this check.\n"));
|
2006-12-06 17:25:34 -06:00
|
|
|
if (!force) {
|
2006-12-06 17:26:16 -06:00
|
|
|
do_warn(_("Use the --force flag to overrule all checks.\n"));
|
2006-12-06 17:25:34 -06:00
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
} else
|
2011-01-31 11:58:26 -06:00
|
|
|
my_warn(_("OK\n"));
|
2006-12-06 17:25:34 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
z = &oldp;
|
|
|
|
|
|
|
|
free_sectors();
|
|
|
|
get_cylindersize(dev, fd, 0);
|
|
|
|
get_partitions(dev, fd, z);
|
|
|
|
|
2006-12-06 17:25:39 -06:00
|
|
|
printf(_("Old situation:\n"));
|
2006-12-06 17:25:34 -06:00
|
|
|
out_partitions(dev, z);
|
|
|
|
|
|
|
|
if (one_only && (one_only_pno = linux_to_index(one_only, z)) < 0)
|
2006-12-06 17:25:39 -06:00
|
|
|
fatal(_("Partition %d does not exist, cannot change it\n"), one_only);
|
2006-12-06 17:25:34 -06:00
|
|
|
|
|
|
|
z = &newp;
|
|
|
|
|
|
|
|
while(1) {
|
|
|
|
|
|
|
|
read_input(dev, interactive, z);
|
|
|
|
|
2006-12-06 17:25:39 -06:00
|
|
|
printf(_("New situation:\n"));
|
2006-12-06 17:25:34 -06:00
|
|
|
out_partitions(dev, z);
|
|
|
|
|
|
|
|
if (!partitions_ok(z) && !force) {
|
2006-12-06 17:26:16 -06:00
|
|
|
if (!interactive)
|
2006-12-06 17:25:39 -06:00
|
|
|
fatal(_("I don't like these partitions - nothing changed.\n"
|
|
|
|
"(If you really want this, use the --force option.)\n"));
|
2006-12-06 17:25:34 -06:00
|
|
|
else
|
2006-12-06 17:26:16 -06:00
|
|
|
do_warn(_("I don't like this - probably you should answer No\n"));
|
2006-12-06 17:25:34 -06:00
|
|
|
}
|
|
|
|
ask:
|
|
|
|
if (interactive) {
|
|
|
|
if (no_write)
|
2006-12-06 17:25:39 -06:00
|
|
|
printf(_("Are you satisfied with this? [ynq] "));
|
2006-12-06 17:25:34 -06:00
|
|
|
else
|
2006-12-06 17:25:39 -06:00
|
|
|
printf(_("Do you want to write this to disk? [ynq] "));
|
2006-12-06 17:25:34 -06:00
|
|
|
answer = c = getchar();
|
|
|
|
while (c != '\n' && c != EOF)
|
|
|
|
c = getchar();
|
|
|
|
if (c == EOF)
|
2006-12-06 17:25:39 -06:00
|
|
|
printf(_("\nsfdisk: premature end of input\n"));
|
2006-12-06 17:25:34 -06:00
|
|
|
if (c == EOF || answer == 'q' || answer == 'Q') {
|
2006-12-06 17:25:39 -06:00
|
|
|
fatal(_("Quitting - nothing changed\n"));
|
2006-12-06 17:25:34 -06:00
|
|
|
} else if (answer == 'n' || answer == 'N') {
|
|
|
|
continue;
|
|
|
|
} else if (answer == 'y' || answer == 'Y') {
|
|
|
|
break;
|
|
|
|
} else {
|
2006-12-06 17:25:39 -06:00
|
|
|
printf(_("Please answer one of y,n,q\n"));
|
2006-12-06 17:25:34 -06:00
|
|
|
goto ask;
|
|
|
|
}
|
|
|
|
} else
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2006-12-06 17:26:16 -06:00
|
|
|
if (write_partitions(dev, fd, z))
|
2006-12-06 17:25:39 -06:00
|
|
|
printf(_("Successfully wrote the new partition table\n\n"));
|
2006-12-06 17:25:34 -06:00
|
|
|
else
|
|
|
|
exit_status = 1;
|
|
|
|
|
2011-05-03 08:47:38 -05:00
|
|
|
if (!reread_disk_partition(dev, fd))
|
|
|
|
exit_status = 1;
|
2007-10-21 22:25:39 -05:00
|
|
|
|
2011-01-31 11:58:26 -06:00
|
|
|
my_warn(_("If you created or changed a DOS partition, /dev/foo7, say, then use dd(1)\n"
|
2006-12-06 17:25:34 -06:00
|
|
|
"to zero the first 512 bytes: dd if=/dev/zero of=/dev/foo7 bs=512 count=1\n"
|
2006-12-06 17:25:39 -06:00
|
|
|
"(See fdisk(8).)\n"));
|
2007-10-21 22:25:39 -05:00
|
|
|
|
2006-12-06 17:25:34 -06:00
|
|
|
sync(); /* superstition */
|
|
|
|
exit(exit_status);
|
|
|
|
}
|