2016-11-25 17:18:40 +01:00
|
|
|
/*
|
|
|
|
* This file is part of the UCB release of Plan 9. It is subject to the license
|
|
|
|
* terms in the LICENSE file found in the top-level directory of this
|
|
|
|
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
|
|
|
* part of the UCB release of Plan 9, including this file, may be copied,
|
|
|
|
* modified, propagated, or distributed except according to the terms contained
|
|
|
|
* in the LICENSE file.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* fdisk - edit dos disk partition table
|
|
|
|
*/
|
|
|
|
#include <u.h>
|
2017-04-19 23:33:14 +02:00
|
|
|
#include <lib9.h>
|
2016-11-25 17:18:40 +01:00
|
|
|
#include <bio.h>
|
2020-09-13 02:21:36 +02:00
|
|
|
#include <chartypes.h>
|
2016-11-25 17:18:40 +01:00
|
|
|
#include <disk.h>
|
|
|
|
#include "edit.h"
|
|
|
|
|
|
|
|
typedef struct Dospart Dospart;
|
|
|
|
enum {
|
|
|
|
NTentry = 4,
|
|
|
|
Mpart = 64,
|
|
|
|
};
|
|
|
|
|
|
|
|
static void rdpart(Edit*, uint64_t, uint64_t);
|
|
|
|
static void findmbr(Edit*);
|
|
|
|
static void autopart(Edit*);
|
|
|
|
static void wrpart(Edit*);
|
|
|
|
static void blankpart(Edit*);
|
|
|
|
static void recover(Edit*);
|
|
|
|
static int Dfmt(Fmt*);
|
|
|
|
static int blank;
|
|
|
|
static int dowrite;
|
|
|
|
static int file;
|
|
|
|
static int rdonly;
|
|
|
|
static int doauto;
|
|
|
|
static int64_t mbroffset;
|
|
|
|
static int printflag;
|
|
|
|
static int printchs;
|
|
|
|
static int sec2cyl;
|
|
|
|
static int written;
|
|
|
|
|
|
|
|
static void cmdsum(Edit*, Part*, int64_t, int64_t);
|
|
|
|
static char *cmdadd(Edit*, char*, int64_t, int64_t);
|
|
|
|
static char *cmddel(Edit*, Part*);
|
|
|
|
static char *cmdext(Edit*, int, char**);
|
|
|
|
static char *cmdhelp(Edit*);
|
|
|
|
static char *cmdokname(Edit*, char*);
|
|
|
|
static char *cmdwrite(Edit*);
|
|
|
|
static void cmdprintctl(Edit*, int);
|
|
|
|
|
|
|
|
#pragma varargck type "D" uchar*
|
|
|
|
|
|
|
|
Edit edit = {
|
|
|
|
.add= cmdadd,
|
|
|
|
.del= cmddel,
|
|
|
|
.ext= cmdext,
|
|
|
|
.help= cmdhelp,
|
|
|
|
.okname= cmdokname,
|
|
|
|
.sum= cmdsum,
|
|
|
|
.write= cmdwrite,
|
|
|
|
.printctl= cmdprintctl,
|
|
|
|
|
|
|
|
.unit= "cylinder",
|
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Catch the obvious error routines to fix up the disk.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
sysfatal(const char *fmt, ...)
|
|
|
|
{
|
|
|
|
char buf[1024];
|
|
|
|
va_list arg;
|
|
|
|
|
|
|
|
va_start(arg, fmt);
|
|
|
|
vseprint(buf, buf+sizeof(buf), fmt, arg);
|
|
|
|
va_end(arg);
|
|
|
|
if(argv0)
|
|
|
|
fprint(2, "%s: %s\n", argv0, buf);
|
|
|
|
else
|
|
|
|
fprint(2, "%s\n", buf);
|
|
|
|
|
|
|
|
if(written)
|
|
|
|
recover(&edit);
|
|
|
|
|
|
|
|
exits(buf);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
recoverOnAbort(void)
|
|
|
|
{
|
|
|
|
fprint(2, "abort\n");
|
|
|
|
recover(&edit);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
usage(void)
|
|
|
|
{
|
|
|
|
fprint(2, "usage: disk/fdisk [-abfprvw] [-s sectorsize] /dev/sdC0/data\n");
|
|
|
|
exits("usage");
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
main(int argc, char **argv)
|
|
|
|
{
|
|
|
|
int64_t secsize;
|
|
|
|
|
|
|
|
_abort = recoverOnAbort;
|
|
|
|
secsize = 0;
|
|
|
|
ARGBEGIN{
|
|
|
|
case 'a':
|
|
|
|
doauto++;
|
|
|
|
break;
|
|
|
|
case 'b':
|
|
|
|
blank++;
|
|
|
|
break;
|
|
|
|
case 'f':
|
|
|
|
file++;
|
|
|
|
break;
|
|
|
|
case 'p':
|
|
|
|
printflag++;
|
|
|
|
break;
|
|
|
|
case 'r':
|
|
|
|
rdonly++;
|
|
|
|
break;
|
|
|
|
case 's':
|
|
|
|
secsize = atoi(ARGF());
|
|
|
|
break;
|
|
|
|
case 'v':
|
|
|
|
printchs++;
|
|
|
|
break;
|
|
|
|
case 'w':
|
|
|
|
dowrite++;
|
|
|
|
break;
|
|
|
|
}ARGEND;
|
|
|
|
|
|
|
|
fmtinstall('D', Dfmt);
|
|
|
|
|
|
|
|
if(argc != 1)
|
|
|
|
usage();
|
|
|
|
|
|
|
|
edit.disk = opendisk(argv[0], rdonly, file);
|
|
|
|
if(edit.disk == nil) {
|
|
|
|
fprint(2, "cannot open disk: %r\n");
|
|
|
|
exits("opendisk");
|
|
|
|
}
|
|
|
|
|
|
|
|
if(secsize != 0) {
|
|
|
|
edit.disk->secsize = secsize;
|
|
|
|
edit.disk->secs = edit.disk->size / secsize;
|
|
|
|
}
|
|
|
|
|
|
|
|
sec2cyl = edit.disk->h * edit.disk->s;
|
|
|
|
edit.end = edit.disk->secs / sec2cyl;
|
|
|
|
|
|
|
|
findmbr(&edit);
|
|
|
|
|
|
|
|
if(blank)
|
|
|
|
blankpart(&edit);
|
|
|
|
else
|
|
|
|
rdpart(&edit, 0, 0);
|
|
|
|
|
|
|
|
if(doauto)
|
|
|
|
autopart(&edit);
|
|
|
|
|
|
|
|
if(dowrite)
|
|
|
|
runcmd(&edit, (char[]){"w"});
|
|
|
|
|
|
|
|
if(printflag)
|
|
|
|
runcmd(&edit, (char[]){"P"});
|
|
|
|
|
|
|
|
if(dowrite || printflag)
|
|
|
|
exits(0);
|
|
|
|
|
|
|
|
fprint(2, "cylinder = %lld bytes\n", sec2cyl*edit.disk->secsize);
|
|
|
|
runcmd(&edit, (char[]){"p"});
|
|
|
|
for(;;) {
|
|
|
|
fprint(2, ">>> ");
|
|
|
|
runcmd(&edit, getline(&edit));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
typedef struct Tentry Tentry;
|
|
|
|
typedef struct Table Table;
|
|
|
|
typedef struct Type Type;
|
|
|
|
typedef struct Tab Tab;
|
|
|
|
typedef struct Recover Recover;
|
|
|
|
|
|
|
|
struct Tentry {
|
|
|
|
uint8_t active; /* active flag */
|
|
|
|
uint8_t starth; /* starting head */
|
|
|
|
uint8_t starts; /* starting sector */
|
|
|
|
uint8_t startc; /* starting cylinder */
|
|
|
|
uint8_t type; /* partition type */
|
|
|
|
uint8_t endh; /* ending head */
|
|
|
|
uint8_t ends; /* ending sector */
|
|
|
|
uint8_t endc; /* ending cylinder */
|
|
|
|
uint8_t xlba[4]; /* starting LBA from beginning of disc or ext. partition */
|
|
|
|
uint8_t xsize[4]; /* size in sectors */
|
|
|
|
};
|
|
|
|
|
|
|
|
struct Table {
|
|
|
|
Tentry entry[NTentry];
|
|
|
|
uint8_t magic[2];
|
|
|
|
uint8_t size[];
|
|
|
|
};
|
|
|
|
|
|
|
|
enum {
|
|
|
|
Active = 0x80, /* partition is active */
|
|
|
|
Primary = 0x01, /* internal flag */
|
|
|
|
|
|
|
|
TypeBB = 0xFF,
|
|
|
|
|
|
|
|
TypeEMPTY = 0x00,
|
|
|
|
TypeFAT12 = 0x01,
|
|
|
|
TypeXENIX = 0x02, /* root */
|
|
|
|
TypeXENIXUSR = 0x03, /* usr */
|
|
|
|
TypeFAT16 = 0x04,
|
|
|
|
TypeEXTENDED = 0x05,
|
|
|
|
TypeFATHUGE = 0x06,
|
|
|
|
TypeHPFS = 0x07,
|
|
|
|
TypeAIXBOOT = 0x08,
|
|
|
|
TypeAIXDATA = 0x09,
|
|
|
|
TypeOS2BOOT = 0x0A, /* OS/2 Boot Manager */
|
|
|
|
TypeFAT32 = 0x0B, /* FAT 32 */
|
|
|
|
TypeFAT32LBA = 0x0C, /* FAT 32 needing LBA support */
|
|
|
|
TypeFAT16X = 0x0E, /* FAT 16 needing LBA support */
|
|
|
|
TypeEXTHUGE = 0x0F, /* FAT 32 extended partition */
|
|
|
|
TypeUNFORMATTED = 0x16, /* unformatted primary partition (OS/2 FDISK)? */
|
|
|
|
TypeHPFS2 = 0x17,
|
|
|
|
TypeIBMRecovery = 0x1C, /* really hidden fat */
|
|
|
|
TypeCPM0 = 0x52,
|
|
|
|
TypeDMDDO = 0x54, /* Disk Manager Dynamic Disk Overlay */
|
|
|
|
TypeGB = 0x56, /* ???? */
|
|
|
|
TypeSPEEDSTOR = 0x61,
|
|
|
|
TypeSYSV386 = 0x63, /* also HURD? */
|
|
|
|
TypeNETWARE = 0x64,
|
|
|
|
TypePCIX = 0x75,
|
|
|
|
TypeMINIX13 = 0x80, /* Minix v1.3 and below */
|
|
|
|
TypeMINIX = 0x81, /* Minix v1.5+ */
|
|
|
|
TypeLINUXSWAP = 0x82,
|
|
|
|
TypeLINUX = 0x83,
|
|
|
|
TypeLINUXEXT = 0x85,
|
|
|
|
TypeLINUXLVM = 0x8E, /* logical volume manager */
|
|
|
|
TypeAMOEBA = 0x93,
|
|
|
|
TypeAMOEBABB = 0x94,
|
|
|
|
TypeBSD386 = 0xA5,
|
|
|
|
TypeNETBSD = 0xA9,
|
|
|
|
TypeBSDI = 0xB7,
|
|
|
|
TypeBSDISWAP = 0xB8,
|
|
|
|
TypeOTHER = 0xDA,
|
|
|
|
TypeCPM = 0xDB,
|
|
|
|
TypeDellRecovery= 0xDE,
|
|
|
|
TypeSPEEDSTOR12 = 0xE1,
|
|
|
|
TypeSPEEDSTOR16 = 0xE4,
|
|
|
|
TypeEFIProtect = 0xEE,
|
|
|
|
TypeEFI = 0xEF,
|
|
|
|
TypeLANSTEP = 0xFE,
|
|
|
|
|
|
|
|
Type9 = 0x39,
|
|
|
|
|
|
|
|
Toffset = 446, /* offset of partition table in sector */
|
|
|
|
Magic0 = 0x55,
|
|
|
|
Magic1 = 0xAA,
|
|
|
|
|
|
|
|
Tablesz = offsetof(Table, size[0]),
|
|
|
|
};
|
|
|
|
|
|
|
|
struct Type {
|
|
|
|
char *desc;
|
|
|
|
char *name;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct Dospart {
|
|
|
|
Part;
|
|
|
|
Tentry;
|
|
|
|
|
|
|
|
uint32_t lba;
|
|
|
|
uint32_t size;
|
|
|
|
int primary;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct Recover {
|
|
|
|
Table table;
|
|
|
|
uint32_t lba;
|
|
|
|
};
|
|
|
|
|
|
|
|
static Type types[256] = {
|
|
|
|
[TypeEMPTY] { "EMPTY", "" },
|
|
|
|
[TypeFAT12] { "FAT12", "dos" },
|
|
|
|
[TypeFAT16] { "FAT16", "dos" },
|
|
|
|
[TypeFAT32] { "FAT32", "dos" },
|
|
|
|
[TypeFAT32LBA] { "FAT32LBA", "dos" },
|
|
|
|
[TypeFAT16X] { "FAT16X", "dos" },
|
|
|
|
[TypeEXTHUGE] { "EXTHUGE", "" },
|
|
|
|
[TypeIBMRecovery] { "IBMRECOVERY", "ibm" },
|
|
|
|
[TypeEXTENDED] { "EXTENDED", "" },
|
|
|
|
[TypeFATHUGE] { "FATHUGE", "dos" },
|
|
|
|
[TypeBB] { "BB", "bb" },
|
|
|
|
|
|
|
|
[TypeXENIX] { "XENIX", "xenix" },
|
|
|
|
[TypeXENIXUSR] { "XENIX USR", "xenixusr" },
|
|
|
|
[TypeHPFS] { "HPFS", "ntfs" },
|
|
|
|
[TypeAIXBOOT] { "AIXBOOT", "aixboot" },
|
|
|
|
[TypeAIXDATA] { "AIXDATA", "aixdata" },
|
|
|
|
[TypeOS2BOOT] { "OS/2BOOT", "os2boot" },
|
|
|
|
[TypeUNFORMATTED] { "UNFORMATTED", "" },
|
|
|
|
[TypeHPFS2] { "HPFS2", "hpfs2" },
|
|
|
|
[TypeCPM0] { "CPM0", "cpm0" },
|
|
|
|
[TypeDMDDO] { "DMDDO", "dmdd0" },
|
|
|
|
[TypeGB] { "GB", "gb" },
|
|
|
|
[TypeSPEEDSTOR] { "SPEEDSTOR", "speedstor" },
|
|
|
|
[TypeSYSV386] { "SYSV386", "sysv386" },
|
|
|
|
[TypeNETWARE] { "NETWARE", "netware" },
|
|
|
|
[TypePCIX] { "PCIX", "pcix" },
|
|
|
|
[TypeMINIX13] { "MINIXV1.3", "minix13" },
|
|
|
|
[TypeMINIX] { "MINIXV1.5", "minix15" },
|
|
|
|
[TypeLINUXSWAP] { "LINUXSWAP", "linuxswap" },
|
|
|
|
[TypeLINUX] { "LINUX", "linux" },
|
|
|
|
[TypeLINUXEXT] { "LINUXEXTENDED", "" },
|
|
|
|
[TypeLINUXLVM] { "LINUXLVM", "linuxlvm" },
|
|
|
|
[TypeAMOEBA] { "AMOEBA", "amoeba" },
|
|
|
|
[TypeAMOEBABB] { "AMOEBABB", "amoebaboot" },
|
|
|
|
[TypeBSD386] { "BSD386", "bsd386" },
|
|
|
|
[TypeNETBSD] { "NETBSD", "netbsd" },
|
|
|
|
[TypeBSDI] { "BSDI", "bsdi" },
|
|
|
|
[TypeBSDISWAP] { "BSDISWAP", "bsdiswap" },
|
|
|
|
[TypeOTHER] { "OTHER", "other" },
|
|
|
|
[TypeCPM] { "CPM", "cpm" },
|
|
|
|
[TypeDellRecovery] { "DELLRECOVERY", "dell" },
|
|
|
|
[TypeSPEEDSTOR12] { "SPEEDSTOR12", "speedstor" },
|
|
|
|
[TypeSPEEDSTOR16] { "SPEEDSTOR16", "speedstor" },
|
|
|
|
[TypeEFIProtect] { "EFIPROTECT", "efiprotect" },
|
|
|
|
[TypeEFI] { "EFI", "efi" },
|
|
|
|
[TypeLANSTEP] { "LANSTEP", "lanstep" },
|
|
|
|
|
|
|
|
[Type9] { "PLAN9", "plan9" },
|
|
|
|
};
|
|
|
|
|
|
|
|
static int npart;
|
|
|
|
|
|
|
|
static char*
|
|
|
|
typestr0(int type)
|
|
|
|
{
|
|
|
|
static char buf[100];
|
|
|
|
|
|
|
|
sprint(buf, "type %d", type);
|
|
|
|
if(type < 0 || type >= 256)
|
|
|
|
return buf;
|
|
|
|
if(types[type].desc == nil)
|
|
|
|
return buf;
|
|
|
|
return types[type].desc;
|
|
|
|
}
|
|
|
|
|
|
|
|
static uint32_t
|
|
|
|
getle32(void* v)
|
|
|
|
{
|
|
|
|
uint8_t *p;
|
|
|
|
|
|
|
|
p = v;
|
|
|
|
return (p[3]<<24)|(p[2]<<16)|(p[1]<<8)|p[0];
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
putle32(void* v, uint32_t i)
|
|
|
|
{
|
|
|
|
uint8_t *p;
|
|
|
|
|
|
|
|
p = v;
|
|
|
|
p[0] = i;
|
|
|
|
p[1] = i>>8;
|
|
|
|
p[2] = i>>16;
|
|
|
|
p[3] = i>>24;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
diskread(Disk *disk, void *data, int ndata, uint32_t sec, uint32_t off)
|
|
|
|
{
|
2019-11-26 02:25:23 +01:00
|
|
|
if(sys_seek(disk->fd, (int64_t)sec*disk->secsize+off, 0) != (int64_t)sec*disk->secsize+off)
|
2016-11-25 17:18:40 +01:00
|
|
|
sysfatal("diskread seek %lud.%lud: %r", (uint32_t)sec,
|
|
|
|
(uint32_t)off);
|
|
|
|
if(readn(disk->fd, data, ndata) != ndata)
|
|
|
|
sysfatal("diskread %lud at %lud.%lud: %r", (uint32_t)ndata,
|
|
|
|
(uint32_t)sec, (uint32_t)off);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
diskwrite(Disk *disk, void *data, int ndata, uint32_t sec, uint32_t off)
|
|
|
|
{
|
|
|
|
written = 1;
|
2019-11-26 02:25:23 +01:00
|
|
|
if(sys_seek(disk->wfd, (int64_t)sec*disk->secsize+off, 0) != (int64_t)sec*disk->secsize+off)
|
2016-11-25 17:18:40 +01:00
|
|
|
goto Error;
|
2019-11-26 02:25:23 +01:00
|
|
|
if(jehanne_write(disk->wfd, data, ndata) != ndata)
|
2016-11-25 17:18:40 +01:00
|
|
|
goto Error;
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
Error:
|
|
|
|
fprint(2, "write %d bytes at %lud.%lud failed: %r\n", ndata,
|
|
|
|
(uint32_t)sec, (uint32_t)off);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static Dospart*
|
|
|
|
mkpart(char *name, int primary, int64_t lba, int64_t size, Tentry *t)
|
|
|
|
{
|
|
|
|
static int n;
|
|
|
|
Dospart *p;
|
|
|
|
|
|
|
|
p = emalloc(sizeof(*p));
|
|
|
|
if(name)
|
|
|
|
p->name = estrdup(name);
|
|
|
|
else{
|
|
|
|
p->name = emalloc(20);
|
|
|
|
sprint(p->name, "%c%d", primary ? 'p' : 's', ++n);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(t)
|
|
|
|
p->Tentry = *t;
|
|
|
|
else
|
|
|
|
memset(&p->Tentry, 0, sizeof(Tentry));
|
|
|
|
|
|
|
|
p->changed = 0;
|
|
|
|
p->start = lba/sec2cyl;
|
|
|
|
p->end = (lba+size)/sec2cyl;
|
|
|
|
p->ctlstart = lba;
|
|
|
|
p->ctlend = lba+size;
|
|
|
|
p->lba = lba;
|
|
|
|
if (p->lba != lba)
|
|
|
|
fprint(2, "%s: start of partition (%lld) won't fit in MBR table\n", argv0, lba);
|
|
|
|
p->size = size;
|
|
|
|
if (p->size != size)
|
|
|
|
fprint(2, "%s: size of partition (%lld) won't fit in MBR table\n", argv0, size);
|
|
|
|
p->primary = primary;
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Recovery takes care of remembering what the various tables
|
|
|
|
* looked like when we started, attempting to restore them when
|
|
|
|
* we are finished.
|
|
|
|
*/
|
|
|
|
static Recover *rtab;
|
|
|
|
static int nrtab;
|
|
|
|
|
|
|
|
static void
|
|
|
|
addrecover(Table t, uint32_t lba)
|
|
|
|
{
|
|
|
|
if((nrtab%8) == 0) {
|
|
|
|
rtab = realloc(rtab, (nrtab+8)*sizeof(rtab[0]));
|
|
|
|
if(rtab == nil)
|
|
|
|
sysfatal("out of memory");
|
|
|
|
}
|
|
|
|
rtab[nrtab] = (Recover){t, lba};
|
|
|
|
nrtab++;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
recover(Edit *edit)
|
|
|
|
{
|
|
|
|
int err, i, ctlfd;
|
|
|
|
int64_t offset;
|
|
|
|
|
|
|
|
err = 0;
|
|
|
|
for(i=0; i<nrtab; i++)
|
|
|
|
if(diskwrite(edit->disk, &rtab[i].table, Tablesz, rtab[i].lba, Toffset) < 0)
|
|
|
|
err = 1;
|
|
|
|
if(err) {
|
|
|
|
fprint(2, "warning: some writes failed during restoration of old partition tables\n");
|
|
|
|
exits("inconsistent");
|
|
|
|
} else {
|
|
|
|
fprint(2, "restored old partition tables\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
ctlfd = edit->disk->ctlfd;
|
|
|
|
offset = edit->disk->offset;
|
|
|
|
if(ctlfd >= 0){
|
|
|
|
for(i=0; i<edit->npart; i++)
|
|
|
|
if(edit->part[i]->ctlname && fprint(ctlfd, "delpart %s", edit->part[i]->ctlname)<0)
|
|
|
|
fprint(2, "delpart failed: %s: %r", edit->part[i]->ctlname);
|
|
|
|
for(i=0; i<edit->nctlpart; i++)
|
|
|
|
if(edit->part[i]->name && fprint(ctlfd, "delpart %s", edit->ctlpart[i]->name)<0)
|
|
|
|
fprint(2, "delpart failed: %s: %r", edit->ctlpart[i]->name);
|
|
|
|
for(i=0; i<edit->nctlpart; i++){
|
|
|
|
if(fprint(ctlfd, "part %s %lld %lld", edit->ctlpart[i]->name,
|
|
|
|
edit->ctlpart[i]->start+offset, edit->ctlpart[i]->end+offset) < 0){
|
|
|
|
fprint(2, "restored disk partition table but not kernel; reboot\n");
|
|
|
|
exits("inconsistent");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
exits("restored");
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Read the partition table (including extended partition tables)
|
|
|
|
* from the disk into the part array.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
rdpart(Edit *edit, uint64_t lba, uint64_t xbase)
|
|
|
|
{
|
|
|
|
char *err;
|
|
|
|
Table table;
|
|
|
|
Tentry *tp, *ep;
|
|
|
|
Dospart *p;
|
|
|
|
|
|
|
|
if(xbase == 0)
|
|
|
|
xbase = lba;
|
|
|
|
|
|
|
|
diskread(edit->disk, &table, Tablesz, mbroffset+lba, Toffset);
|
|
|
|
addrecover(table, mbroffset+lba);
|
|
|
|
|
|
|
|
if(table.magic[0] != Magic0 || table.magic[1] != Magic1) {
|
|
|
|
assert(lba != 0);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
for(tp=table.entry, ep=tp+NTentry; tp<ep && npart < Mpart; tp++) {
|
|
|
|
switch(tp->type) {
|
|
|
|
case TypeEMPTY:
|
|
|
|
break;
|
|
|
|
case TypeEXTENDED:
|
|
|
|
case TypeEXTHUGE:
|
|
|
|
case TypeLINUXEXT:
|
|
|
|
rdpart(edit, xbase+getle32(tp->xlba), xbase);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
p = mkpart(nil, lba==0, lba+getle32(tp->xlba), getle32(tp->xsize), tp);
|
|
|
|
if(err = addpart(edit, p))
|
|
|
|
fprint(2, "adding partition: %s\n", err);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
blankpart(Edit *edit)
|
|
|
|
{
|
|
|
|
edit->changed = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
findmbr(Edit *edit)
|
|
|
|
{
|
|
|
|
Table table;
|
|
|
|
Tentry *tp;
|
|
|
|
|
|
|
|
diskread(edit->disk, &table, Tablesz, 0, Toffset);
|
|
|
|
if(table.magic[0] != Magic0 || table.magic[1] != Magic1)
|
|
|
|
sysfatal("did not find master boot record");
|
|
|
|
|
|
|
|
for(tp = table.entry; tp < &table.entry[NTentry]; tp++)
|
|
|
|
if(tp->type == TypeDMDDO)
|
|
|
|
mbroffset = edit->disk->s;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
haveroom(Edit *edit, int primary, int64_t start)
|
|
|
|
{
|
|
|
|
int i, lastsec, n;
|
|
|
|
Dospart *p, *q;
|
|
|
|
uint32_t pend, qstart;
|
|
|
|
|
|
|
|
if(primary) {
|
|
|
|
/*
|
|
|
|
* must be open primary slot.
|
|
|
|
* primary slots are taken by primary partitions
|
|
|
|
* and runs of secondary partitions.
|
|
|
|
*/
|
|
|
|
n = 0;
|
|
|
|
lastsec = 0;
|
|
|
|
for(i=0; i<edit->npart; i++) {
|
|
|
|
p = (Dospart*)edit->part[i];
|
|
|
|
if(p->primary)
|
|
|
|
n++, lastsec=0;
|
|
|
|
else if(!lastsec)
|
|
|
|
n++, lastsec=1;
|
|
|
|
}
|
|
|
|
return n<4;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* secondary partitions can be inserted between two primary
|
|
|
|
* partitions only if there is an empty primary slot.
|
|
|
|
* otherwise, we can put a new secondary partition next
|
|
|
|
* to a secondary partition no problem.
|
|
|
|
*/
|
|
|
|
n = 0;
|
|
|
|
for(i=0; i<edit->npart; i++){
|
|
|
|
p = (Dospart*)edit->part[i];
|
|
|
|
if(p->primary)
|
|
|
|
n++;
|
|
|
|
pend = p->end;
|
|
|
|
if(i+1<edit->npart){
|
|
|
|
q = (Dospart*)edit->part[i+1];
|
|
|
|
qstart = q->start;
|
|
|
|
}else{
|
|
|
|
qstart = edit->end;
|
|
|
|
q = nil;
|
|
|
|
}
|
|
|
|
if(start < pend || start >= qstart)
|
|
|
|
continue;
|
|
|
|
/* we go between these two */
|
|
|
|
if(p->primary==0 || (q && q->primary==0))
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
/* not next to a secondary, need a new primary */
|
|
|
|
return n<4;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
autopart(Edit *edit)
|
|
|
|
{
|
|
|
|
char *err;
|
|
|
|
int active, i;
|
|
|
|
int64_t bigstart, bigsize, start;
|
|
|
|
Dospart *p;
|
|
|
|
|
|
|
|
for(i=0; i<edit->npart; i++)
|
|
|
|
if(((Dospart*)edit->part[i])->type == Type9)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* look for the biggest gap in which we can put a primary partition */
|
|
|
|
start = 0;
|
|
|
|
bigsize = 0;
|
|
|
|
SET(bigstart);
|
|
|
|
for(i=0; i<edit->npart; i++) {
|
|
|
|
p = (Dospart*)edit->part[i];
|
|
|
|
if(p->start > start && p->start - start > bigsize && haveroom(edit, 1, start)) {
|
|
|
|
bigsize = p->start - start;
|
|
|
|
bigstart = start;
|
|
|
|
}
|
|
|
|
start = p->end;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(edit->end - start > bigsize && haveroom(edit, 1, start)) {
|
|
|
|
bigsize = edit->end - start;
|
|
|
|
bigstart = start;
|
|
|
|
}
|
|
|
|
if(bigsize < 1) {
|
|
|
|
fprint(2, "couldn't find space or partition slot for plan 9 partition\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* set new partition active only if no others are */
|
|
|
|
active = Active;
|
|
|
|
for(i=0; i<edit->npart; i++)
|
|
|
|
if(((Dospart*)edit->part[i])->primary && (((Dospart*)edit->part[i])->active & Active))
|
|
|
|
active = 0;
|
|
|
|
|
|
|
|
/* add new plan 9 partition */
|
|
|
|
bigsize *= sec2cyl;
|
|
|
|
bigstart *= sec2cyl;
|
|
|
|
if(bigstart == 0) {
|
|
|
|
bigstart += edit->disk->s;
|
|
|
|
bigsize -= edit->disk->s;
|
|
|
|
}
|
|
|
|
p = mkpart(nil, 1, bigstart, bigsize, nil);
|
|
|
|
p->active = active;
|
|
|
|
p->changed = 1;
|
|
|
|
p->type = Type9;
|
|
|
|
edit->changed = 1;
|
|
|
|
if(err = addpart(edit, p)) {
|
|
|
|
fprint(2, "error adding plan9 partition: %s\n", err);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
typedef struct Name Name;
|
|
|
|
struct Name {
|
|
|
|
char *name;
|
|
|
|
Name *link;
|
|
|
|
};
|
|
|
|
Name *namelist;
|
|
|
|
static void
|
|
|
|
plan9print(Dospart *part, int fd)
|
|
|
|
{
|
|
|
|
int i, ok;
|
|
|
|
char *name, *vname;
|
|
|
|
Name *n;
|
|
|
|
int64_t start, end;
|
|
|
|
char *sep;
|
|
|
|
|
|
|
|
vname = types[part->type].name;
|
|
|
|
if(vname==nil || strcmp(vname, "")==0) {
|
|
|
|
part->ctlname = "";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
start = mbroffset+part->lba;
|
|
|
|
end = start+part->size;
|
|
|
|
|
|
|
|
/* avoid names like plan90 */
|
|
|
|
i = strlen(vname) - 1;
|
|
|
|
if(vname[i] >= '0' && vname[i] <= '9')
|
|
|
|
sep = ".";
|
|
|
|
else
|
|
|
|
sep = "";
|
|
|
|
|
|
|
|
i = 0;
|
|
|
|
name = emalloc(strlen(vname)+10);
|
|
|
|
|
|
|
|
sprint(name, "%s", vname);
|
|
|
|
do {
|
|
|
|
ok = 1;
|
|
|
|
for(n=namelist; n; n=n->link) {
|
|
|
|
if(strcmp(name, n->name) == 0) {
|
|
|
|
i++;
|
|
|
|
sprint(name, "%s%s%d", vname, sep, i);
|
|
|
|
ok = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} while(ok == 0);
|
|
|
|
|
|
|
|
n = emalloc(sizeof(*n));
|
|
|
|
n->name = name;
|
|
|
|
n->link = namelist;
|
|
|
|
namelist = n;
|
|
|
|
part->ctlname = name;
|
|
|
|
|
|
|
|
if(fd >= 0)
|
|
|
|
print("part %s %lld %lld\n", name, start, end);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
freenamelist(void)
|
|
|
|
{
|
|
|
|
Name *n, *next;
|
|
|
|
|
|
|
|
for(n=namelist; n; n=next) {
|
|
|
|
next = n->link;
|
|
|
|
free(n);
|
|
|
|
}
|
|
|
|
namelist = nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
cmdprintctl(Edit *edit, int ctlfd)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
freenamelist();
|
|
|
|
for(i=0; i<edit->npart; i++)
|
|
|
|
plan9print((Dospart*)edit->part[i], -1);
|
|
|
|
ctldiff(edit, ctlfd);
|
|
|
|
}
|
|
|
|
|
|
|
|
static char*
|
|
|
|
cmdokname(Edit *e, char *name)
|
|
|
|
{
|
|
|
|
char *q;
|
|
|
|
|
|
|
|
if(name[0] != 'p' && name[0] != 's')
|
|
|
|
return "name must be pN or sN";
|
|
|
|
|
|
|
|
strtol(name+1, &q, 10);
|
|
|
|
if(*q != '\0')
|
|
|
|
return "name must be pN or sN";
|
|
|
|
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
#define TB (1024LL*GB)
|
|
|
|
#define GB (1024*1024*1024)
|
|
|
|
#define MB (1024*1024)
|
|
|
|
#define KB (1024)
|
|
|
|
|
|
|
|
static void
|
|
|
|
cmdsum(Edit *edit, Part *vp, int64_t a, int64_t b)
|
|
|
|
{
|
|
|
|
char *name, *ty;
|
|
|
|
char buf[3];
|
|
|
|
char *suf;
|
|
|
|
Dospart *p;
|
|
|
|
int64_t sz, div;
|
|
|
|
|
|
|
|
p = (Dospart*)vp;
|
|
|
|
|
|
|
|
buf[0] = p && p->changed ? '\'' : ' ';
|
|
|
|
buf[1] = p && (p->active & Active) ? '*' : ' ';
|
|
|
|
buf[2] = '\0';
|
|
|
|
|
|
|
|
name = p ? p->name : "empty";
|
|
|
|
ty = p ? typestr0(p->type) : "";
|
|
|
|
|
|
|
|
sz = (b-a)*edit->disk->secsize*sec2cyl;
|
|
|
|
if(sz >= 1*TB){
|
|
|
|
suf = "TB";
|
|
|
|
div = TB;
|
|
|
|
}else if(sz >= 1*GB){
|
|
|
|
suf = "GB";
|
|
|
|
div = GB;
|
|
|
|
}else if(sz >= 1*MB){
|
|
|
|
suf = "MB";
|
|
|
|
div = MB;
|
|
|
|
}else if(sz >= 1*KB){
|
|
|
|
suf = "KB";
|
|
|
|
div = KB;
|
|
|
|
}else{
|
|
|
|
suf = "B ";
|
|
|
|
div = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(div == 1)
|
|
|
|
print("%s %-12s %*lld %-*lld (%lld cylinders, %lld %s) %s\n", buf, name,
|
|
|
|
edit->disk->width, a, edit->disk->width, b, b-a, sz, suf, ty);
|
|
|
|
else
|
|
|
|
print("%s %-12s %*lld %-*lld (%lld cylinders, %lld.%.2d %s) %s\n", buf, name,
|
|
|
|
edit->disk->width, a, edit->disk->width, b, b-a,
|
|
|
|
sz/div, (int)(((sz%div)*100)/div), suf, ty);
|
|
|
|
}
|
|
|
|
|
|
|
|
static char*
|
|
|
|
cmdadd(Edit *edit, char *name, int64_t start, int64_t end)
|
|
|
|
{
|
|
|
|
Dospart *p;
|
|
|
|
|
|
|
|
if(!haveroom(edit, name[0]=='p', start))
|
|
|
|
return "no room for partition";
|
|
|
|
start *= sec2cyl;
|
|
|
|
end *= sec2cyl;
|
|
|
|
if(start == 0 || name[0] != 'p')
|
|
|
|
start += edit->disk->s;
|
|
|
|
p = mkpart(name, name[0]=='p', start, end-start, nil);
|
|
|
|
p->changed = 1;
|
|
|
|
p->type = Type9;
|
|
|
|
return addpart(edit, p);
|
|
|
|
}
|
|
|
|
|
|
|
|
static char*
|
|
|
|
cmddel(Edit *edit, Part *p)
|
|
|
|
{
|
|
|
|
return delpart(edit, p);
|
|
|
|
}
|
|
|
|
|
|
|
|
static char*
|
|
|
|
cmdwrite(Edit *edit)
|
|
|
|
{
|
|
|
|
wrpart(edit);
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
static char *help =
|
|
|
|
"A name - set partition active\n"
|
|
|
|
"P - print table in ctl format\n"
|
|
|
|
"R - restore disk back to initial configuration and exit\n"
|
|
|
|
"e - show empty dos partitions\n"
|
|
|
|
"t name [type] - set partition type\n";
|
|
|
|
|
|
|
|
static char*
|
|
|
|
cmdhelp(Edit *e)
|
|
|
|
{
|
|
|
|
print("%s\n", help);
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
static char*
|
|
|
|
cmdactive(Edit *edit, int nf, char **f)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
Dospart *p, *ip;
|
|
|
|
|
|
|
|
if(nf != 2)
|
|
|
|
return "args";
|
|
|
|
|
|
|
|
if(f[1][0] != 'p')
|
|
|
|
return "cannot set secondary partition active";
|
|
|
|
|
|
|
|
if((p = (Dospart*)findpart(edit, f[1])) == nil)
|
|
|
|
return "unknown partition";
|
|
|
|
|
|
|
|
for(i=0; i<edit->npart; i++) {
|
|
|
|
ip = (Dospart*)edit->part[i];
|
|
|
|
if(ip->active & Active) {
|
|
|
|
ip->active &= ~Active;
|
|
|
|
ip->changed = 1;
|
|
|
|
edit->changed = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if((p->active & Active) == 0) {
|
|
|
|
p->active |= Active;
|
|
|
|
p->changed = 1;
|
|
|
|
edit->changed = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
static char*
|
|
|
|
strupr(char *s)
|
|
|
|
{
|
|
|
|
char *p;
|
|
|
|
|
|
|
|
for(p=s; *p; p++)
|
|
|
|
*p = toupper(*p);
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
dumplist(void)
|
|
|
|
{
|
|
|
|
int i, n;
|
|
|
|
|
|
|
|
n = 0;
|
|
|
|
for(i=0; i<256; i++) {
|
|
|
|
if(types[i].desc) {
|
|
|
|
print("%-16s", types[i].desc);
|
|
|
|
if(n++%4 == 3)
|
|
|
|
print("\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(n%4)
|
|
|
|
print("\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
static char*
|
|
|
|
cmdtype(Edit *edit, int nf, char **f)
|
|
|
|
{
|
|
|
|
char *q;
|
|
|
|
Dospart *p;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if(nf < 2)
|
|
|
|
return "args";
|
|
|
|
|
|
|
|
if((p = (Dospart*)findpart(edit, f[1])) == nil)
|
|
|
|
return "unknown partition";
|
|
|
|
|
|
|
|
if(nf == 2) {
|
|
|
|
for(;;) {
|
|
|
|
fprint(2, "new partition type [? for list]: ");
|
|
|
|
q = getline(edit);
|
|
|
|
if(q[0] == '?')
|
|
|
|
dumplist();
|
|
|
|
else
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else
|
|
|
|
q = f[2];
|
|
|
|
|
|
|
|
strupr(q);
|
|
|
|
for(i=0; i<256; i++)
|
|
|
|
if(types[i].desc && strcmp(types[i].desc, q) == 0)
|
|
|
|
break;
|
|
|
|
if(i < 256 && p->type != i) {
|
|
|
|
p->type = i;
|
|
|
|
p->changed = 1;
|
|
|
|
edit->changed = 1;
|
|
|
|
}
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
static char*
|
|
|
|
cmdext(Edit *edit, int nf, char **f)
|
|
|
|
{
|
|
|
|
switch(f[0][0]) {
|
|
|
|
case 'A':
|
|
|
|
return cmdactive(edit, nf, f);
|
|
|
|
case 't':
|
|
|
|
return cmdtype(edit, nf, f);
|
|
|
|
case 'R':
|
|
|
|
recover(edit);
|
|
|
|
return nil;
|
|
|
|
default:
|
|
|
|
return "unknown command";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
Dfmt(Fmt *f)
|
|
|
|
{
|
|
|
|
char buf[60];
|
|
|
|
uint8_t *p;
|
|
|
|
int c, h, s;
|
|
|
|
|
|
|
|
p = va_arg(f->args, uint8_t*);
|
|
|
|
h = p[0];
|
|
|
|
c = p[2];
|
|
|
|
c |= (p[1]&0xC0)<<2;
|
|
|
|
s = (p[1] & 0x3F);
|
|
|
|
|
|
|
|
sprint(buf, "%d/%d/%d", c, h, s);
|
|
|
|
return fmtstrcpy(f, buf);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
writechs(Disk *disk, uint8_t *p, int64_t lba)
|
|
|
|
{
|
|
|
|
int c, h, s;
|
|
|
|
|
|
|
|
s = lba % disk->s;
|
|
|
|
h = (lba / disk->s) % disk->h;
|
|
|
|
c = lba / (disk->s * disk->h);
|
|
|
|
|
|
|
|
if(c >= 1024) {
|
|
|
|
c = 1023;
|
|
|
|
h = disk->h - 1;
|
|
|
|
s = disk->s - 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
p[0] = h;
|
|
|
|
p[1] = ((s+1) & 0x3F) | ((c>>2) & 0xC0);
|
|
|
|
p[2] = c;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
wrtentry(Disk *disk, Tentry *tp, int type, uint32_t xbase, uint32_t lba,
|
|
|
|
uint32_t end)
|
|
|
|
{
|
|
|
|
tp->type = type;
|
|
|
|
writechs(disk, &tp->starth, lba);
|
|
|
|
writechs(disk, &tp->endh, end-1);
|
|
|
|
putle32(tp->xlba, lba-xbase);
|
|
|
|
putle32(tp->xsize, end-lba);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
wrextend(Edit *edit, int i, int64_t xbase, int64_t startlba,
|
|
|
|
int64_t *endlba)
|
|
|
|
{
|
|
|
|
int ni;
|
|
|
|
Table table;
|
|
|
|
Tentry *tp, *ep;
|
|
|
|
Dospart *p;
|
|
|
|
Disk *disk;
|
|
|
|
|
|
|
|
if(i == edit->npart){
|
|
|
|
*endlba = edit->disk->secs;
|
|
|
|
Finish:
|
|
|
|
if(startlba < *endlba){
|
|
|
|
disk = edit->disk;
|
|
|
|
diskread(disk, &table, Tablesz, mbroffset+startlba, Toffset);
|
|
|
|
tp = table.entry;
|
|
|
|
ep = tp+NTentry;
|
|
|
|
for(; tp<ep; tp++)
|
|
|
|
memset(tp, 0, sizeof *tp);
|
|
|
|
table.magic[0] = Magic0;
|
|
|
|
table.magic[1] = Magic1;
|
|
|
|
|
|
|
|
if(diskwrite(edit->disk, &table, Tablesz, mbroffset+startlba, Toffset) < 0)
|
|
|
|
recover(edit);
|
|
|
|
}
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
|
|
|
p = (Dospart*)edit->part[i];
|
|
|
|
if(p->primary){
|
|
|
|
*endlba = (int64_t)p->start*sec2cyl;
|
|
|
|
goto Finish;
|
|
|
|
}
|
|
|
|
|
|
|
|
disk = edit->disk;
|
|
|
|
diskread(disk, &table, Tablesz, mbroffset+startlba, Toffset);
|
|
|
|
tp = table.entry;
|
|
|
|
ep = tp+NTentry;
|
|
|
|
|
|
|
|
ni = wrextend(edit, i+1, xbase, p->end*sec2cyl, endlba);
|
|
|
|
|
|
|
|
*tp = p->Tentry;
|
|
|
|
wrtentry(disk, tp, p->type, startlba, startlba+disk->s, p->end*sec2cyl);
|
|
|
|
tp++;
|
|
|
|
|
|
|
|
if(p->end*sec2cyl != *endlba){
|
|
|
|
memset(tp, 0, sizeof *tp);
|
|
|
|
wrtentry(disk, tp, TypeEXTENDED, xbase, p->end*sec2cyl, *endlba);
|
|
|
|
tp++;
|
|
|
|
}
|
|
|
|
|
|
|
|
for(; tp<ep; tp++)
|
|
|
|
memset(tp, 0, sizeof *tp);
|
|
|
|
|
|
|
|
table.magic[0] = Magic0;
|
|
|
|
table.magic[1] = Magic1;
|
|
|
|
|
|
|
|
if(diskwrite(edit->disk, &table, Tablesz, mbroffset+startlba, Toffset) < 0)
|
|
|
|
recover(edit);
|
|
|
|
return ni;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
wrpart(Edit *edit)
|
|
|
|
{
|
|
|
|
int i, ni, t;
|
|
|
|
Table table;
|
|
|
|
Tentry *tp, *ep;
|
|
|
|
Disk *disk;
|
|
|
|
int64_t s, endlba;
|
|
|
|
Dospart *p;
|
|
|
|
|
|
|
|
disk = edit->disk;
|
|
|
|
|
|
|
|
diskread(disk, &table, Tablesz, mbroffset, Toffset);
|
|
|
|
|
|
|
|
tp = table.entry;
|
|
|
|
ep = tp+NTentry;
|
|
|
|
for(i=0; i<edit->npart && tp<ep; ) {
|
|
|
|
p = (Dospart*)edit->part[i];
|
|
|
|
if(p->start == 0)
|
|
|
|
s = disk->s;
|
|
|
|
else
|
|
|
|
s = p->start*sec2cyl;
|
|
|
|
if(p->primary) {
|
|
|
|
*tp = p->Tentry;
|
|
|
|
wrtentry(disk, tp, p->type, 0, s, p->end*sec2cyl);
|
|
|
|
tp++;
|
|
|
|
i++;
|
|
|
|
} else {
|
|
|
|
ni = wrextend(edit, i, p->start*sec2cyl, p->start*sec2cyl, &endlba);
|
|
|
|
memset(tp, 0, sizeof *tp);
|
|
|
|
if(endlba >= 1024*sec2cyl)
|
|
|
|
t = TypeEXTHUGE;
|
|
|
|
else
|
|
|
|
t = TypeEXTENDED;
|
|
|
|
wrtentry(disk, tp, t, 0, s, endlba);
|
|
|
|
tp++;
|
|
|
|
i = ni;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for(; tp<ep; tp++)
|
|
|
|
memset(tp, 0, sizeof(*tp));
|
|
|
|
|
|
|
|
if(i != edit->npart)
|
|
|
|
sysfatal("cannot happen #1");
|
|
|
|
|
|
|
|
if(diskwrite(disk, &table, Tablesz, mbroffset, Toffset) < 0)
|
|
|
|
recover(edit);
|
|
|
|
|
|
|
|
/* bring parts up to date */
|
|
|
|
freenamelist();
|
|
|
|
for(i=0; i<edit->npart; i++)
|
|
|
|
plan9print((Dospart*)edit->part[i], -1);
|
|
|
|
|
|
|
|
if(ctldiff(edit, disk->ctlfd) < 0)
|
|
|
|
fprint(2, "?warning: partitions could not be updated in devsd\n");
|
|
|
|
}
|