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
 * prep - prepare plan9 disk partition
3
 */
4
#include <u.h>
5
#include <libc.h>
6
#include <bio.h>
7
#include <disk.h>
8
#include "edit.h"
9
 
10
enum {
11
	Maxpath = 128,
12
};
13
 
14
static int	blank;
15
static int	file;
16
static int	doautox;
17
static int	printflag;
18
static Part	**opart;
19
static int	nopart;
20
static char	*osecbuf;
21
static char	*secbuf;
22
static int	rdonly;
23
static int	dowrite;
24
static int	docache;
25
static int	donvram;
26
 
27
static void	autoxpart(Edit*);
28
static Part	*mkpart(char*, vlong, vlong, int);
29
static void	rdpart(Edit*);
30
static void	wrpart(Edit*);
31
static void	checkfat(Disk*);
32
 
33
static void 	cmdsum(Edit*, Part*, vlong, vlong);
34
static char 	*cmdadd(Edit*, char*, vlong, vlong);
35
static char 	*cmddel(Edit*, Part*);
36
static char 	*cmdokname(Edit*, char*);
37
static char 	*cmdwrite(Edit*);
38
static char	*cmdctlprint(Edit*, int, char**);
39
 
40
Edit edit = {
41
	.add=	cmdadd,
42
	.del=	cmddel,
43
	.okname=cmdokname,
44
	.sum=	cmdsum,
45
	.write=	cmdwrite,
46
 
47
	.unit=	"sector",
48
};
49
 
50
typedef struct Auto Auto;
51
struct Auto
52
{
53
	char	*name;
54
	uvlong	min;
55
	uvlong	max;
56
	uint	weight;
57
	uchar	alloc;
58
	uvlong	size;
59
};
60
 
61
#define TB (1024LL*GB)
62
#define GB (1024*1024*1024)
63
#define MB (1024*1024)
64
#define KB (1024)
65
 
66
/*
67
 * Order matters -- this is the layout order on disk.
68
 */
69
Auto autox[] = 
70
{
71
	{	"9fat",		10*MB,	100*MB,	10,	},
72
	{	"nvram",	512,	512,	1,	},
73
	{	"fscfg",	1024,	8192,	1,	},
74
	{	"fs",		200*MB,	0,	10,	},
75
	{	"fossil",	200*MB,	0,	4,	},
76
	{	"arenas",	500*MB,	0,	20,	},
77
	{	"isect",	25*MB,	0,	1,	},
78
	{	"bloom",	4*MB,	512*MB,	1,	},
79
 
80
	{	"other",	200*MB,	0,	4,	},
81
	{	"swap",		100*MB,	512*MB,	1,	},
82
	{	"cache",	50*MB,	1*GB,	2,	},
83
};
84
 
85
void
86
usage(void)
87
{
88
	fprint(2, "usage: disk/prep [-bcfprw] [-a partname]... [-s sectorsize] /dev/sdC0/plan9\n");
89
	exits("usage");
90
}
91
 
92
void
93
main(int argc, char **argv)
94
{
95
	int i;
96
	char *p;
97
	Disk *disk;
98
	vlong secsize;
99
 
100
	secsize = 0;
101
	ARGBEGIN{
102
	case 'a':
103
		p = EARGF(usage());
104
		for(i=0; i<nelem(autox); i++){
105
			if(strcmp(p, autox[i].name) == 0){
106
				if(autox[i].alloc){
107
					fprint(2, "you said -a %s more than once.\n", p);
108
					usage();
109
				}
110
				autox[i].alloc = 1;
111
				break;
112
			}
113
		}
114
		if(i == nelem(autox)){
115
			fprint(2, "don't know how to create automatic partition %s\n", p);
116
			usage();
117
		}
118
		doautox = 1;
119
		break;
120
	case 'b':
121
		blank++;
122
		break;
123
	case 'c':
124
		docache++;
125
		break;
126
	case 'f':
127
		file++;
128
		break;
129
	case 'n':
130
		donvram++;
131
		break;
132
	case 'p':
133
		printflag++;
134
		rdonly++;
135
		break;
136
	case 'r':
137
		rdonly++;
138
		break;
139
	case 's':
140
		secsize = atoi(ARGF());
141
		break;
142
	case 'w':
143
		dowrite++;
144
		break;
145
	default:
146
		usage();
147
	}ARGEND;
148
 
149
	if(argc != 1)
150
		usage();
151
 
152
	disk = opendisk(argv[0], rdonly, file);
153
	if(disk == nil)
154
		sysfatal("cannot open disk: %r");
155
 
156
	if(secsize != 0) {
157
		disk->secsize = secsize;
158
		disk->secs = disk->size / secsize;
159
	}
160
	edit.end = disk->secs;
161
 
162
	checkfat(disk);
163
 
164
	secbuf = emalloc(disk->secsize+1);
165
	osecbuf = emalloc(disk->secsize+1);
166
	edit.disk = disk;
167
 
168
	if(blank == 0)
169
		rdpart(&edit);
170
 
171
	opart = emalloc(edit.npart*sizeof(opart[0]));
172
 
173
	/* save old partition table */
174
	for(i=0; i<edit.npart; i++)
175
		opart[i] = edit.part[i];
176
	nopart = edit.npart;
177
 
178
	if(printflag) {
179
		runcmd(&edit, "P");
180
		exits(0);
181
	}
182
 
183
	if(doautox)
184
		autoxpart(&edit);
185
 
186
	if(dowrite) {
187
		runcmd(&edit, "w");
188
		exits(0);
189
	}
190
 
191
	runcmd(&edit, "p");
192
	for(;;) {
193
		fprint(2, ">>> ");
194
		runcmd(&edit, getline(&edit));
195
	}
196
}
197
 
198
static void
199
cmdsum(Edit *edit, Part *p, vlong a, vlong b)
200
{
201
	vlong sz, div;
202
	char *suf, *name;
203
	char c;
204
 
205
	c = p && p->changed ? '\'' : ' ';
206
	name = p ? p->name : "empty";
207
 
208
	sz = (b-a)*edit->disk->secsize;
209
	if(sz >= 1*TB){
210
		suf = "TB";
211
		div = TB;
212
	}else if(sz >= 1*GB){
213
		suf = "GB";
214
		div = GB;
215
	}else if(sz >= 1*MB){
216
		suf = "MB";
217
		div = MB;
218
	}else if(sz >= 1*KB){
219
		suf = "KB";
220
		div = KB;
221
	}else{
222
		if (sz < 0)
223
			fprint(2, "%s: negative size!\n", argv0);
224
		suf = "B ";
225
		div = 1;
226
	}
227
 
228
	if(div == 1)
229
		print("%c %-12s %*lld %-*lld (%lld sectors, %lld %s)\n", c, name,
230
			edit->disk->width, a, edit->disk->width, b, b-a, sz, suf);
231
	else
232
		print("%c %-12s %*lld %-*lld (%lld sectors, %lld.%.2d %s)\n", c, name,
233
			edit->disk->width, a, edit->disk->width, b, b-a,
234
			sz/div, (int)(((sz%div)*100)/div), suf);
235
}
236
 
237
static char*
238
cmdadd(Edit *edit, char *name, vlong start, vlong end)
239
{
240
	if(start < 2 && strcmp(name, "9fat") != 0)
241
		return "overlaps with the pbs and/or the partition table";
242
 
243
	return addpart(edit, mkpart(name, start, end, 1));
244
}
245
 
246
static char*
247
cmddel(Edit *edit, Part *p)
248
{
249
	return delpart(edit, p);
250
}
251
 
252
static char*
253
cmdwrite(Edit *edit)
254
{
255
	wrpart(edit);
256
	return nil;
257
}
258
 
259
static char isfrog[256]={
260
	/*NUL*/	1, 1, 1, 1, 1, 1, 1, 1,
261
	/*BKS*/	1, 1, 1, 1, 1, 1, 1, 1,
262
	/*DLE*/	1, 1, 1, 1, 1, 1, 1, 1,
263
	/*CAN*/	1, 1, 1, 1, 1, 1, 1, 1,
264
	[' ']	1,
265
	['/']	1,
266
	[0x7f]	1,
267
};
268
 
269
static char*
270
cmdokname(Edit*, char *elem)
271
{
272
	for(; *elem; elem++)
273
		if(isfrog[*(uchar*)elem])
274
			return "bad character in name";
275
	return nil;
276
}
277
 
278
static Part*
279
mkpart(char *name, vlong start, vlong end, int changed)
280
{
281
	Part *p;
282
 
283
	p = emalloc(sizeof(*p));
284
	p->name = estrdup(name);
285
	p->ctlname = estrdup(name);
286
	p->start = start;
287
	p->end = end;
288
	p->changed = changed;
289
	return p;
290
}
291
 
292
/* plan9 partition is first sector of the disk */
293
static void
294
rdpart(Edit *edit)
295
{
296
	int i, nline, nf, waserr;
297
	vlong a, b;
298
	char *line[128];
299
	char *f[5];
300
	char *err;
301
	Disk *disk;
302
 
303
	disk = edit->disk;
304
	seek(disk->fd, disk->secsize, 0);
305
	if(readn(disk->fd, osecbuf, disk->secsize) != disk->secsize)
306
		return;
307
	osecbuf[disk->secsize] = '\0';
308
	memmove(secbuf, osecbuf, disk->secsize+1);
309
 
310
	if(strncmp(secbuf, "part", 4) != 0){
311
		fprint(2, "no plan9 partition table found\n");
312
		return;
313
	}
314
 
315
	waserr = 0;
316
	nline = getfields(secbuf, line, nelem(line), 1, "\n");
317
	for(i=0; i<nline; i++){
318
		if(strncmp(line[i], "part", 4) != 0) {
319
		Error:
320
			if(waserr == 0)
321
				fprint(2, "syntax error reading partition\n");
322
			waserr = 1;
323
			continue;
324
		}
325
 
326
		nf = getfields(line[i], f, nelem(f), 1, " \t\r");
327
		if(nf != 4 || strcmp(f[0], "part") != 0)
328
			goto Error;
329
 
330
		a = strtoll(f[2], 0, 0);
331
		b = strtoll(f[3], 0, 0);
332
		if(a >= b)
333
			goto Error;
334
 
335
		if(err = addpart(edit, mkpart(f[1], a, b, 0))) {
336
			fprint(2, "?%s: not continuing\n", err);
337
			exits("partition");
338
		}
339
	}
340
}
341
 
342
static vlong
343
min(vlong a, vlong b)
344
{
345
	if(a < b)
346
		return a;
347
	return b;
348
}
349
 
350
static void
351
autoxpart(Edit *edit)
352
{
353
	int i, totw, futz;
354
	vlong secs, secsize, s;
355
	char *err;
356
 
357
	if(edit->npart > 0) {
358
		if(doautox)
359
			fprint(2, "partitions already exist; not repartitioning\n");
360
		return;
361
	}
362
 
363
	secs = edit->disk->secs;
364
	secsize = edit->disk->secsize;
365
	for(;;){
366
		/* compute total weights */
367
		totw = 0;
368
		for(i=0; i<nelem(autox); i++){
369
			if(autox[i].alloc==0 || autox[i].size)
370
				continue;
371
			totw += autox[i].weight;
372
		}
373
		if(totw == 0)
374
			break;
375
 
376
		if(secs <= 0){
377
			fprint(2, "ran out of disk space during autoxpartition.\n");
378
			return;
379
		}
380
 
381
		/* assign any minimums for small disks */
382
		futz = 0;
383
		for(i=0; i<nelem(autox); i++){
384
			if(autox[i].alloc==0 || autox[i].size)
385
				continue;
386
			s = (secs*autox[i].weight)/totw;
387
			if(s < autox[i].min/secsize){
388
				autox[i].size = autox[i].min/secsize;
389
				secs -= autox[i].size;
390
				futz = 1;
391
				break;
392
			}
393
		}
394
		if(futz)
395
			continue;
396
 
397
		/* assign any maximums for big disks */
398
		futz = 0;
399
		for(i=0; i<nelem(autox); i++){
400
			if(autox[i].alloc==0 || autox[i].size)
401
				continue;
402
			s = (secs*autox[i].weight)/totw;
403
			if(autox[i].max && s > autox[i].max/secsize){
404
				autox[i].size = autox[i].max/secsize;
405
				secs -= autox[i].size;
406
				futz = 1;
407
				break;
408
			}
409
		}
410
		if(futz)
411
			continue;
412
 
413
		/* finally, assign partition sizes according to weights */
414
		for(i=0; i<nelem(autox); i++){
415
			if(autox[i].alloc==0 || autox[i].size)
416
				continue;
417
			s = (secs*autox[i].weight)/totw;
418
			autox[i].size = s;
419
 
420
			/* use entire disk even in face of rounding errors */
421
			secs -= autox[i].size;
422
			totw -= autox[i].weight;
423
		}
424
	}
425
 
426
	for(i=0; i<nelem(autox); i++)
427
		if(autox[i].alloc)
428
			print("%s %llud\n", autox[i].name, autox[i].size);
429
 
430
	s = 0;
431
	for(i=0; i<nelem(autox); i++){
432
		if(autox[i].alloc == 0)
433
			continue;
434
		if(err = addpart(edit, mkpart(autox[i].name, s, s+autox[i].size, 1)))
435
			fprint(2, "addpart %s: %s\n", autox[i].name, err);
436
		s += autox[i].size;
437
	}
438
}
439
 
440
static void
441
restore(Edit *edit, int ctlfd)
442
{
443
	int i;
444
	vlong offset;
445
 
446
	offset = edit->disk->offset;
447
	fprint(2, "attempting to restore partitions to previous state\n");
448
	if(seek(edit->disk->wfd, edit->disk->secsize, 0) != 0){
449
		fprint(2, "cannot restore: error seeking on disk\n");
450
		exits("inconsistent");
451
	}
452
 
453
	if(write(edit->disk->wfd, osecbuf, edit->disk->secsize) != edit->disk->secsize){
454
		fprint(2, "cannot restore: couldn't write old partition table to disk\n");
455
		exits("inconsistent");
456
	}
457
 
458
	if(ctlfd >= 0){
459
		for(i=0; i<edit->npart; i++)
460
			fprint(ctlfd, "delpart %s", edit->part[i]->name);
461
		for(i=0; i<nopart; i++){
462
			if(fprint(ctlfd, "part %s %lld %lld", opart[i]->name, opart[i]->start+offset, opart[i]->end+offset) < 0){
463
				fprint(2, "restored disk partition table but not kernel; reboot\n");
464
				exits("inconsistent");
465
			}
466
		}
467
	}
468
	exits("restored");
469
}
470
 
471
static void
472
wrpart(Edit *edit)
473
{
474
	int i, n;
475
	Disk *disk;
476
 
477
	disk = edit->disk;
478
 
479
	memset(secbuf, 0, disk->secsize);
480
	n = 0;
481
	for(i=0; i<edit->npart; i++)
482
		n += snprint(secbuf+n, disk->secsize-n, "part %s %lld %lld\n", 
483
			edit->part[i]->name, edit->part[i]->start, edit->part[i]->end);
484
 
485
	if(seek(disk->wfd, disk->secsize, 0) != disk->secsize){
486
		fprint(2, "error seeking %d %lld on disk: %r\n", disk->wfd, disk->secsize);
487
		exits("seek");
488
	}
489
 
490
	if(write(disk->wfd, secbuf, disk->secsize) != disk->secsize){
491
		fprint(2, "error writing partition table to disk\n");
492
		restore(edit, -1);
493
	}
494
 
495
	if(ctldiff(edit, disk->ctlfd) < 0)
496
		fprint(2, "?warning: partitions could not be updated in devsd\n");
497
}
498
 
499
/*
500
 * Look for a boot sector in sector 1, as would be
501
 * the case if editing /dev/sdC0/data when that
502
 * was really a bootable disk.
503
 */
504
static void
505
checkfat(Disk *disk)
506
{
507
	uchar buf[32];
508
 
509
	if(seek(disk->fd, disk->secsize, 0) < 0
510
	|| read(disk->fd, buf, sizeof(buf)) < sizeof(buf))
511
		return;
512
 
513
	if(buf[0] != 0xEB || buf[1] != 0x3C || buf[2] != 0x90)
514
		return;
515
 
516
	fprint(2, 
517
		"there's a fat partition where the\n"
518
		"plan9 partition table would go.\n"
519
		"if you really want to overwrite it, zero\n"
520
		"the second sector of the disk and try again\n");
521
 
522
	exits("fat partition");
523
}