Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
/*
2
 * fdisk - edit dos disk partition table
3
 */
4
#include <u.h>
5
#include <libc.h>
6
#include <bio.h>
7
#include <ctype.h>
8
#include <disk.h>
9
#include "edit.h"
10
 
11
typedef struct Dospart	Dospart;
12
enum {
13
	NTentry = 4,
14
	Mpart = 64,
15
};
16
 
17
static void rdpart(Edit*, uvlong, uvlong);
18
static void findmbr(Edit*);
19
static void autopart(Edit*);
20
static void wrpart(Edit*);
21
static void blankpart(Edit*);
22
static void cmdnamectl(Edit*);
23
static void recover(Edit*);
24
static int Dfmt(Fmt*);
25
static int blank;
26
static int dowrite;
27
static int file;
28
static int rdonly;
29
static int doauto;
30
static vlong mbroffset;
31
static int printflag;
32
static int printchs;
33
static int sec2cyl;
34
static int written;
35
 
36
static void 	cmdsum(Edit*, Part*, vlong, vlong);
37
static char 	*cmdadd(Edit*, char*, vlong, vlong);
38
static char 	*cmddel(Edit*, Part*);
39
static char 	*cmdext(Edit*, int, char**);
40
static char 	*cmdhelp(Edit*);
41
static char 	*cmdokname(Edit*, char*);
42
static char 	*cmdwrite(Edit*);
43
static void	cmdprintctl(Edit*, int);
44
 
45
#pragma varargck type "D" uchar*
46
 
47
Edit edit = {
48
	.add=	cmdadd,
49
	.del=		cmddel,
50
	.ext=		cmdext,
51
	.help=	cmdhelp,
52
	.okname=	cmdokname,
53
	.sum=	cmdsum,
54
	.write=	cmdwrite,
55
	.printctl=	cmdprintctl,
56
 
57
	.unit=	"cylinder",
58
};
59
 
60
/*
61
 * Catch the obvious error routines to fix up the disk.
62
 */
63
void
64
sysfatal(char *fmt, ...)
65
{
66
	char buf[1024];
67
	va_list arg;
68
 
69
	va_start(arg, fmt);
70
	vseprint(buf, buf+sizeof(buf), fmt, arg);
71
	va_end(arg);
72
	if(argv0)
73
		fprint(2, "%s: %s\n", argv0, buf);
74
	else
75
		fprint(2, "%s\n", buf);
76
 
77
	if(written)
78
		recover(&edit);
79
 
80
	exits(buf);
81
}
82
 
83
void
84
abort(void)
85
{
86
	fprint(2, "abort\n");
87
	recover(&edit);
88
}
89
 
90
void
91
usage(void)
92
{
93
	fprint(2, "usage: disk/fdisk [-abfprvw] [-s sectorsize] /dev/sdC0/data\n");
94
	exits("usage");
95
}
96
 
97
void
98
main(int argc, char **argv)
99
{
100
	vlong secsize;
101
 
102
	secsize = 0;
103
	ARGBEGIN{
104
	case 'a':
105
		doauto++;
106
		break;
107
	case 'b':
108
		blank++;
109
		break;
110
	case 'f':
111
		file++;
112
		break;
113
	case 'p':
114
		printflag++;
115
		break;
116
	case 'r':
117
		rdonly++;
118
		break;
119
	case 's':
120
		secsize = atoi(ARGF());
121
		break;
122
	case 'v':
123
		printchs++;
124
		break;
125
	case 'w':
126
		dowrite++;
127
		break;
128
	}ARGEND;
129
 
130
	fmtinstall('D', Dfmt);
131
 
132
	if(argc != 1)
133
		usage();
134
 
135
	edit.disk = opendisk(argv[0], rdonly, file);
136
	if(edit.disk == nil) {
137
		fprint(2, "cannot open disk: %r\n");
138
		exits("opendisk");
139
	}
140
 
141
	if(secsize != 0) {
142
		edit.disk->secsize = secsize;
143
		edit.disk->secs = edit.disk->size / secsize;
144
	}
145
 
146
	sec2cyl = edit.disk->h * edit.disk->s;
147
	edit.end = edit.disk->secs / sec2cyl;
148
 
149
	findmbr(&edit);
150
 
151
	if(blank)
152
		blankpart(&edit);
153
	else
154
		rdpart(&edit, 0, 0);
155
 
156
	if(doauto)
157
		autopart(&edit);
158
 
159
	if(dowrite)
160
		runcmd(&edit, "w");
161
 
162
	if(printflag)
163
		runcmd(&edit, "P");
164
 
165
	if(dowrite || printflag)
166
		exits(0);
167
 
168
	fprint(2, "cylinder = %lld bytes\n", sec2cyl*edit.disk->secsize);
169
	runcmd(&edit, "p");
170
	for(;;) {
171
		fprint(2, ">>> ");
172
		runcmd(&edit, getline(&edit));
173
	}
174
}
175
 
176
typedef struct Tentry	Tentry;
177
typedef struct Table	Table;
178
typedef struct Type	Type;
179
typedef struct Tab	Tab;
180
typedef struct Recover Recover;
181
 
182
struct Tentry {
183
	uchar	active;			/* active flag */
184
	uchar	starth;			/* starting head */
185
	uchar	starts;			/* starting sector */
186
	uchar	startc;			/* starting cylinder */
187
	uchar	type;			/* partition type */
188
	uchar	endh;			/* ending head */
189
	uchar	ends;			/* ending sector */
190
	uchar	endc;			/* ending cylinder */
191
	uchar	xlba[4];		/* starting LBA from beginning of disc or ext. partition */
192
	uchar	xsize[4];		/* size in sectors */
193
};
194
 
195
struct Table {
196
	Tentry	entry[NTentry];
197
	uchar	magic[2];
198
	uchar	size[];
199
};
200
 
201
enum {
202
	Active		= 0x80,		/* partition is active */
203
	Primary		= 0x01,		/* internal flag */
204
 
205
	TypeBB		= 0xFF,
206
 
207
	TypeEMPTY	= 0x00,
208
	TypeFAT12	= 0x01,
209
	TypeXENIX	= 0x02,		/* root */
210
	TypeXENIXUSR	= 0x03,		/* usr */
211
	TypeFAT16	= 0x04,
212
	TypeEXTENDED	= 0x05,
213
	TypeFATHUGE	= 0x06,
214
	TypeHPFS	= 0x07,
215
	TypeAIXBOOT	= 0x08,
216
	TypeAIXDATA	= 0x09,
217
	TypeOS2BOOT	= 0x0A,		/* OS/2 Boot Manager */
218
	TypeFAT32	= 0x0B,		/* FAT 32 */
219
	TypeFAT32LBA	= 0x0C,		/* FAT 32 needing LBA support */
220
	TypeFAT16X	= 0x0E,		/* FAT 16 needing LBA support */
221
	TypeEXTHUGE	= 0x0F,		/* FAT 32 extended partition */
222
	TypeUNFORMATTED	= 0x16,		/* unformatted primary partition (OS/2 FDISK)? */
223
	TypeHPFS2	= 0x17,
224
	TypeIBMRecovery = 0x1C,		/* really hidden fat */
225
	TypeCPM0	= 0x52,
226
	TypeDMDDO	= 0x54,		/* Disk Manager Dynamic Disk Overlay */
227
	TypeGB		= 0x56,		/* ???? */
228
	TypeSPEEDSTOR	= 0x61,
229
	TypeSYSV386	= 0x63,		/* also HURD? */
230
	TypeNETWARE	= 0x64,
231
	TypePCIX	= 0x75,
232
	TypeMINIX13	= 0x80,		/* Minix v1.3 and below */
233
	TypeMINIX	= 0x81,		/* Minix v1.5+ */
234
	TypeLINUXSWAP	= 0x82,
235
	TypeLINUX	= 0x83,
236
	TypeLINUXEXT	= 0x85,
237
	TypeLINUXLVM	= 0x8E,		/* logical volume manager */
238
	TypeAMOEBA	= 0x93,
239
	TypeAMOEBABB	= 0x94,
240
	TypeBSD386	= 0xA5,
241
	TypeNETBSD	= 0xA9,
242
	TypeBSDI	= 0xB7,
243
	TypeBSDISWAP	= 0xB8,
244
	TypeOTHER	= 0xDA,
245
	TypeCPM		= 0xDB,
246
	TypeDellRecovery= 0xDE,
247
	TypeSPEEDSTOR12	= 0xE1,
248
	TypeSPEEDSTOR16	= 0xE4,
249
	TypeEFIProtect	= 0xEE,
250
	TypeEFI		= 0xEF,
251
	TypeLANSTEP	= 0xFE,
252
 
253
	Type9		= 0x39,
254
 
255
	Toffset		= 446,		/* offset of partition table in sector */
256
	Magic0		= 0x55,
257
	Magic1		= 0xAA,
258
 
259
	Tablesz		= offsetof(Table, size[0]),
260
};
261
 
262
struct Type {
263
	char *desc;
264
	char *name;
265
};
266
 
267
struct Dospart {
268
	Part;
269
	Tentry;
270
 
271
	u32int	lba;
272
	u32int	size;
273
	int		primary;
274
};
275
 
276
struct Recover {
277
	Table	table;
278
	ulong	lba;
279
};
280
 
281
static Type types[256] = {
282
	[TypeEMPTY]		{ "EMPTY", "" },
283
	[TypeFAT12]		{ "FAT12", "dos" },
284
	[TypeFAT16]		{ "FAT16", "dos" },
285
	[TypeFAT32]		{ "FAT32", "dos" },
286
	[TypeFAT32LBA]		{ "FAT32LBA", "dos" },
287
	[TypeFAT16X]		{ "FAT16X", "dos" },
288
	[TypeEXTHUGE]		{ "EXTHUGE", "" },
289
	[TypeIBMRecovery]	{ "IBMRECOVERY", "ibm" },
290
	[TypeEXTENDED]		{ "EXTENDED", "" },
291
	[TypeFATHUGE]		{ "FATHUGE", "dos" },
292
	[TypeBB]		{ "BB", "bb" },
293
 
294
	[TypeXENIX]		{ "XENIX", "xenix" },
295
	[TypeXENIXUSR]		{ "XENIX USR", "xenixusr" },
296
	[TypeHPFS]		{ "HPFS", "ntfs" },
297
	[TypeAIXBOOT]		{ "AIXBOOT", "aixboot" },
298
	[TypeAIXDATA]		{ "AIXDATA", "aixdata" },
299
	[TypeOS2BOOT]		{ "OS/2BOOT", "os2boot" },
300
	[TypeUNFORMATTED]	{ "UNFORMATTED", "" },
301
	[TypeHPFS2]		{ "HPFS2", "hpfs2" },
302
	[TypeCPM0]		{ "CPM0", "cpm0" },
303
	[TypeDMDDO]		{ "DMDDO", "dmdd0" },
304
	[TypeGB]		{ "GB", "gb" },
305
	[TypeSPEEDSTOR]		{ "SPEEDSTOR", "speedstor" },
306
	[TypeSYSV386]		{ "SYSV386", "sysv386" },
307
	[TypeNETWARE]		{ "NETWARE", "netware" },
308
	[TypePCIX]		{ "PCIX", "pcix" },
309
	[TypeMINIX13]		{ "MINIXV1.3", "minix13" },
310
	[TypeMINIX]		{ "MINIXV1.5", "minix15" },
311
	[TypeLINUXSWAP]		{ "LINUXSWAP", "linuxswap" },
312
	[TypeLINUX]		{ "LINUX", "linux" },
313
	[TypeLINUXEXT]		{ "LINUXEXTENDED", "" },
314
	[TypeLINUXLVM]		{ "LINUXLVM", "linuxlvm" },
315
	[TypeAMOEBA]		{ "AMOEBA", "amoeba" },
316
	[TypeAMOEBABB]		{ "AMOEBABB", "amoebaboot" },
317
	[TypeBSD386]		{ "BSD386", "bsd386" },
318
	[TypeNETBSD]		{ "NETBSD", "netbsd" },
319
	[TypeBSDI]		{ "BSDI", "bsdi" },
320
	[TypeBSDISWAP]		{ "BSDISWAP", "bsdiswap" },
321
	[TypeOTHER]		{ "OTHER", "other" },
322
	[TypeCPM]		{ "CPM", "cpm" },
323
	[TypeDellRecovery]	{ "DELLRECOVERY", "dell" },
324
	[TypeSPEEDSTOR12]	{ "SPEEDSTOR12", "speedstor" },
325
	[TypeSPEEDSTOR16]	{ "SPEEDSTOR16", "speedstor" },
326
	[TypeEFIProtect]	{ "EFIPROTECT", "efiprotect" },
327
	[TypeEFI]		{ "EFI", "efi" },
328
	[TypeLANSTEP]		{ "LANSTEP", "lanstep" },
329
 
330
	[Type9]			{ "PLAN9", "plan9" },
331
};
332
 
333
static Dospart	part[Mpart];
334
static int		npart;
335
 
336
static char*
337
typestr0(int type)
338
{
339
	static char buf[100];
340
 
341
	sprint(buf, "type %d", type);
342
	if(type < 0 || type >= 256)
343
		return buf;
344
	if(types[type].desc == nil)
345
		return buf;
346
	return types[type].desc;
347
}
348
 
349
static u32int
350
getle32(void* v)
351
{
352
	uchar *p;
353
 
354
	p = v;
355
	return (p[3]<<24)|(p[2]<<16)|(p[1]<<8)|p[0];
356
}
357
 
358
static void
359
putle32(void* v, u32int i)
360
{
361
	uchar *p;
362
 
363
	p = v;
364
	p[0] = i;
365
	p[1] = i>>8;
366
	p[2] = i>>16;
367
	p[3] = i>>24;
368
}
369
 
370
static void
371
diskread(Disk *disk, void *data, int ndata, u32int sec, u32int off)
372
{
373
	if(seek(disk->fd, (vlong)sec*disk->secsize+off, 0) != (vlong)sec*disk->secsize+off)
374
		sysfatal("diskread seek %lud.%lud: %r", (ulong)sec, (ulong)off);
375
	if(readn(disk->fd, data, ndata) != ndata)
376
		sysfatal("diskread %lud at %lud.%lud: %r", (ulong)ndata, (ulong)sec, (ulong)off);
377
}
378
 
379
static int
380
diskwrite(Disk *disk, void *data, int ndata, u32int sec, u32int off)
381
{
382
	written = 1;
383
	if(seek(disk->wfd, (vlong)sec*disk->secsize+off, 0) != (vlong)sec*disk->secsize+off)
384
		goto Error;
385
	if(write(disk->wfd, data, ndata) != ndata)
386
		goto Error;
387
	return 0;
388
 
389
Error:
390
	fprint(2, "write %d bytes at %lud.%lud failed: %r\n", ndata, (ulong)sec, (ulong)off);
391
	return -1;
392
}
393
 
394
static Dospart*
395
mkpart(char *name, int primary, vlong lba, vlong size, Tentry *t)
396
{
397
	static int n;
398
	Dospart *p;
399
 
400
	p = emalloc(sizeof(*p));
401
	if(name)
402
		p->name = estrdup(name);
403
	else{
404
		p->name = emalloc(20);
405
		sprint(p->name, "%c%d", primary ? 'p' : 's', ++n);
406
	}
407
 
408
	if(t)
409
		p->Tentry = *t;
410
	else
411
		memset(&p->Tentry, 0, sizeof(Tentry));
412
 
413
	p->changed = 0;
414
	p->start = lba/sec2cyl;
415
	p->end = (lba+size)/sec2cyl;
416
	p->ctlstart = lba;
417
	p->ctlend = lba+size;
418
	p->lba = lba;
419
	if (p->lba != lba)
420
		fprint(2, "%s: start of partition (%lld) won't fit in MBR table\n", argv0, lba);
421
	p->size = size;
422
	if (p->size != size)
423
		fprint(2, "%s: size of partition (%lld) won't fit in MBR table\n", argv0, size);
424
	p->primary = primary;
425
	return p;
426
}
427
 
428
/*
429
 * Recovery takes care of remembering what the various tables
430
 * looked like when we started, attempting to restore them when
431
 * we are finished.
432
 */
433
static Recover	*rtab;
434
static int		nrtab;
435
 
436
static void
437
addrecover(Table t, ulong lba)
438
{
439
	if((nrtab%8) == 0) {
440
		rtab = realloc(rtab, (nrtab+8)*sizeof(rtab[0]));
441
		if(rtab == nil)
442
			sysfatal("out of memory");
443
	}
444
	rtab[nrtab] = (Recover){t, lba};
445
	nrtab++;
446
}
447
 
448
static void
449
recover(Edit *edit)
450
{
451
	int err, i, ctlfd;
452
	vlong offset;
453
 
454
	err = 0;
455
	for(i=0; i<nrtab; i++)
456
		if(diskwrite(edit->disk, &rtab[i].table, Tablesz, rtab[i].lba, Toffset) < 0)
457
			err = 1;
458
	if(err) {
459
		fprint(2, "warning: some writes failed during restoration of old partition tables\n");
460
		exits("inconsistent");
461
	} else {
462
		fprint(2, "restored old partition tables\n");
463
	}
464
 
465
	ctlfd = edit->disk->ctlfd;
466
	offset = edit->disk->offset;
467
	if(ctlfd >= 0){
468
		for(i=0; i<edit->npart; i++)
469
			if(edit->part[i]->ctlname && fprint(ctlfd, "delpart %s", edit->part[i]->ctlname)<0)
470
				fprint(2, "delpart failed: %s: %r", edit->part[i]->ctlname);
471
		for(i=0; i<edit->nctlpart; i++)
472
			if(edit->part[i]->name && fprint(ctlfd, "delpart %s", edit->ctlpart[i]->name)<0)
473
				fprint(2, "delpart failed: %s: %r", edit->ctlpart[i]->name);
474
		for(i=0; i<edit->nctlpart; i++){
475
			if(fprint(ctlfd, "part %s %lld %lld", edit->ctlpart[i]->name,
476
				edit->ctlpart[i]->start+offset, edit->ctlpart[i]->end+offset) < 0){
477
				fprint(2, "restored disk partition table but not kernel; reboot\n");
478
				exits("inconsistent");
479
			}
480
		}
481
	}
482
	exits("restored");
483
 
484
}
485
 
486
/*
487
 * Read the partition table (including extended partition tables)
488
 * from the disk into the part array.
489
 */
490
static void
491
rdpart(Edit *edit, uvlong lba, uvlong xbase)
492
{
493
	char *err;
494
	Table table;
495
	Tentry *tp, *ep;
496
	Dospart *p;
497
 
498
	if(xbase == 0)
499
		xbase = lba;
500
 
501
	diskread(edit->disk, &table, Tablesz, mbroffset+lba, Toffset);
502
	addrecover(table, mbroffset+lba);
503
 
504
	if(table.magic[0] != Magic0 || table.magic[1] != Magic1) {
505
		assert(lba != 0);
506
		return;
507
	}
508
 
509
	for(tp=table.entry, ep=tp+NTentry; tp<ep && npart < Mpart; tp++) {
510
		switch(tp->type) {
511
		case TypeEMPTY:
512
			break;
513
		case TypeEXTENDED:
514
		case TypeEXTHUGE:
515
		case TypeLINUXEXT:
516
			rdpart(edit, xbase+getle32(tp->xlba), xbase);
517
			break;
518
		default:
519
			p = mkpart(nil, lba==0, lba+getle32(tp->xlba), getle32(tp->xsize), tp);
520
			if(err = addpart(edit, p))
521
				fprint(2, "adding partition: %s\n", err);
522
			break;
523
		}
524
	}
525
}
526
 
527
static void
528
blankpart(Edit *edit)
529
{
530
	edit->changed = 1;
531
}
532
 
533
static void
534
findmbr(Edit *edit)
535
{
536
	Table table;
537
	Tentry *tp;
538
 
539
	diskread(edit->disk, &table, Tablesz, 0, Toffset);
540
	if(table.magic[0] != Magic0 || table.magic[1] != Magic1)
541
		sysfatal("did not find master boot record");
542
 
543
	for(tp = table.entry; tp < &table.entry[NTentry]; tp++)
544
		if(tp->type == TypeDMDDO)
545
			mbroffset = edit->disk->s;
546
}
547
 
548
static int
549
haveroom(Edit *edit, int primary, vlong start)
550
{
551
	int i, lastsec, n;
552
	Dospart *p, *q;
553
	ulong pend, qstart;
554
 
555
	if(primary) {
556
		/*
557
		 * must be open primary slot.
558
		 * primary slots are taken by primary partitions
559
		 * and runs of secondary partitions.
560
		 */
561
		n = 0;
562
		lastsec = 0;
563
		for(i=0; i<edit->npart; i++) {
564
			p = (Dospart*)edit->part[i];
565
			if(p->primary)
566
				n++, lastsec=0;
567
			else if(!lastsec)
568
				n++, lastsec=1;
569
		}
570
		return n<4;
571
	}
572
 
573
	/* 
574
	 * secondary partitions can be inserted between two primary
575
	 * partitions only if there is an empty primary slot.
576
	 * otherwise, we can put a new secondary partition next
577
	 * to a secondary partition no problem.
578
	 */
579
	n = 0;
580
	for(i=0; i<edit->npart; i++){
581
		p = (Dospart*)edit->part[i];
582
		if(p->primary)
583
			n++;
584
		pend = p->end;
585
		if(i+1<edit->npart){
586
			q = (Dospart*)edit->part[i+1];
587
			qstart = q->start;
588
		}else{
589
			qstart = edit->end;
590
			q = nil;
591
		}
592
		if(start < pend || start >= qstart)
593
			continue;
594
		/* we go between these two */
595
		if(p->primary==0 || (q && q->primary==0))
596
			return 1;
597
	}
598
	/* not next to a secondary, need a new primary */
599
	return n<4;
600
}
601
 
602
static void
603
autopart(Edit *edit)
604
{
605
	char *err;
606
	int active, i;
607
	vlong bigstart, bigsize, start;
608
	Dospart *p;
609
 
610
	for(i=0; i<edit->npart; i++)
611
		if(((Dospart*)edit->part[i])->type == Type9)
612
			return;
613
 
614
	/* look for the biggest gap in which we can put a primary partition */
615
	start = 0;
616
	bigsize = 0;
617
	SET(bigstart);
618
	for(i=0; i<edit->npart; i++) {
619
		p = (Dospart*)edit->part[i];
620
		if(p->start > start && p->start - start > bigsize && haveroom(edit, 1, start)) {
621
			bigsize = p->start - start;
622
			bigstart = start;
623
		}
624
		start = p->end;
625
	}
626
 
627
	if(edit->end - start > bigsize && haveroom(edit, 1, start)) {
628
		bigsize = edit->end - start;
629
		bigstart = start;
630
	}
631
	if(bigsize < 1) {
632
		fprint(2, "couldn't find space or partition slot for plan 9 partition\n");
633
		return;
634
	}
635
 
636
	/* set new partition active only if no others are */
637
	active = Active;	
638
	for(i=0; i<edit->npart; i++)
639
		if(((Dospart*)edit->part[i])->primary && (((Dospart*)edit->part[i])->active & Active))
640
			active = 0;
641
 
642
	/* add new plan 9 partition */
643
	bigsize *= sec2cyl;
644
	bigstart *= sec2cyl;
645
	if(bigstart == 0) {
646
		bigstart += edit->disk->s;
647
		bigsize -= edit->disk->s;
648
	}
649
	p = mkpart(nil, 1, bigstart, bigsize, nil);
650
	p->active = active;
651
	p->changed = 1;
652
	p->type = Type9;
653
	edit->changed = 1;
654
	if(err = addpart(edit, p)) {
655
		fprint(2, "error adding plan9 partition: %s\n", err);
656
		return;
657
	}
658
}
659
 
660
typedef struct Name Name;
661
struct Name {
662
	char *name;
663
	Name *link;
664
};
665
Name *namelist;
666
static void
667
plan9print(Dospart *part, int fd)
668
{
669
	int i, ok;
670
	char *name, *vname;
671
	Name *n;
672
	vlong start, end;
673
	char *sep;
674
 
675
	vname = types[part->type].name;
676
	if(vname==nil || strcmp(vname, "")==0) {
677
		part->ctlname = "";
678
		return;
679
	}
680
 
681
	start = mbroffset+part->lba;
682
	end = start+part->size;
683
 
684
	/* avoid names like plan90 */
685
	i = strlen(vname) - 1;
686
	if(vname[i] >= '0' && vname[i] <= '9')
687
		sep = ".";
688
	else
689
		sep = "";
690
 
691
	i = 0;
692
	name = emalloc(strlen(vname)+10);
693
 
694
	sprint(name, "%s", vname);
695
	do {
696
		ok = 1;
697
		for(n=namelist; n; n=n->link) {
698
			if(strcmp(name, n->name) == 0) {
699
				i++;
700
				sprint(name, "%s%s%d", vname, sep, i);
701
				ok = 0;
702
			}
703
		}
704
	} while(ok == 0);
705
 
706
	n = emalloc(sizeof(*n));
707
	n->name = name;
708
	n->link = namelist;
709
	namelist = n;
710
	part->ctlname = name;
711
 
712
	if(fd >= 0)
713
		print("part %s %lld %lld\n", name, start, end);
714
}
715
 
716
static void
717
freenamelist(void)
718
{
719
	Name *n, *next;
720
 
721
	for(n=namelist; n; n=next) {
722
		next = n->link;
723
		free(n);
724
	}
725
	namelist = nil;
726
}
727
 
728
static void
729
cmdprintctl(Edit *edit, int ctlfd)
730
{
731
	int i;
732
 
733
	freenamelist();
734
	for(i=0; i<edit->npart; i++)
735
		plan9print((Dospart*)edit->part[i], -1);
736
	ctldiff(edit, ctlfd);
737
}
738
 
739
static char*
740
cmdokname(Edit*, char *name)
741
{
742
	char *q;
743
 
744
	if(name[0] != 'p' && name[0] != 's')
745
		return "name must be pN or sN";
746
 
747
	strtol(name+1, &q, 10);
748
	if(*q != '\0')
749
		return "name must be pN or sN";
750
 
751
	return nil;
752
}
753
 
754
#define TB (1024LL*GB)
755
#define GB (1024*1024*1024)
756
#define MB (1024*1024)
757
#define KB (1024)
758
 
759
static void
760
cmdsum(Edit *edit, Part *vp, vlong a, vlong b)
761
{
762
	char *name, *ty;
763
	char buf[3];
764
	char *suf;
765
	Dospart *p;
766
	vlong sz, div;
767
 
768
	p = (Dospart*)vp;
769
 
770
	buf[0] = p && p->changed ? '\'' : ' ';
771
	buf[1] = p && (p->active & Active) ? '*' : ' ';
772
	buf[2] = '\0';
773
 
774
	name = p ? p->name : "empty";
775
	ty = p ? typestr0(p->type) : "";
776
 
777
	sz = (b-a)*edit->disk->secsize*sec2cyl;
778
	if(sz >= 1*TB){
779
		suf = "TB";
780
		div = TB;
781
	}else if(sz >= 1*GB){
782
		suf = "GB";
783
		div = GB;
784
	}else if(sz >= 1*MB){
785
		suf = "MB";
786
		div = MB;
787
	}else if(sz >= 1*KB){
788
		suf = "KB";
789
		div = KB;
790
	}else{
791
		suf = "B ";
792
		div = 1;
793
	}
794
 
795
	if(div == 1)
796
		print("%s %-12s %*lld %-*lld (%lld cylinders, %lld %s) %s\n", buf, name,
797
			edit->disk->width, a, edit->disk->width, b, b-a, sz, suf, ty);
798
	else
799
		print("%s %-12s %*lld %-*lld (%lld cylinders, %lld.%.2d %s) %s\n", buf, name,
800
			edit->disk->width, a, edit->disk->width, b,  b-a,
801
			sz/div, (int)(((sz%div)*100)/div), suf, ty);
802
}
803
 
804
static char*
805
cmdadd(Edit *edit, char *name, vlong start, vlong end)
806
{
807
	Dospart *p;
808
 
809
	if(!haveroom(edit, name[0]=='p', start))
810
		return "no room for partition";
811
	start *= sec2cyl;
812
	end *= sec2cyl;
813
	if(start == 0 || name[0] != 'p')
814
		start += edit->disk->s;
815
	p = mkpart(name, name[0]=='p', start, end-start, nil);
816
	p->changed = 1;
817
	p->type = Type9;
818
	return addpart(edit, p);
819
}
820
 
821
static char*
822
cmddel(Edit *edit, Part *p)
823
{
824
	return delpart(edit, p);
825
}
826
 
827
static char*
828
cmdwrite(Edit *edit)
829
{
830
	wrpart(edit);
831
	return nil;
832
}
833
 
834
static char *help = 
835
	"A name - set partition active\n"
836
	"P - print table in ctl format\n"
837
	"R - restore disk back to initial configuration and exit\n"
838
	"e - show empty dos partitions\n"
839
	"t name [type] - set partition type\n";
840
 
841
static char*
842
cmdhelp(Edit*)
843
{
844
	print("%s\n", help);
845
	return nil;
846
}
847
 
848
static char*
849
cmdactive(Edit *edit, int nf, char **f)
850
{
851
	int i;
852
	Dospart *p, *ip;
853
 
854
	if(nf != 2)
855
		return "args";
856
 
857
	if(f[1][0] != 'p')
858
		return "cannot set secondary partition active";
859
 
860
	if((p = (Dospart*)findpart(edit, f[1])) == nil)
861
		return "unknown partition";
862
 
863
	for(i=0; i<edit->npart; i++) {
864
		ip = (Dospart*)edit->part[i];
865
		if(ip->active & Active) {
866
			ip->active &= ~Active;
867
			ip->changed = 1;
868
			edit->changed = 1;
869
		}
870
	}
871
 
872
	if((p->active & Active) == 0) {
873
		p->active |= Active;
874
		p->changed = 1;
875
		edit->changed = 1;
876
	}
877
 
878
	return nil;
879
}
880
 
881
static char*
882
strupr(char *s)
883
{
884
	char *p;
885
 
886
	for(p=s; *p; p++)
887
		*p = toupper(*p);
888
	return s;
889
}
890
 
891
static void
892
dumplist(void)
893
{
894
	int i, n;
895
 
896
	n = 0;
897
	for(i=0; i<256; i++) {
898
		if(types[i].desc) {
899
			print("%-16s", types[i].desc);
900
			if(n++%4 == 3)
901
				print("\n");
902
		}
903
	}
904
	if(n%4)
905
		print("\n");
906
}
907
 
908
static char*
909
cmdtype(Edit *edit, int nf, char **f)
910
{
911
	char *q;
912
	Dospart *p;
913
	int i;
914
 
915
	if(nf < 2)
916
		return "args";
917
 
918
	if((p = (Dospart*)findpart(edit, f[1])) == nil)
919
		return "unknown partition";
920
 
921
	if(nf == 2) {
922
		for(;;) {
923
			fprint(2, "new partition type [? for list]: ");
924
			q = getline(edit);
925
			if(q[0] == '?')
926
				dumplist();
927
			else
928
				break;
929
		}
930
	} else
931
		q = f[2];
932
 
933
	strupr(q);
934
	for(i=0; i<256; i++)
935
		if(types[i].desc && strcmp(types[i].desc, q) == 0)
936
			break;
937
	if(i < 256 && p->type != i) {
938
		p->type = i;
939
		p->changed = 1;
940
		edit->changed = 1;
941
	}
942
	return nil;
943
}
944
 
945
static char*
946
cmdext(Edit *edit, int nf, char **f)
947
{
948
	switch(f[0][0]) {
949
	case 'A':
950
		return cmdactive(edit, nf, f);
951
	case 't':
952
		return cmdtype(edit, nf, f);
953
	case 'R':
954
		recover(edit);
955
		return nil;
956
	default:
957
		return "unknown command";
958
	}
959
}
960
 
961
static int
962
Dfmt(Fmt *f)
963
{
964
	char buf[60];
965
	uchar *p;
966
	int c, h, s;
967
 
968
	p = va_arg(f->args, uchar*);
969
	h = p[0];
970
	c = p[2];
971
	c |= (p[1]&0xC0)<<2;
972
	s = (p[1] & 0x3F);
973
 
974
	sprint(buf, "%d/%d/%d", c, h, s);
975
	return fmtstrcpy(f, buf);
976
}
977
 
978
static void
979
writechs(Disk *disk, uchar *p, vlong lba)
980
{
981
	int c, h, s;
982
 
983
	s = lba % disk->s;
984
	h = (lba / disk->s) % disk->h;
985
	c = lba / (disk->s * disk->h);
986
 
987
	if(c >= 1024) {
988
		c = 1023;
989
		h = disk->h - 1;
990
		s = disk->s - 1;
991
	}
992
 
993
	p[0] = h;
994
	p[1] = ((s+1) & 0x3F) | ((c>>2) & 0xC0);
995
	p[2] = c;
996
}
997
 
998
static void
999
wrtentry(Disk *disk, Tentry *tp, int type, u32int xbase, u32int lba, u32int end)
1000
{
1001
	tp->type = type;
1002
	writechs(disk, &tp->starth, lba);
1003
	writechs(disk, &tp->endh, end-1);
1004
	putle32(tp->xlba, lba-xbase);
1005
	putle32(tp->xsize, end-lba);
1006
}
1007
 
1008
static int
1009
wrextend(Edit *edit, int i, vlong xbase, vlong startlba, vlong *endlba)
1010
{
1011
	int ni;
1012
	Table table;
1013
	Tentry *tp, *ep;
1014
	Dospart *p;
1015
	Disk *disk;
1016
 
1017
	if(i == edit->npart){
1018
		*endlba = edit->disk->secs;
1019
	Finish:
1020
		if(startlba < *endlba){
1021
			disk = edit->disk;
1022
			diskread(disk, &table, Tablesz, mbroffset+startlba, Toffset);
1023
			tp = table.entry;
1024
			ep = tp+NTentry;
1025
			for(; tp<ep; tp++)
1026
				memset(tp, 0, sizeof *tp);
1027
			table.magic[0] = Magic0;
1028
			table.magic[1] = Magic1;
1029
 
1030
			if(diskwrite(edit->disk, &table, Tablesz, mbroffset+startlba, Toffset) < 0)
1031
				recover(edit);
1032
		}
1033
		return i;
1034
	}
1035
 
1036
	p = (Dospart*)edit->part[i];
1037
	if(p->primary){
1038
		*endlba = (vlong)p->start*sec2cyl;
1039
		goto Finish;
1040
	}
1041
 
1042
	disk = edit->disk;
1043
	diskread(disk, &table, Tablesz, mbroffset+startlba, Toffset);
1044
	tp = table.entry;
1045
	ep = tp+NTentry;
1046
 
1047
	ni = wrextend(edit, i+1, xbase, p->end*sec2cyl, endlba);
1048
 
1049
	*tp = p->Tentry;
1050
	wrtentry(disk, tp, p->type, startlba, startlba+disk->s, p->end*sec2cyl);
1051
	tp++;
1052
 
1053
	if(p->end*sec2cyl != *endlba){
1054
		memset(tp, 0, sizeof *tp);
1055
		wrtentry(disk, tp, TypeEXTENDED, xbase, p->end*sec2cyl, *endlba);
1056
		tp++;
1057
	}
1058
 
1059
	for(; tp<ep; tp++)
1060
		memset(tp, 0, sizeof *tp);
1061
 
1062
	table.magic[0] = Magic0;
1063
	table.magic[1] = Magic1;
1064
 
1065
	if(diskwrite(edit->disk, &table, Tablesz, mbroffset+startlba, Toffset) < 0)
1066
		recover(edit);
1067
	return ni;
1068
}	
1069
 
1070
static void
1071
wrpart(Edit *edit)
1072
{	
1073
	int i, ni, t;
1074
	Table table;
1075
	Tentry *tp, *ep;
1076
	Disk *disk;
1077
	vlong s, endlba;
1078
	Dospart *p;
1079
 
1080
	disk = edit->disk;
1081
 
1082
	diskread(disk, &table, Tablesz, mbroffset, Toffset);
1083
 
1084
	tp = table.entry;
1085
	ep = tp+NTentry;
1086
	for(i=0; i<edit->npart && tp<ep; ) {
1087
		p = (Dospart*)edit->part[i];
1088
		if(p->start == 0)
1089
			s = disk->s;
1090
		else
1091
			s = p->start*sec2cyl;
1092
		if(p->primary) {
1093
			*tp = p->Tentry;
1094
			wrtentry(disk, tp, p->type, 0, s, p->end*sec2cyl);
1095
			tp++;
1096
			i++;
1097
		} else {
1098
			ni = wrextend(edit, i, p->start*sec2cyl, p->start*sec2cyl, &endlba);
1099
			memset(tp, 0, sizeof *tp);
1100
			if(endlba >= 1024*sec2cyl)
1101
				t = TypeEXTHUGE;
1102
			else
1103
				t = TypeEXTENDED;
1104
			wrtentry(disk, tp, t, 0, s, endlba);
1105
			tp++;
1106
			i = ni;
1107
		}
1108
	}
1109
	for(; tp<ep; tp++)
1110
		memset(tp, 0, sizeof(*tp));
1111
 
1112
	if(i != edit->npart)
1113
		sysfatal("cannot happen #1");
1114
 
1115
	if(diskwrite(disk, &table, Tablesz, mbroffset, Toffset) < 0)
1116
		recover(edit);
1117
 
1118
	/* bring parts up to date */
1119
	freenamelist();
1120
	for(i=0; i<edit->npart; i++)
1121
		plan9print((Dospart*)edit->part[i], -1);
1122
 
1123
	if(ctldiff(edit, disk->ctlfd) < 0)
1124
		fprint(2, "?warning: partitions could not be updated in devsd\n");
1125
}