/*
* gpart.c -- gpart main
*
* gpart (c) 1999-2001 Michail Brzitwa <mb@ichabod.han.de>
* Guess PC-type hard disk partitions.
*
* gpart 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 2, or (at your
* option) any later version.
*
* Created: 04.01.1999 <mb@ichabod.han.de>
* Modified: 11.06.1999 <mb@ichabod.han.de>
* Handle disk read errors.
* Minor fixes.
*
* 29.06.1999 <mb@ichabod.han.de>
* Made every disk read/write buffer aligned to pagesize.
*
* 29.08.1999 <mb@ichabod.han.de>
* Default scan increment now 's'.
* Extended ptbl boundary condition now depends on scan
* increment.
*
* 26.02.2000 <mb@ichabod.han.de>
* Default scan increment 'h' again.
* Fixed faulty head boundary condition.
* Introduced ptbl entry editing after guess loop.
* First scanned sector is no of sects/head, if no start
* sector was given.
* m_notinext now honoured.
* Make a MBR backup.
* Interactive mode now somehow works.
*
* 14.05.2000 <mb@ichabod.han.de>
* Made writing of guessed table also aligned.
* Fixed stupid copy&paste bug in the check routine
* (found by Bruno Bozza <brunobozza@hotmail.com>.
*
* 29.01.2001 <mb@ichabod.han.de>
* Extended partition type on an LBA disk now 0x0f instead
* of 0x05. Changed some partition types (get_part_type).
* When comparing partition types in extptbl links, try
* to compare similarity, not equality (is_same_partition_type).
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include <sys/stat.h>
#include <sys/types.h>
#include "gpart.h"
static const char rcsid[] = "$Id: gpart.c,v 1.11 2001/02/07 18:08:08 mb Exp mb $";
static const char *gpart_version = PROGRAM " v" VERSION;
int f_check = 0, f_verbose = 0, f_dontguess = 0, f_fast = 1;
int f_getgeom = 1, f_interactive = 0, f_quiet = 0, f_testext = 1;
int f_skiperrors = 1, berrno = 0;
int (*boundary_fun)(disk_desc *,s64_t);
unsigned long increment = 'h', gc = 0, gh = 0, gs = 0;
s64_t skipsec = 0, maxsec = 0;
FILE *log = 0;
void usage()
{
FILE *fp = stderr;
fprintf(fp,"Usage: %s [options] device\n",PROGRAM);
fprintf(fp,"Options: [-b <backup MBR>][-C c,h,s][-c][-d][-E][-e][-f][-g][-h][-i]\n");
fprintf(fp," [-K <last sector>][-k <# of sectors>][-L][-l <log file>]\n");
fprintf(fp," [-n <increment>][-q][-s <sector-size>][-t <module-name>]\n");
fprintf(fp," [-V][-v][-W <device>][-w <module-name,weight>]\n");
fprintf(fp,"%s (c) 1999-2001 Michail Brzitwa <michail@brzitwa.de>.\n",gpart_version);
fprintf(fp,"Guess PC-type hard disk partitions.\n\n");
if (! f_verbose)
return;
fprintf(fp,"Options:\n");
fprintf(fp," -b Save a backup of the original MBR to specified file.\n");
fprintf(fp," -C Set c/h/s to be used in the scan.\n");
fprintf(fp," -c Check/compare mode.\n");
fprintf(fp," -d Do not start the guessing loop.\n");
fprintf(fp," -E Do not try to identify extended partition tables.\n");
fprintf(fp," -e Do not skip disk read errors.\n");
fprintf(fp," -f Full scan.\n");
fprintf(fp," -g Do not try to get the disk geometry.\n");
fprintf(fp," -h Show this help.\n");
fprintf(fp," -i Run interactively (ask for confirmation).\n");
fprintf(fp," -K Scan only up to given sector.\n");
fprintf(fp," -k Skip sectors before scan.\n");
fprintf(fp," -L List available modules and their weights, then exit.\n");
fprintf(fp," -l Logfile name.\n");
fprintf(fp," -n Scan increment: number or 's' sector, 'h' head, 'c' cylinder.\n");
fprintf(fp," -q Run quiet (however log file is written if specified).\n");
fprintf(fp," -s Sector size to use (disable sector size probing).\n");
fprintf(fp," -t Name of a guessing module to be added.\n");
fprintf(fp," -V Show version.\n");
fprintf(fp," -v Verbose mode. Can be given more than once.\n");
fprintf(fp," -W Write guessed primary partition table to given device or file.\n");
fprintf(fp," -w Weight factor of module.\n");
fprintf(fp,"\n");
}
void pr(int type,char *fmt,...)
{
va_list vl;
static char msg[512];
va_start(vl,fmt); vsnprintf(msg,511,fmt,vl); va_end(vl); msg[511] = 0;
switch (type)
{
case FATAL :
g_mod_deleteall();
if (! f_quiet) fprintf(stderr,EM_FATALERROR,msg);
if (log)
{
fprintf(log,EM_FATALERROR,msg);
fclose(log);
}
exit(1);
case ERROR :
if (! f_quiet) fprintf(stderr,EM_SIMPLEERROR,msg);
if (log) fprintf(log,EM_SIMPLEERROR,msg);
break;
case WARN :
if (! f_quiet) fprintf(stderr,EM_WARNING,msg);
if (log) fprintf(log,EM_WARNING,msg);
break;
case MSG :
if (! f_quiet) fputs(msg,stdout); fflush(stdout);
if (log) fputs(msg,log);
break;
}
if (log) fflush(log);
}
byte_t *alloc(ssize_t s)
{
byte_t *p = (byte_t *)malloc(s);
if (p == 0)
pr(FATAL,EM_MALLOCFAILED,s);
memset(p,0,s);
return (p);
}
/*
* read nsecs blocks of ssize bytes from fd
*/
ssize_t bread(int fd,byte_t *buf,size_t ssize,size_t nsecs)
{
ssize_t cs = 0, nr = 0;
for ( ; nsecs > 0; nsecs--)
{
if ((nr = read(fd,buf,ssize)) == -1)
{
berrno = errno;
return ((cs == 0) ? -1 : cs);
}
cs += nr; buf += nr;
if (nr < ssize)
break;
}
return (cs);
}
static int yesno(char *q)
{
int ch = 0;
char buf[3];
pr(MSG,q); pr(MSG," %s : ",DM_YESNO);
if (fgets(buf,3,stdin)) ch = *buf; pr(MSG,"\n");
return (strchr(DM_YES,ch) == 0 ? 0 : 1);
}
static long number_or_quit(char *m,long lo,long up)
{
char buf[32];
long num = -1;
pr(MSG,m); pr(MSG,DM_NUMORQUIT,lo,up);
if (fgets(buf,32,stdin))
{
if (strchr(DM_QUIT,*buf))
return (-1);
num = strtoul(buf,0,0);
if (errno == ERANGE)
return (-1);
}
return (num);
}
/*
* get three comma separated strings.
*/
static int get_csep_arg(char *arg,char **p1,char **p2,char **p3)
{
char *p;
if (p1) *p1 = arg; else return (0);
if ((p = strchr(arg,',')) == 0) return (0);
*p = 0; arg = p + 1;
if (p2) *p2 = arg; else return (1);
if (p3)
{
if ((p = strchr(arg,',')) == 0) return (0);
*p = 0; *p3 = p + 1;
}
return (1);
}
/*
* partition type list, taken from *BSD i386 fdisk, cfdisk etc.
*/
static char *get_part_type(int type)
{
int i;
struct
{
int t;
char *n;
} ptypes[] =
{
{ 0x00, "unused" },
{ 0x01, "Primary DOS with 12 bit FAT" },
{ 0x02, "XENIX / filesystem" },
{ 0x03, "XENIX /usr filesystem" },
{ 0x04, "Primary DOS with 16 bit FAT (<= 32MB)" },
{ 0x05, "Extended DOS" },
{ 0x06, "Primary 'big' DOS (> 32MB)" },
{ 0x07, "OS/2 HPFS, NTFS, QNX or Advanced UNIX" },
{ 0x08, "AIX filesystem" },
{ 0x09, "AIX boot partition or Coherent" },
{ 0x0A, "OS/2 Boot Manager or OPUS" },
{ 0x0B, "DOS or Windows 95 with 32 bit FAT" },
{ 0x0C, "DOS or Windows 95 with 32 bit FAT, LBA" },
{ 0x0E, "Primary 'big' DOS (> 32MB, LBA)" },
{ 0x0F, "Extended DOS, LBA" },
{ 0x10, "OPUS" },
{ 0x11, "Hidden DOS with 12 bit FAT" },
{ 0x12, "Compaq Diagnostics" },
{ 0x14, "Hidden DOS with 16 bit FAT (<= 32MB)" },
{ 0x16, "Hidden 'big' DOS (> 32MB)" },
{ 0x17, "OS/2 Boot Manager HPFS" },
{ 0x18, "AST special Windows swap file" },
{ 0x24, "NEC MS-DOS 3.x" },
{ 0x3C, "PowerQuest PartitionMagic recovery partition" },
{ 0x40, "VENIX 286" },
{ 0x4D, "QNX4.x" },
{ 0x4E, "QNX4.x 2nd part" },
{ 0x4F, "QNX4.x 3rd part" },
{ 0x50, "DM" },
{ 0x51, "DM" },
{ 0x51, "DM" },
{ 0x52, "CP/M or Microport SysV/AT" },
{ 0x55, "EZ Drive" },
{ 0x56, "GB" },
{ 0x61, "SpeedStor" },
{ 0x63, "ISC UNIX, other System V/386, GNU HURD or Mach" },
{ 0x64, "Novell Netware 2.xx" },
{ 0x65, "Novell Netware 3.xx" },
{ 0x70, "DiskSecure Multi-Boot" },
{ 0x75, "PCIX" },
{ 0x80, "Minix V1" },
{ 0x81, "Minix V2/Linux" },
{ 0x82, "Linux swap or Solaris/x86" },
{ 0x83, "Linux ext2 filesystem" },
{ 0x85, "Extended Linux" },
{ 0x86, "FAT16 volume/stripe set" },
{ 0x8E, "Linux LVM physical volume" },
{ 0x93, "Amoeba filesystem" },
{ 0x94, "Amoeba bad block table" },
{ 0xA5, "FreeBSD/NetBSD/386BSD" },
{ 0xA6, "OpenBSD" },
{ 0xA7, "NEXTSTEP" },
{ 0xB7, "BSDI BSD/386 filesystem" },
{ 0xB8, "BSDI BSD/386 swap" },
{ 0xC7, "Syrinx" },
{ 0xDB, "Concurrent CPM or C.DOS or CTOS" },
{ 0xE1, "SpeedStor 12-bit FAT extended" },
{ 0xE3, "Speed" },
{ 0xE4, "SpeedStor 16-bit FAT" },
{ 0xEB, "BeOS fs" },
{ 0xF1, "SpeedStor" },
{ 0xF2, "DOS 3.3+ Secondary" },
{ 0xF4, "SpeedStor" },
{ 0xFD, "Linux raid autodetect" },
{ 0xFE, "LANstep" },
{ 0xFF, "BBT (Bad Blocks Table)" }
};
for (i = 0; i < sizeof(ptypes)/sizeof(ptypes[0]); i++)
if (type == ptypes[i].t)
return (ptypes[i].n);
return (0);
}
static int is_ext_parttype(dos_part_entry *p)
{
return (p->p_size && ((p->p_typ == 0x05) ||
(p->p_typ == 0x0F) || (p->p_typ == 0x85)));
}
static int is_sane_partentry(disk_desc *d,dos_part_entry *p,int c)
{
if (p->p_start >= d->d_nsecs)
{
if (c) pr(WARN,EM_PSTART2BIG,get_part_type(p->p_typ));
return (0);
}
if (p->p_size > d->d_nsecs)
{
if (c) pr(WARN,EM_PSIZE2BIG,get_part_type(p->p_typ));
return (0);
}
if (p->p_start + p->p_size > d->d_nsecs)
{
if (c) pr(WARN,EM_PEND2BIG,get_part_type(p->p_typ));
return (0);
}
if (p->p_flag && (p->p_flag != DOSPARTACTIVE))
{
if (c) pr(WARN,EM_STRANGEPTYPE,get_part_type(p->p_typ));
return (0);
}
return (1);
}
static int is_real_parttype(dos_part_entry *p)
{
return (!is_ext_parttype(p) && p->p_typ && get_part_type(p->p_typ));
}
static int no_of_ext_partitions(dos_part_entry *p)
{
dos_part_entry *t;
int ne = 0;
for (t = &p[0]; t < &p[NDOSPARTS]; t++)
if (is_ext_parttype(t))
ne++;
return (ne);
}
static int no_of_real_partitions(dos_part_entry *p)
{
dos_part_entry *t;
int nr = 0;
for (t = &p[0]; t < &p[NDOSPARTS]; t++)
if (is_real_parttype(t))
nr++;
return (nr);
}
/*
* Test similarity of partition types
*/
static int is_same_partition_type(dos_part_entry *p1,dos_part_entry *p2)
{
int ret = 0;
switch (p1->p_typ)
{
case 0x01: case 0x11:
ret = (p2->p_typ == 0x06) || (p2->p_typ == 0x0E);
break;
case 0x06: case 0x0E: case 0x16:
ret = (p2->p_typ == 0x06) || (p2->p_typ == 0x0E) || (p2->p_typ == 0x16);
break;
case 0x05: case 0x0F:
ret = (p2->p_typ == 0x05) || (p2->p_typ == 0x0F);
break;
case 0x0B: case 0x0C:
ret = (p2->p_typ == 0x0B) || (p2->p_typ == 0x0C);
break;
case 0x8E: case 0xFE:
ret = (p2->p_typ == 0x8E) || (p2->p_typ == 0xFE);
break;
default :
ret = p1->p_typ == p2->p_typ;
break;
}
return (ret);
}
/*
* detecting an extended ptbl isn't unambiguous, the boot code
* preceding the ptbl should be zeroed but isn't always. The
* ptbl should in theory contain one 'normal' entry, zero or
* one link to the next extended ptbl and two or three zeroed
* entries.
*/
static int is_ext_parttable(disk_desc *d,byte_t *buf)
{
int r, e;
byte_t *magic;
dos_part_entry *p, *t;
p = (dos_part_entry *)(buf + DOSPARTOFF);
magic = (byte_t *)&p[NDOSPARTS];
if (*(unsigned short *)magic != le16(DOSPTMAGIC))
return (0);
/*
* ptbl sanity checks.
*/
for (t = p; t < &p[NDOSPARTS]; t++)
if (! is_sane_partentry(d,t,0))
return (0);
/*
* one real, zero or one extended and two or three unused
* partition entries.
*/
r = no_of_real_partitions(p);
e = no_of_ext_partitions(p);
return ((r == 1) && ((e == 0) || (e == 1)));
}
static void fillin_dos_chs(disk_desc *d,dos_part_entry *p,s64_t offset)
{
unsigned long n;
n = p->p_start;
if (n > 1023 * d->d_dg.d_h * d->d_dg.d_s)
{
p->p_ssect = d->d_dg.d_s | ((1023 >> 2) & 0xc0);
p->p_shd = d->d_dg.d_h - 1;
p->p_scyl = 1023 & 0xff;
}
else
{
p->p_ssect = (n % d->d_dg.d_s) + 1;
n /= d->d_dg.d_s;
p->p_shd = n % d->d_dg.d_h;
n /= d->d_dg.d_h;
p->p_scyl = n & 0xff;
p->p_ssect |= (n >> 2) & 0xc0;
}
n = p->p_size + p->p_start - 1;
if (n > 1023 * d->d_dg.d_h * d->d_dg.d_s)
{
p->p_esect = d->d_dg.d_s | ((1023 >> 2) & 0xc0);
p->p_ehd = d->d_dg.d_h - 1;
p->p_ecyl = 1023 & 0xff;
}
else
{
p->p_esect = (n % d->d_dg.d_s) + 1;
n /= d->d_dg.d_s;
p->p_ehd = n % d->d_dg.d_h;
n /= d->d_dg.d_h;
p->p_ecyl = n & 0xff;
p->p_esect |= (n >> 2) & 0xc0;
}
}
static void u_to_chs(disk_desc *d,unsigned long u,long *c,long *h,long *s)
{
struct disk_geom *g = &d->d_dg;
*c = *h = *s = 0;
if (g->d_h && g->d_s && u)
{
*c = u / (g->d_h * g->d_s);
*h = (u / g->d_s) % g->d_h;
*s = u % g->d_s + 1;
}
}
static int on_cyl_boundary(disk_desc *d,s64_t sec)
{
struct disk_geom *g = &d->d_dg;
if (g->d_h && g->d_s)
return ((sec % (g->d_h * g->d_s)) == 0);
return (1);
}
static int on_head_boundary(disk_desc *d,s64_t sec)
{
struct disk_geom *g = &d->d_dg;
if (g->d_s)
return ((sec % g->d_s) == 0);
return (1);
}
static void print_partition(disk_desc *d,dos_part_entry *p,int inset,s64_t offset)
{
long i, c = 0, h = 0, s = 0;
s64_t size;
char *ptyp = get_part_type(p->p_typ);
#define indent(s) for (i = 0; i < s; i++) pr(MSG," ")
size = p->p_size; s2mb(d,size);
indent(inset);
pr(MSG,PM_PT_TYPE,p->p_typ,p->p_typ,ptyp ? ptyp : "UNKNOWN");
if (p->p_flag == DOSPARTACTIVE)
pr(MSG," (BOOT)");
pr(MSG,"\n");
indent(inset);
pr(MSG,PM_PT_SIZE,size,(s64_t)p->p_size);
size = p->p_start; size += offset; size += p->p_size;
if (size) size -= 1;
pr(MSG," s(%qd-%qd)\n",(s64_t)p->p_start + offset,size);
indent(inset);
pr(MSG,PM_PT_CHS,
DOSCYL(p->p_scyl,p->p_ssect),p->p_shd,DOSSEC(p->p_ssect),
DOSCYL(p->p_ecyl,p->p_esect),p->p_ehd,DOSSEC(p->p_esect));
if (size) u_to_chs(d,p->p_start + offset,&c,&h,&s);
pr(MSG," (%ld/%ld/%ld)-",c,h,s);
if (size) u_to_chs(d,p->p_start + offset + p->p_size - 1,&c,&h,&s);
pr(MSG,"(%ld/%ld/%ld)r\n",c,h,s);
if (f_verbose > 0)
{
indent(inset);
pr(MSG,PM_PT_HEX);
for (i = 0; i < sizeof(dos_part_entry); i++)
pr(MSG," %02X",((byte_t *)p)[i]);
pr(MSG,"\n");
}
pr(MSG,"\n");
}
static void print_ext_partitions(disk_desc *d,s64_t offset)
{
dos_part_table *pt = d->d_pt.t_ext;
dos_part_entry *p;
s64_t extst = 0;
for ( ; pt; pt = pt->t_ext)
{
pr(MSG,PM_EXTPART);
for (p = pt->t_parts; p < &pt->t_parts[NDOSPARTS + 1]; p++)
if (is_real_parttype(p))
print_partition(d,p,1,offset + extst);
for (p = pt->t_parts; p < &pt->t_parts[NDOSPARTS + 1]; p++)
if (is_ext_parttype(p))
extst = p->p_start;
}
}
static void print_ptable(disk_desc *d,dos_part_table *pt,int pr_ext)
{
int n;
for (n = 0; n < NDOSPARTS; n++)
{
pr(MSG,PM_PRIMPART,n + 1);
print_partition(d,&pt->t_parts[n],0,0);
if (pr_ext && is_ext_parttype(&pt->t_parts[n]))
print_ext_partitions(d,pt->t_parts[n].p_start);
}
}
static void print_disk_desc(disk_desc *d)
{
s64_t s;
pr(MSG,PM_DEVDESC1,d->d_dev,d->d_ssize);
if (f_getgeom)
{
s = d->d_nsecs; s2mb(d,s);
pr(MSG,PM_DEVDESC2,
d->d_dg.d_c,d->d_dg.d_h,d->d_dg.d_s,
d->d_lba ? "(LBA) " : " ",
d->d_nsecs,s);
}
pr(MSG,"\n");
if (d->d_pt.t_magic != le16(DOSPTMAGIC))
pr(WARN,EM_STRANGEPTBLMAGIC,d->d_pt.t_magic);
print_ptable(d,&d->d_pt,1);
}
static void print_mboot_block(disk_desc *d)
{
int n, m, cols = 16;
byte_t *boot = d->d_pt.t_boot;
pr(MSG,PM_MBRPRINT,d->d_dev);
for (n = 0; n < DOSPARTOFF - cols; n += cols)
{
pr(MSG," %04X: ",n);
for (m = n; m < n + cols; m++)
pr(MSG," %02x",boot[m]);
pr(MSG,"\n ");
for (m = n; m < n + cols; m++)
pr(MSG," %c ",isprint(boot[m]) ? boot[m] : '.');
pr(MSG,"\n");
}
}
static void read_part_table(disk_desc *d,s64_t sec,byte_t *where)
{
ssize_t rd;
size_t psize;
byte_t *ubuf, *buf;
psize = getpagesize();
ubuf = alloc(MAXSSIZE + psize);
buf = align(ubuf,psize);
sec *= d->d_ssize;
if (l64seek(d->d_fd,sec,SEEK_SET) == -1)
pr(FATAL,EM_SEEKFAILURE,d->d_dev);
if (d->d_ssize < 512)
rd = bread(d->d_fd,buf,d->d_ssize,512 / d->d_ssize);
else
rd = bread(d->d_fd,buf,d->d_ssize,1);
if (rd == -1)
pr(FATAL,EM_PTBLREAD);
memcpy(where,buf,512);
free((void *)ubuf);
}
static void read_ext_part_table(disk_desc *d,dos_part_table *pt)
{
dos_part_entry *p, *ep;
s64_t epsize, epstart, epoffset;
int epcount;
epsize = epstart = epoffset = epcount = 0;
while (1)
{
ep = 0;
for (p = pt->t_parts; p < &pt->t_parts[NDOSPARTS + 1]; p++)
if (is_ext_parttype(p))
{
if (ep == 0)
{
ep = p;
break;
}
pr(ERROR,EM_TOOMANYEXTP);
}
if (ep == 0)
return;
if (++epcount > 128) /* arbitrary maximum */
{
pr(ERROR,EM_TOOMANYLOGP,128);
return;
}
if (epstart == 0)
{
epstart = ep->p_start;
epsize = ep->p_size;
epoffset = 0;
}
else
epoffset = ep->p_start;
if (epoffset > epsize)
{
pr(ERROR,EM_EPILLEGALOFS);
return;
}
/*
* link in new extended ptbl.
*/
pt->t_ext = (dos_part_table *)alloc(sizeof(dos_part_table));
read_part_table(d,epstart + epoffset,(pt = pt->t_ext)->t_boot);
if (! is_ext_parttable(d,pt->t_boot))
{
pr(ERROR,EM_INVXPTBL,epstart + epoffset);
return;
}
}
}
static void free_disk_desc(disk_desc *d)
{
dos_part_table *pt;
dos_guessed_pt *pg;
void *t;
for (pt = d->d_pt.t_ext; pt; )
{
t = pt->t_ext; free((void *)pt); pt = t;
}
for (pt = d->d_gpt.t_ext; pt; )
{
t = pt->t_ext; free((void *)pt); pt = t;
}
for (pg = d->d_gl; pg; )
{
t = pg->g_next; free((void *)pg); pg = t;
}
free((void *)d);
}
static disk_desc *get_disk_desc(char *dev,int sectsize)
{
byte_t *ubuf, *buf;
disk_desc *d;
int psize, ssize;
struct disk_geom *dg;
psize = getpagesize();
ubuf = alloc(MAXSSIZE + psize);
buf = align(ubuf,psize);
d = (disk_desc *)alloc(sizeof(disk_desc));
/*
* I don't care if the given name denotes a block or character
* special file or just a regular file.
*/
if ((d->d_fd = open(dev,O_RDONLY)) == -1)
pr(FATAL,EM_OPENFAIL,dev,strerror(errno));
/*
* try to test for sector sizes (doesn't work under many systems).
*/
if (sectsize > MAXSSIZE)
pr(FATAL,EM_WRONGSECTSIZE,MAXSSIZE);
if (sectsize)
{
ssize = bread(d->d_fd,buf,sectsize,1);
if (ssize != sectsize)
pr(FATAL,EM_FAILSSIZEATTEMPT,sectsize);
d->d_ssize = sectsize;
}
else
{
for (d->d_ssize = MINSSIZE; d->d_ssize <= MAXSSIZE; d->d_ssize *= 2)
{
if (l64seek(d->d_fd,0,SEEK_SET) == -1)
pr(FATAL,EM_SEEKFAILURE,dev);
ssize = bread(d->d_fd,buf,d->d_ssize,1);
if (ssize == d->d_ssize)
break;
}
if (ssize == -1)
pr(FATAL,EM_CANTGETSSIZE,dev);
}
d->d_dev = dev;
read_part_table(d,0,d->d_pt.t_boot);
if (f_getgeom)
{
if ((dg = disk_geometry(d)) == 0)
pr(FATAL,EM_CANTGETGEOM);
memcpy(&d->d_dg,dg,sizeof(struct disk_geom));
/*
* command line geometry overrides
*/
if (gc) d->d_dg.d_c = gc;
if (gh) d->d_dg.d_h = gh;
if (gs) d->d_dg.d_s = gs;
}
else
{
d->d_dg.d_c = gc;
d->d_dg.d_h = gh;
d->d_dg.d_s = gs;
}
if (d->d_dg.d_c < 1024) d->d_dosc = 1;
if ((d->d_dg.d_h > 16) || (d->d_dg.d_s > 63)) d->d_lba = 1;
d->d_nsecs = d->d_dg.d_c;
d->d_nsecs *= d->d_dg.d_h;
d->d_nsecs *= d->d_dg.d_s;
read_ext_part_table(d,&d->d_pt);
close(d->d_fd);
free((void *)ubuf);
return (d);
}
static void add_guessed_p(disk_desc *d,dos_part_entry *p,int cnt)
{
dos_guessed_pt *gpt;
if (d->d_gl == 0)
gpt = d->d_gl = (dos_guessed_pt *)alloc(sizeof(dos_guessed_pt));
else
{
for (gpt = d->d_gl; gpt->g_next; gpt = gpt->g_next)
;
gpt->g_next = (dos_guessed_pt *)alloc(sizeof(dos_guessed_pt));
gpt = gpt->g_next;
}
gpt->g_ext = (cnt > 1);
for ( ; cnt > 0; cnt--)
memcpy(&gpt->g_p[cnt-1],&p[cnt-1],sizeof(dos_part_entry));
gpt->g_sec = d->d_nsb;
}
static g_module *get_best_guess(g_module **g,int count)
{
int mx, i;
float bestg = 0.0;
/*
* up to now the best guess is simple that one which
* reported the largest probability (if there are more
* than one, the last one of them).
*/
for (mx = i = 0; i < count; i++)
if (g[i]->m_guess * g[i]->m_weight > bestg)
bestg = g[mx = i]->m_guess * g[i]->m_weight;
return ((bestg > 0.0) ? g[mx] : 0);
}
static int mod_is_aligned(disk_desc *d,g_module *m)
{
s64_t al;
switch (m->m_align)
{
case 'h' :
return (on_head_boundary(d,d->d_nsb));
case 'c' :
return (on_cyl_boundary(d,d->d_nsb));
case 1 :
case 's' :
return (1);
default :
if (m->m_align > 0)
{
al = d->d_nsb; al %= m->m_align;
return (al == 0);
}
break;
}
return (1);
}
/*
* the main guessing loop.
*/
static void do_guess_loop(disk_desc *d)
{
g_module *m, **guesses;
unsigned long incr = 0;
int nsecs, in_ext = 0, end_of_ext = 0, psize;
ssize_t rd, bsize = d->d_ssize;
s64_t bincr, noffset, start;
byte_t *ubuf;
if ((d->d_fd = open(d->d_dev,O_RDONLY)) == -1)
pr(FATAL,EM_OPENFAIL,d->d_dev,strerror(errno));
/*
* initialize modules. Each should return the minimum
* size in bytes it wants to receive for a test.
*/
for (m = g_mod_head(); m; m = m->m_next)
if (m->m_init)
{
int sz;
if ((sz = (*m->m_init)(d,m)) <= 0)
pr(ERROR,EM_MINITFAILURE,m->m_name);
bsize = max(sz,bsize);
}
if (bsize % d->d_ssize)
bsize += d->d_ssize - bsize % d->d_ssize;
nsecs = bsize / d->d_ssize;
switch (increment)
{
case 's' : incr = 1; break;
case 'h' : incr = d->d_dg.d_s; break;
case 'c' : incr = d->d_dg.d_s * d->d_dg.d_h; break;
default : incr = increment; break;
}
if (incr == 0)
incr = 1;
boundary_fun = (incr == 1) ? on_head_boundary : on_cyl_boundary;
psize = getpagesize();
ubuf = alloc(bsize + psize);
d->d_sbuf = align(ubuf,psize);
d->d_nsb = 0;
bincr = incr * d->d_ssize;
start = skipsec ? skipsec : d->d_dg.d_s;
d->d_nsb = start - incr;
start *= d->d_ssize;
if (l64seek(d->d_fd,start,SEEK_SET) == -1)
pr(FATAL,EM_SEEKFAILURE,d->d_dev);
/*
* do the work: read blocks, distribute to modules, check
* for probable hits.
*/
guesses = (g_module **)alloc(g_mod_count() * sizeof(g_module *));
pr(MSG,DM_STARTSCAN);
scanloop:
while ((rd = bread(d->d_fd,d->d_sbuf,d->d_ssize,nsecs)) == bsize)
{
int mod, have_ext = 0;
g_module *bg;
s64_t sz, ofs;
d->d_nsb += incr; noffset = 0;
ofs = d->d_nsb; s2mb(d,ofs);
if (maxsec && (d->d_nsb > maxsec)) break;
/*
* reset modules
*/
for (m = g_mod_head(); m; m = m->m_next)
m->m_skip = 0;
guessit:
bg = 0; mod = 0;
for (m = g_mod_head(); m; m = m->m_next)
{
if (m->m_skip || (in_ext && m->m_notinext) || !mod_is_aligned(d,m))
continue;
/*
* because a gmodule is allowed to seek on
* d->d_fd the current file position must be
* saved.
*/
memset(&m->m_part,0,sizeof(dos_part_entry));
m->m_guess = GM_NO; l64opush(d->d_fd);
if ((*m->m_gfun)(d,m) && (m->m_guess * m->m_weight >= GM_PERHAPS))
guesses[mod++] = m;
if ((sz = l64opop(d->d_fd)) != l64tell(d->d_fd))
l64seek(d->d_fd,sz,SEEK_SET);
}
/*
* now fetch the best guess.
*/
if (mod && (bg = get_best_guess(guesses,mod)))
{
noffset = bg->m_part.p_size;
fillin_dos_chs(d,&bg->m_part,0);
}
/*
* extended partition begin?
*/
if (f_testext && boundary_fun(d,d->d_nsb) &&
(!bg || !bg->m_hasptbl) && is_ext_parttable(d,d->d_sbuf))
{
dos_part_entry *p;
int no_ext;
p = (dos_part_entry *)(d->d_sbuf + DOSPARTOFF);
no_ext = no_of_ext_partitions(p);
if (! in_ext)
{
pr(MSG,PM_POSSIBLEEXTPART,ofs);
in_ext = 1; end_of_ext = 0; noffset = 0;
}
else if (no_ext == 0)
end_of_ext = 1;
if (in_ext)
{
if (f_interactive)
{
if (yesno(DM_ACCEPTGUESS))
add_guessed_p(d,p,have_ext = NDOSPARTS);
else
if (mod && bg)
{
bg->m_skip = 1;
goto guessit;
}
}
else
add_guessed_p(d,p,have_ext = NDOSPARTS);
}
}
if (! have_ext && noffset)
{
sz = noffset; s2mb(d,sz);
if (in_ext) pr(MSG," ");
pr(MSG,PM_POSSIBLEPART,bg->m_desc ? bg->m_desc : bg->m_name,sz,ofs);
if (f_verbose)
print_partition(d,&bg->m_part,in_ext ? 1 : 0,0);
if (f_interactive)
if (! yesno(DM_ACCEPTGUESS))
{
noffset = 0;
if (mod && bg)
{
bg->m_skip = 1;
goto guessit;
}
}
if (noffset)
{
add_guessed_p(d,&bg->m_part,1);
if (end_of_ext) in_ext = 0;
}
}
/*
* seek to next sectors to investigate (may seek
* backwards).
*/
if (noffset && f_fast)
{
if (noffset % incr)
noffset += incr - noffset % incr;
d->d_nsb += noffset - incr;
noffset -= nsecs; noffset *= d->d_ssize;
if (l64seek(d->d_fd,noffset,SEEK_CUR) == -1)
pr(FATAL,EM_SEEKFAILURE,d->d_dev);
}
else if (bincr)
if (l64seek(d->d_fd,bincr - bsize,SEEK_CUR) == -1)
pr(FATAL,EM_SEEKFAILURE,d->d_dev);
}
/*
* short read?
*/
if ((rd > 0) && (rd < bsize))
if (d->d_nsb + nsecs + 1 < d->d_nsecs)
{
/*
* short read not at end of disk
*/
pr(f_skiperrors ? WARN : FATAL,EM_SHORTBREAD,d->d_nsb,rd,bsize);
noffset = l64tell(d->d_fd); noffset /= d->d_ssize;
noffset *= d->d_ssize;
if (l64seek(d->d_fd,noffset,SEEK_SET) == -1)
pr(FATAL,EM_SEEKFAILURE,d->d_dev);
d->d_nsb = l64tell(d->d_fd) / d->d_ssize - incr;
goto scanloop;
}
if (rd == -1)
{
/*
* EIO is ignored (skipping current sector(s))
*/
if (f_skiperrors && (berrno == EIO))
{
pr(WARN,EM_BADREADIO,d->d_nsb);
noffset = l64tell(d->d_fd); noffset /= d->d_ssize;
noffset += incr; noffset *= d->d_ssize;
if (l64seek(d->d_fd,noffset,SEEK_SET) == -1)
pr(FATAL,EM_SEEKFAILURE,d->d_dev);
d->d_nsb = l64tell(d->d_fd) / d->d_ssize - incr;
goto scanloop;
}
pr(FATAL,EM_READERROR,d->d_dev,d->d_nsb,strerror(berrno));
}
pr(MSG,DM_ENDSCAN);
if (guesses) free((void *)guesses);
for (m = g_mod_head(); m; m = m->m_next)
if (m->m_term)
(*m->m_term)(d);
free((void *)ubuf);
close(d->d_fd);
}
static void edit_partition(disk_desc *d,dos_part_entry *p)
{
char ans[32];
int n;
unsigned long val;
while (1)
{
pr(MSG,DM_NOCHECKWARNING);
pr(MSG,PM_EDITITEM1,p->p_start);
pr(MSG,PM_EDITITEM2,p->p_size);
pr(MSG,PM_EDITITEM3,p->p_typ,get_part_type(p->p_typ));
if ((n = number_or_quit(DM_EDITWHICHITEM,1,3)) < 0)
break;
if ((n < 1) || (n > 3))
continue;
pr(MSG,"Enter value for %d : ",n);
if (fgets(ans,32,stdin))
{
val = strtoul(ans,0,0);
switch (n)
{
case 1:
p->p_start = val;
fillin_dos_chs(d,p,0);
break;
case 2:
p->p_size = val;
fillin_dos_chs(d,p,0);
break;
case 3:
p->p_typ = val & 0xFF;
break;
}
}
}
}
static int make_mbr_backup(disk_desc *d,char *bfile)
{
int fd, ret = 0;
if ((fd = open(bfile,O_WRONLY|O_CREAT)) < 0)
return (ret);
if (write(fd,d->d_pt.t_boot,512) == 512)
ret = 1;
close(fd);
return (ret);
}
static void write_primary_ptbl(disk_desc *d,char *dev)
{
struct stat sbuf;
byte_t *ptbl, *uptbl;
int fd, doesntexist = 0, n;
uptbl = alloc(d->d_ssize + getpagesize());
ptbl = align(uptbl,getpagesize());
if (stat(dev,&sbuf) == -1)
{
if (errno != ENOENT)
pr(FATAL,EM_STATFAILURE,dev,strerror(errno));
else
doesntexist = 1;
}
fd = open(dev,O_WRONLY | (doesntexist ? O_CREAT | O_EXCL : 0),0660);
if (fd == -1)
pr(FATAL,EM_OPENFAIL,dev,strerror(errno));
if (l64seek(fd,0,SEEK_SET) == -1)
pr(FATAL,EM_SEEKFAILURE,dev);
/*
* is there a guessed partition table?
*/
if (d->d_gpt.t_magic == le16(DOSPTMAGIC))
{
/*
* ask if table should be hand-edited
*/
if (yesno(DM_EDITPTBL))
while (1)
{
if ((n = number_or_quit(DM_EDITWHICHPART,1,NDOSPARTS)) < 0)
break;
if ((n >= 1) && (n <= NDOSPARTS))
edit_partition(d,&d->d_gpt.t_parts[n - 1]);
else
break;
print_ptable(d,&d->d_gpt,0);
}
/*
* ask for the active partition.
*/
while (1)
{
if ((n = number_or_quit(DM_ACTWHICHPART,1,NDOSPARTS)) < 0)
break;
if ((n >= 1) && (n <= NDOSPARTS) &&
get_part_type(d->d_gpt.t_parts[n].p_typ))
{
d->d_gpt.t_parts[n - 1].p_flag = DOSPARTACTIVE;
break;
}
}
if (yesno(DM_WRITEIT))
{
memcpy(ptbl,d->d_pt.t_boot,DOSPARTOFF);
memcpy(ptbl + DOSPARTOFF,d->d_gpt.t_parts,NDOSPARTS * sizeof(dos_part_entry) + 2);
if (write(fd,ptbl,d->d_ssize) != d->d_ssize)
pr(FATAL,EM_PTBLWRITE);
if (S_ISBLK(sbuf.st_mode) || S_ISCHR(sbuf.st_mode))
{
sync(); sleep(1); sync();
reread_partition_table(fd);
pr(WARN,DM_ASKTOREBOOT);
}
}
else
pr(MSG,DM_NOTWRITTEN);
}
close(fd);
free((void *)uptbl);
}
static void warn_invalid(disk_desc *d,dos_part_entry *p,char *w)
{
if (f_verbose > 1)
{
pr(MSG,EM_PINVALID,w);
print_partition(d,p,0,0);
}
}
/*
* after having gathered a list of possible partitions they
* have to be checked for consistency. This routine must be
* improved, it's too weird and is mistaken too often.
*/
static int check_partition_list(disk_desc *d)
{
dos_guessed_pt *gp, *prev;
dos_part_entry *p, *rp, *ep, *lep;
int n, npp, epp, maxp, in_ext;
s64_t size, ofs;
p = rp = ep = lep = 0;
pr(MSG,DM_STARTCHECK);
/*
* 1. pass: discard overlapping entries. This means
* that the first entry is assumed to be ok.
*/
ofs = 0; prev = 0; npp = 0;
for (gp = d->d_gl; gp; gp = gp->g_next)
{
if (gp->g_ext || gp->g_inv) continue;
p = &gp->g_p[0];
if (gp == d->d_gl)
ofs = p->p_start + p->p_size;
else
{
if (p->p_start < ofs)
{
/*
* overlap. unlink and discard.
*/
prev->g_next = gp->g_next;
free((void *)gp);
gp = prev; npp++;
}
else
ofs += p->p_size;
}
prev = gp;
}
if (npp)
pr(WARN,EM_DISCARDOVLP,npp);
/*
* 2. pass: decide type of every partition,
* marking inconsistent ones as invalid.
*/
size = 0;
in_ext = npp = epp = 0; maxp = NDOSPARTS;
for (n = 1, gp = d->d_gl; gp; gp = gp->g_next, n++)
{
if (gp->g_inv) continue;
if (gp->g_ext)
{
if (gp->g_next == 0)
{
/*
* ext ptbl without logical p.
*/
gp->g_inv = 1;
warn_invalid(d,p,EM_P_EATEND);
break;
}
if (! in_ext)
{
/*
* new extended p. chain.
*/
if (no_of_ext_partitions(gp->g_p) == 0)
{
gp->g_inv = 1;
warn_invalid(d,p,EM_P_EWLP);
continue;
}
in_ext = 1; epp++;
if (maxp >= NDOSPARTS) maxp--;
/*
* already had one?
*/
if (epp > 1)
{
gp->g_inv = 1;
warn_invalid(d,p,EM_P_MTOE);
continue;
}
}
if (no_of_ext_partitions(gp->g_p) == 0)
in_ext = 0;
rp = 0;
for (p = &gp->g_p[0]; p < &gp->g_p[NDOSPARTS]; p++)
{
if (is_real_parttype(p))
rp = p;
else if (is_ext_parttype(p) && (n == 1))
size = p->p_start;
}
gp = gp->g_next;
if (gp->g_ext)
{
/*
* should not happen: a supposedly logical
* partition which is an extended p itself.
*/
gp->g_inv = 1;
warn_invalid(d,p,EM_P_LISAE);
continue;
}
else
gp->g_log = 1;
/*
* the p. type in the extended ptbl and the following
* logical p. type must be identical. Also check size.
*/
p = &gp->g_p[0];
if (is_real_parttype(p) && is_same_partition_type(rp,p) &&
(rp->p_size >= p->p_size))
{
if (! is_sane_partentry(d,p,1))
gp->g_inv = 1;
else
size += gp->g_p[0].p_size + 1;
}
else
{
gp->g_inv = 1;
warn_invalid(d,p,EM_P_UTS);
}
}
else if (! in_ext)
{
/*
* primary entry.
*/
gp->g_prim = 1; p = &gp->g_p[0];
if (n == 1) size = p->p_start;
if (npp++ >= maxp)
{
gp->g_inv = 1;
warn_invalid(d,p,EM_P_2MANYPP);
}
else
{
if (! is_sane_partentry(d,p,1))
{
gp->g_inv = 1;
warn_invalid(d,p,EM_P_NOTSANE);
}
else
size += p->p_size;
}
}
else
{
/*
* in_ext && !gp->g_ext. This means the end
* of the logical partition chain hasn't been
* found. Reset it.
*/
in_ext = 0; gp->g_inv = 1;
warn_invalid(d,p,EM_P_ENDNOTF);
}
}
if (epp > 1)
pr(WARN,EM_TOOMANYXPTS,epp);
if (npp > maxp)
pr(WARN,EM_TOOMANYPPTS,maxp,npp);
/*
* 3. pass: check logical partition chain. Logical
* partitions which seem ok but are not found in the
* link chain are marked orphaned.
*/
in_ext = size = ofs = 0; lep = 0;
for (gp = d->d_gl; gp; gp = gp->g_next)
{
if (gp->g_inv) continue;
if (gp->g_ext)
{
if (! in_ext)
{
in_ext = 1; ofs = gp->g_sec;
}
rp = ep = 0;
for (p = &gp->g_p[0]; p < &gp->g_p[NDOSPARTS]; p++)
{
if (is_real_parttype(p))
rp = p;
else if (is_ext_parttype(p))
ep = p;
}
if (lep && rp)
if (gp->g_sec != ofs + lep->p_start)
gp->g_next->g_orph = 1;
if (ep) lep = ep;
gp = gp->g_next;
}
}
/*
* if the list was consistent the size of the whole
* extended ptbl is equal to the end of the last eptbl
* link.
*/
if (rp && lep)
size = lep->p_start + lep->p_size;
else
size = ofs = 0;
for (gp = d->d_gl; gp; gp = gp->g_next)
{
if (gp->g_ext) continue;
p = &gp->g_p[0];
if (gp->g_log) pr(MSG," ");
pr(MSG,"Partition(%s): ",get_part_type(p->p_typ));
if (gp->g_inv) pr(MSG,PM_G_INVALID);
if (gp->g_orph) pr(MSG,PM_G_ORPHANED);
if (gp->g_prim) pr(MSG,PM_G_PRIMARY);
if (gp->g_log) pr(MSG,PM_G_LOGICAL);
pr(MSG,"\n");
if (f_verbose > 1)
print_partition(d,p,gp->g_log ? 1 : 0,0);
}
/*
* now fill in the guessed primary partition table.
*/
in_ext = n = 0;
memset(&d->d_gpt,0,sizeof(dos_part_table));
for (gp = d->d_gl; gp; gp = gp->g_next)
{
if (n >= NDOSPARTS) break;
if (gp->g_inv) continue;
if (gp->g_ext)
{
if (! in_ext)
{
in_ext = 1;
if (size && ofs)
{
p = &d->d_gpt.t_parts[n++];
p->p_start = ofs;
p->p_typ = 0x05;
p->p_typ = d->d_lba ? 0x0F : 0x05;
p->p_size = size;
fillin_dos_chs(d,p,0);
}
}
gp = gp->g_next;
continue;
}
if (gp->g_prim)
memcpy(&d->d_gpt.t_parts[n++],&gp->g_p[0],sizeof(dos_part_entry));
}
/*
* final step: re-check this table. If ok, set the
* ptbl magic number which is the indicator for
* write_primary_ptbl that it seems to be ok.
*/
ep = 0; npp = 0;
for (n = 0; n < NDOSPARTS; n++)
{
p = &d->d_gpt.t_parts[n];
if (ep && p->p_typ)
{
if ((ep->p_start + ep->p_size > p->p_start) ||
! is_sane_partentry(d,p,1))
{
/*
* zis is not funny. Perhaps the p. list
* can be re-checked but for now only
* inconsistencies are counted.
*/
npp++;
if (f_verbose > 2)
{
pr(WARN,EM_PINCONS);
print_partition(d,p,0,0);
}
}
}
ep = p;
}
if (npp == 0)
{
d->d_gpt.t_magic = le16(DOSPTMAGIC);
pr(MSG,"Ok.\n");
}
else
pr(MSG,DM_NOOFINCONS,npp);
return (npp);
}
/*
* compare both existing and guessed partition tables.
* The order of the ptbl entries is not important (the
* physically first partition on disk can be in the last
* ptbl slot).
*/
static int compare_parttables(disk_desc *d)
{
int ret, i, j, diff;
byte_t *pr, *pg;
ret = 0;
for (i = 0; i < NDOSPARTS; i++)
{
pr = (byte_t *)&d->d_pt.t_parts[i];
for (j = 0; j < NDOSPARTS; j++)
{
pg = (byte_t *)&d->d_gpt.t_parts[j];
/*
* the p_flag entry cannot be included
* in the comparison.
*/
diff = memcmp(pr + 1,pg + 1,sizeof(dos_part_entry) - 1);
if (diff == 0) break;
}
if (diff) ret++;
}
return (ret);
}
/*
* main
*/
int main(int ac,char **av)
{
char *optstr = "b:C:cdEefghiK:k:Ll:n:qs:t:VvW:w:";
char *p1, *p2, *p3, *odev = 0, *backup = 0;
int opt, sectsize = 0, no_of_incons = 0;
disk_desc *d;
g_mod_addinternals();
while ((opt = getopt(ac,av,optstr)) != -1)
switch (opt)
{
case 'b' :
backup = optarg; break;
case 'C' :
if (! get_csep_arg(optarg,&p1,&p2,&p3))
{
usage();
return (EXIT_FAILURE);
}
gc = strtoul(p1,0,0);
if (errno == ERANGE) pr(FATAL,EM_INVVALUE);
gh = strtoul(p2,0,0);
if (errno == ERANGE) pr(FATAL,EM_INVVALUE);
gs = strtoul(p3,0,0);
if (errno == ERANGE) pr(FATAL,EM_INVVALUE);
break;
case 'c' :
f_check = 1; break;
case 'd' :
f_dontguess = 1; break;
case 'E' :
f_testext = 0; break;
case 'e' :
f_skiperrors = 0; break;
case 'f' :
f_fast = 0; break;
case 'g' :
f_getgeom = 0; break;
case 'i' :
f_interactive = 1; break;
case 'K' :
maxsec = strtoul(optarg,0,0);
if ((maxsec <= 0) || (errno == ERANGE))
pr(FATAL,EM_INVVALUE);
break;
case 'k' :
/* strtos64? */
skipsec = strtoul(optarg,0,0);
if (errno == ERANGE) pr(FATAL,EM_INVVALUE);
break;
case 'n' :
if ((*optarg == 's') || (*optarg == 'h') ||
(*optarg == 'c'))
increment = *optarg;
else
{
increment = strtoul(optarg,0,0);
if (errno == ERANGE)
pr(FATAL,EM_INVVALUE);
}
break;
case 'l' :
if (log) fclose(log);
if ((log = fopen(optarg,"w")) == 0)
pr(FATAL,EM_OPENLOG,optarg);
break;
case 'L' :
g_mod_list();
return (EXIT_SUCCESS);
case 'q' :
f_quiet = 1; break;
case 's' :
if ((sectsize = atoi(optarg)) <= 0)
pr(FATAL,"sector size must be >= 0");
break;
case 't' :
if (! g_mod_addexternal(optarg))
return (EXIT_FAILURE);
break;
case 'v' :
f_verbose++; break;
case 'V' :
fprintf(stderr,"%s\n",gpart_version);
return (EXIT_SUCCESS);
case 'w' :
if (! get_csep_arg(optarg,&p1,&p2,0))
{
usage();
return (EXIT_FAILURE);
}
if (! g_mod_setweight(p1,atof(p2)))
pr(FATAL,EM_NOSUCHMOD,p1);
break;
case 'W' :
odev = optarg;
break;
case '?' :
case 'h' :
default :
usage(); return (EXIT_FAILURE);
}
if ((optind + 1) != ac)
{
usage();
return (EXIT_FAILURE);
}
if (f_dontguess) f_check = 0;
if (f_check)
{
f_quiet = 1;
f_dontguess = 0;
odev = 0;
}
if (f_quiet)
f_interactive = 0;
sync(); d = get_disk_desc(av[optind],sectsize);
if (f_verbose > 0)
print_disk_desc(d);
if (f_verbose > 2)
print_mboot_block(d);
if (! f_dontguess)
{
sleep(1); sync();
do_guess_loop(d);
no_of_incons = check_partition_list(d);
pr(MSG,DM_GUESSEDPTBL);
print_ptable(d,&d->d_gpt,0);
if ((no_of_incons == 0) && f_check)
no_of_incons = compare_parttables(d);
if ((no_of_incons == 0) && odev)
{
if (backup)
make_mbr_backup(d,backup);
write_primary_ptbl(d,odev);
}
}
free_disk_desc(d);
if (log) fclose(log);
return (f_check ? no_of_incons : 0);
}
syntax highlighted by Code2HTML, v. 0.9.1