Warning: Attempt to read property "date" on null in /usr/local/www/websvn.planix.org/blame.php on line 247

Warning: Attempt to read property "msg" on null in /usr/local/www/websvn.planix.org/blame.php on line 247
WebSVN – planix.SVN – Blame – /os/branches/feature_fixcpp/sys/src/cmd/disk/prep/edit.c – Rev 2

Subversion Repositories planix.SVN

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
/*
2
 * disk partition editor
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
char*
12
getline(Edit *edit)
13
{
14
	static int inited;
15
	static Biobuf bin;
16
	char *p;
17
	int n;
18
 
19
	if(!inited){
20
		Binit(&bin, 0, OREAD);
21
		inited = 1;
22
	}
23
	p = Brdline(&bin, '\n');
24
	n = Blinelen(&bin);
25
	if(p == nil || n < 1){
26
		if(edit->changed)
27
			fprint(2, "?warning: changes not written\n");
28
		exits(0);
29
	}
30
	p[n - 1] = '\0';
31
	while(isspace(*p))
32
		p++;
33
	return p;
34
}
35
 
36
Part*
37
findpart(Edit *edit, char *name)
38
{
39
	int i;
40
 
41
	for(i=0; i<edit->npart; i++)
42
		if(strcmp(edit->part[i]->name, name) == 0)
43
			return edit->part[i];
44
	return nil;
45
}
46
 
47
static char*
48
okname(Edit *edit, char *name)
49
{
50
	int i;
51
	static char msg[100];
52
 
53
	if(name[0] == '\0')
54
		return "partition has no name";
55
 
56
//	if(strlen(name) >= NAMELEN)
57
//		return "name too long";
58
//
59
	for(i=0; i<edit->npart; i++) {
60
		if(strcmp(name, edit->part[i]->name) == 0) {
61
			sprint(msg, "already have partition with name \"%s\"", name);
62
			return msg;
63
		}
64
	}
65
	return nil;
66
}
67
 
68
char*
69
addpart(Edit *edit, Part *p)
70
{
71
	int i;
72
	static char msg[100];
73
	char *err;
74
 
75
	if(err = okname(edit, p->name))
76
		return err;
77
 
78
	for(i=0; i<edit->npart; i++) {
79
		if(p->start < edit->part[i]->end && edit->part[i]->start < p->end) {
80
			sprint(msg, "\"%s\" %lld-%lld overlaps with \"%s\" %lld-%lld",
81
				p->name, p->start, p->end,
82
				edit->part[i]->name, edit->part[i]->start, edit->part[i]->end);
83
		//	return msg;
84
		}
85
	}
86
 
87
	if(edit->npart >= nelem(edit->part))	
88
		return "too many partitions";
89
 
90
	edit->part[i=edit->npart++] = p;
91
	for(; i > 0 && p->start < edit->part[i-1]->start; i--) {
92
		edit->part[i] = edit->part[i-1];
93
		edit->part[i-1] = p;
94
	}
95
 
96
	if(p->changed)
97
		edit->changed = 1;
98
	return nil;
99
}
100
 
101
char*
102
delpart(Edit *edit, Part *p)
103
{
104
	int i;
105
 
106
	for(i=0; i<edit->npart; i++)
107
		if(edit->part[i] == p)
108
			break;
109
	assert(i < edit->npart);
110
	edit->npart--;
111
	for(; i<edit->npart; i++)
112
		edit->part[i] = edit->part[i+1];
113
 
114
	edit->changed = 1;
115
	return nil;
116
}
117
 
118
static char*
119
editdot(Edit *edit, int argc, char **argv)
120
{
121
	char *err;
122
	vlong ndot;
123
 
124
	if(argc == 1) {
125
		print("\t. %lld\n", edit->dot);
126
		return nil;
127
	}
128
 
129
	if(argc > 2)
130
		return "args";
131
 
132
	if(err = parseexpr(argv[1], edit->dot, edit->end, edit->end, &ndot))
133
		return err;
134
 
135
	edit->dot = ndot;
136
	return nil;
137
}
138
 
139
static char*
140
editadd(Edit *edit, int argc, char **argv)
141
{
142
	char *name, *err, *q;
143
	static char msg[100];
144
	vlong start, end, maxend;
145
	int i;
146
 
147
	if(argc < 2)
148
		return "args";
149
 
150
	name = estrdup(argv[1]);
151
	if((err = okname(edit, name)) || (err = edit->okname(edit, name)))
152
		return err;
153
 
154
	if(argc >= 3)
155
		q = argv[2];
156
	else {
157
		fprint(2, "start %s: ", edit->unit);
158
		q = getline(edit);
159
	}
160
	if(err = parseexpr(q, edit->dot, edit->end, edit->end, &start))
161
		return err;
162
 
163
	if(start < 0 || start >= edit->end)
164
		return "start out of range";
165
 
166
	for(i=0; i < edit->npart; i++) {
167
		if(edit->part[i]->start <= start && start < edit->part[i]->end) {
168
			sprint(msg, "start %s in partition \"%s\"", edit->unit, edit->part[i]->name);
169
			return msg;
170
		}
171
	}
172
 
173
	maxend = edit->end;
174
	for(i=0; i < edit->npart; i++)
175
		if(start < edit->part[i]->start && edit->part[i]->start < maxend)
176
			maxend = edit->part[i]->start;
177
 
178
	if(argc >= 4)
179
		q = argv[3];
180
	else {
181
		fprint(2, "end [%lld..%lld] ", start, maxend);
182
		q = getline(edit);
183
	}
184
	if(err = parseexpr(q, edit->dot, maxend, edit->end, &end))
185
		return err;
186
 
187
	if(start == end)
188
		return "size zero partition";
189
 
190
	if(end <= start || end > maxend)
191
		return "end out of range";
192
 
193
	if(argc > 4)
194
		return "args";
195
 
196
	if(err = edit->add(edit, name, start, end))
197
		return err;
198
 
199
	edit->dot = end;
200
	return nil;
201
}
202
 
203
static char*
204
editdel(Edit *edit, int argc, char **argv)
205
{
206
	Part *p;
207
 
208
	if(argc != 2)
209
		return "args";
210
 
211
	if((p = findpart(edit, argv[1])) == nil)
212
		return "no such partition";
213
 
214
	return edit->del(edit, p);
215
}
216
 
217
static char *helptext = 
218
	". [newdot] - display or set value of dot\n"
219
	"a name [start [end]] - add partition\n"
220
	"d name - delete partition\n"
221
	"h - print help message\n"
222
	"p - print partition table\n"
223
	"P - print commands to update sd(3) device\n"
224
	"w - write partition table\n"
225
	"q - quit\n";
226
 
227
static char*
228
edithelp(Edit *edit, int, char**)
229
{
230
	print("%s", helptext);
231
	if(edit->help)
232
		return edit->help(edit);
233
	return nil;
234
}
235
 
236
static char*
237
editprint(Edit *edit, int argc, char**)
238
{
239
	vlong lastend;
240
	int i;
241
	Part **part;
242
 
243
	if(argc != 1)
244
		return "args";
245
 
246
	lastend = 0;
247
	part = edit->part;
248
	for(i=0; i<edit->npart; i++) {
249
		if(lastend < part[i]->start)
250
			edit->sum(edit, nil, lastend, part[i]->start);
251
		edit->sum(edit, part[i], part[i]->start, part[i]->end);
252
		lastend = part[i]->end;
253
	}
254
	if(lastend < edit->end)
255
		edit->sum(edit, nil, lastend, edit->end);
256
	return nil;
257
}
258
 
259
char*
260
editwrite(Edit *edit, int argc, char**)
261
{
262
	int i;
263
	char *err;
264
 
265
	if(argc != 1)
266
		return "args";
267
 
268
	if(edit->disk->rdonly)
269
		return "read only";
270
 
271
	err = edit->write(edit);
272
	if(err)
273
		return err;
274
	for(i=0; i<edit->npart; i++)
275
		edit->part[i]->changed = 0;
276
	edit->changed = 0;
277
	return nil;
278
}
279
 
280
static char*
281
editquit(Edit *edit, int argc, char**)
282
{
283
	static int warned;
284
 
285
	if(argc != 1) {
286
		warned = 0;
287
		return "args";
288
	}
289
 
290
	if(edit->changed && (!edit->warned || edit->lastcmd != 'q')) {
291
		edit->warned = 1;
292
		return "changes unwritten";
293
	}
294
 
295
	exits(0);
296
	return nil;	/* not reached */
297
}
298
 
299
char*
300
editctlprint(Edit *edit, int argc, char **)
301
{
302
	if(argc != 1)
303
		return "args";
304
 
305
	if(edit->printctl)
306
		edit->printctl(edit, 1);
307
	else
308
		ctldiff(edit, 1);
309
	return nil;
310
}
311
 
312
typedef struct Cmd Cmd;
313
struct Cmd {
314
	char c;
315
	char *(*fn)(Edit*, int ,char**);
316
};
317
 
318
Cmd cmds[] = {
319
	'.',	editdot,
320
	'a',	editadd,
321
	'd',	editdel,
322
	'?',	edithelp,
323
	'h',	edithelp,
324
	'P',	editctlprint,
325
	'p',	editprint,
326
	'w',	editwrite,
327
	'q',	editquit,
328
};
329
 
330
void
331
runcmd(Edit *edit, char *cmd)
332
{
333
	char *f[10], *err;
334
	int i, nf;
335
 
336
	while(*cmd && isspace(*cmd))
337
		cmd++;
338
 
339
	nf = tokenize(cmd, f, nelem(f));
340
	if(nf >= 10) {
341
		fprint(2, "?\n");
342
		return;
343
	}
344
 
345
	if(nf < 1)
346
		return;
347
	if(strlen(f[0]) != 1) {
348
		fprint(2, "?\n");
349
		return;
350
	}
351
 
352
	err = nil;
353
	for(i=0; i<nelem(cmds); i++) {
354
		if(cmds[i].c == f[0][0]) {
355
			err = cmds[i].fn(edit, nf, f);
356
			break;
357
		}
358
	}
359
	if(i == nelem(cmds)){
360
		if(edit->ext)
361
			err = edit->ext(edit, nf, f);
362
		else
363
			err = "unknown command";
364
	}
365
	if(err) 
366
		fprint(2, "?%s\n", err);
367
	edit->lastcmd = f[0][0];
368
}
369
 
370
static Part*
371
ctlmkpart(char *name, vlong start, vlong end, int changed)
372
{
373
	Part *p;
374
 
375
	p = emalloc(sizeof(*p));
376
	p->name = estrdup(name);
377
	p->ctlname = estrdup(name);
378
	p->start = start;
379
	p->end = end;
380
	p->changed = changed;
381
	return p;
382
}
383
 
384
static void
385
rdctlpart(Edit *edit)
386
{
387
	int i, nline, nf;
388
	char *line[128];
389
	char buf[4096];
390
	vlong a, b;
391
	char *f[5];
392
	Disk *disk;
393
 
394
	disk = edit->disk;
395
	edit->nctlpart = 0;
396
	seek(disk->ctlfd, 0, 0);
397
	if(readn(disk->ctlfd, buf, sizeof buf) <= 0) {
398
		return;
399
	}
400
 
401
	nline = getfields(buf, line, nelem(line), 1, "\n");
402
	for(i=0; i<nline; i++){
403
		if(strncmp(line[i], "part ", 5) != 0)
404
			continue;
405
 
406
		nf = getfields(line[i], f, nelem(f), 1, " \t\r");
407
		if(nf != 4 || strcmp(f[0], "part") != 0)
408
			break;
409
 
410
		a = strtoll(f[2], 0, 0);
411
		b = strtoll(f[3], 0, 0);
412
 
413
		if(a >= b)
414
			break;
415
 
416
		/* only gather partitions contained in the disk partition we are editing */
417
		if(a < disk->offset ||  disk->offset+disk->secs < b)
418
			continue;
419
 
420
		a -= disk->offset;
421
		b -= disk->offset;
422
 
423
		/* the partition we are editing does not count */
424
		if(strcmp(f[1], disk->part) == 0)
425
			continue;
426
 
427
		if(edit->nctlpart >= nelem(edit->ctlpart)) {
428
			fprint(2, "?too many partitions in ctl file\n");
429
			exits("ctlpart");
430
		}
431
		edit->ctlpart[edit->nctlpart++] = ctlmkpart(f[1], a, b, 0);
432
	}
433
}
434
 
435
static vlong
436
ctlstart(Part *p)
437
{
438
	if(p->ctlstart)
439
		return p->ctlstart;
440
	return p->start;
441
}
442
 
443
static vlong
444
ctlend(Part *p)
445
{
446
	if(p->ctlend)
447
		return p->ctlend;
448
	return p->end;
449
}
450
 
451
static int
452
areequiv(Part *p, Part *q)
453
{
454
	if(p->ctlname[0]=='\0' || q->ctlname[0]=='\0')
455
		return 0;
456
 
457
	return strcmp(p->ctlname, q->ctlname) == 0
458
			&& ctlstart(p) == ctlstart(q) && ctlend(p) == ctlend(q);
459
}
460
 
461
static void
462
unchange(Edit *edit, Part *p)
463
{
464
	int i;
465
	Part *q;
466
 
467
	for(i=0; i<edit->nctlpart; i++) {
468
		q = edit->ctlpart[i];
469
		if(p->start <= q->start && q->end <= p->end) {
470
			q->changed = 0;
471
		}
472
	}
473
assert(p->changed == 0);
474
}
475
 
476
int
477
ctldiff(Edit *edit, int ctlfd)
478
{
479
	int i, j, waserr;
480
	Part *p;
481
	vlong offset;
482
 
483
	rdctlpart(edit);
484
 
485
	/* everything is bogus until we prove otherwise */
486
	for(i=0; i<edit->nctlpart; i++)
487
		edit->ctlpart[i]->changed = 1;
488
 
489
	/*
490
	 * partitions with same info have not changed,
491
	 * and neither have partitions inside them.
492
	 */
493
	for(i=0; i<edit->nctlpart; i++)
494
		for(j=0; j<edit->npart; j++)
495
			if(areequiv(edit->ctlpart[i], edit->part[j])) {
496
				unchange(edit, edit->ctlpart[i]);
497
				break;
498
			}
499
 
500
	waserr = 0;
501
	/*
502
	 * delete all the changed partitions except data (we'll add them back if necessary) 
503
	 */
504
	for(i=0; i<edit->nctlpart; i++) {
505
		p = edit->ctlpart[i];
506
		if(p->changed)
507
		if(fprint(ctlfd, "delpart %s\n", p->ctlname)<0) {
508
			fprint(2, "delpart failed: %s: %r\n", p->ctlname);
509
			waserr = -1;
510
		}
511
	}
512
 
513
	/*
514
	 * add all the partitions from the real list;
515
	 * this is okay since adding a parition with
516
	 * information identical to what is there is a no-op.
517
	 */
518
	offset = edit->disk->offset;
519
	for(i=0; i<edit->npart; i++) {
520
		p = edit->part[i];
521
		if(p->ctlname[0]) {
522
			if(fprint(ctlfd, "part %s %lld %lld\n", p->ctlname, offset+ctlstart(p), offset+ctlend(p)) < 0) {
523
				fprint(2, "adding part failed: %s: %r\n", p->ctlname);
524
				waserr = -1;
525
			}
526
		}
527
	}
528
	return waserr;
529
}
530
 
531
void*
532
emalloc(ulong sz)
533
{
534
	void *v;
535
 
536
	v = malloc(sz);
537
	if(v == nil)
538
		sysfatal("malloc %lud fails", sz);
539
	memset(v, 0, sz);
540
	return v;
541
}
542
 
543
char*
544
estrdup(char *s)
545
{
546
	s = strdup(s);
547
	if(s == nil)
548
		sysfatal("strdup (%.10s) fails", s);
549
	return s;
550
}
551