Subversion Repositories planix.SVN

Rev

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

Rev Author Line No. Line
2 - 1
#include "all.h"
2
#include "io.h"
3
 
4
static void	dowormcopy(void);
5
static int	dodevcopy(void);
6
 
7
struct {
8
	char*	icharp;
9
	char*	charp;
10
	int	error;
11
	int	newconf;	/* clear before start */
12
	int	modconf;	/* write back when done */
13
	int	nextiter;
14
	int	lastiter;
15
	int	diriter;
16
	Device*	lastcw;
17
	Device*	devlist;
18
} f;
19
 
20
static Device* confdev;
21
static int copyworm = 0, copydev = 0;
22
static char *src, *dest;
23
 
24
static int resetparams;
25
 
26
Fspar fspar[] = {
27
	{ "blocksize",	RBUFSIZE, },
28
	{ "daddrbits",	sizeof(Off)*8, },
29
	{ "indirblks",	NIBLOCK, },
30
	{ "dirblks",	NDBLOCK, },
31
	{ "namelen",	NAMELEN, },
32
	{ nil, 0, },
33
};
34
 
35
int
36
devcmpr(Device *d1, Device *d2)
37
{
38
	while (d1 != d2) {
39
		if(d1 == nil || d2 == nil || d1->type != d2->type)
40
			return 1;
41
 
42
		switch(d1->type) {
43
		default:
44
			print("can't compare dev: %Z\n", d1);
45
			panic("devcmp");
46
			return 1;
47
 
48
		case Devmcat:
49
		case Devmlev:
50
		case Devmirr:
51
			d1 = d1->cat.first;
52
			d2 = d2->cat.first;
53
			while(d1 && d2) {
54
				if(devcmpr(d1, d2))
55
					return 1;
56
				d1 = d1->link;
57
				d2 = d2->link;
58
			}
59
			break;
60
 
61
		case Devnone:
62
			return 0;
63
 
64
		case Devro:
65
			d1 = d1->ro.parent;
66
			d2 = d2->ro.parent;
67
			break;
68
 
69
		case Devjuke:
70
		case Devcw:
71
			if(devcmpr(d1->cw.c, d2->cw.c))
72
				return 1;
73
			d1 = d1->cw.w;
74
			d2 = d2->cw.w;
75
			break;
76
 
77
		case Devfworm:
78
			d1 = d1->fw.fw;
79
			d2 = d2->fw.fw;
80
			break;
81
 
82
		case Devwren:
83
		case Devworm:
84
		case Devlworm:
85
			if(d1->wren.ctrl == d2->wren.ctrl)
86
			if(d1->wren.targ == d2->wren.targ)
87
			if(d1->wren.lun == d2->wren.lun)
88
				return 0;
89
			return 1;
90
 
91
		case Devpart:
92
			if(d1->part.base == d2->part.base)
93
			if(d1->part.size == d2->part.size) {
94
				d1 = d1->part.d;
95
				d2 = d2->part.d;
96
				break;
97
			}
98
			return 1;
99
		}
100
	}
101
	return 0;
102
}
103
 
104
void
105
cdiag(char *s, int c1)
106
{
107
 
108
	f.charp--;
109
	if(f.error == 0) {
110
		print("config diag: %s -- <%c>\n", s, c1);
111
		f.error = 1;
112
	}
113
}
114
 
115
int
116
cnumb(void)
117
{
118
	int c, n;
119
 
120
	c = *f.charp++;
121
	if(c == '<') {
122
		n = f.nextiter;
123
		if(n >= 0) {
124
			f.nextiter = n+f.diriter;
125
			if(n == f.lastiter) {
126
				f.nextiter = -1;
127
				f.lastiter = -1;
128
			}
129
			do {
130
				c = *f.charp++;
131
			} while (c != '>');
132
			return n;
133
		}
134
		n = cnumb();
135
		if(*f.charp++ != '-') {
136
			cdiag("- expected", f.charp[-1]);
137
			return 0;
138
		}
139
		c = cnumb();
140
		if(*f.charp++ != '>') {
141
			cdiag("> expected", f.charp[-1]);
142
			return 0;
143
		}
144
		f.lastiter = c;
145
		f.diriter = 1;
146
		if(n > c)
147
			f.diriter = -1;
148
		f.nextiter = n+f.diriter;
149
		return n;
150
	}
151
	if(!isascii(c) || !isdigit(c)) {
152
		cdiag("number expected", c);
153
		return 0;
154
	}
155
	n = 0;
156
	while(isascii(c) && isdigit(c)) {
157
		n = n*10 + (c-'0');
158
		c = *f.charp++;
159
	}
160
	f.charp--;
161
	return n;
162
}
163
 
164
Device*
165
config1(int c)
166
{
167
	Device *d, *t;
168
	int m;
169
 
170
	d = malloc(sizeof(Device));
171
	do {
172
		t = config();
173
		if(d->cat.first == 0)
174
			d->cat.first = t;
175
		else
176
			d->cat.last->link = t;
177
		d->cat.last = t;
178
		if(f.error)
179
			return devnone;
180
		m = *f.charp;
181
		if(c == '(' && m == ')')
182
			d->type = Devmcat;
183
		else if(c == '[' && m == ']')
184
			d->type = Devmlev;
185
		else if(c == '{' && m == '}')
186
			d->type = Devmirr;
187
	} while (d->type == 0);
188
	f.charp++;
189
	if(d->cat.first == d->cat.last)
190
		d = d->cat.first;
191
	return d;
192
}
193
 
194
static void
195
map(Device *d)
196
{
197
	Map *map;
198
 
199
	if (d->type != Devwren || d->wren.mapped)
200
		return;
201
	for (map = devmap; map != nil; map = map->next)
202
		if (devcmpr(d, map->fdev) == 0)
203
			break;
204
	if (map == nil)
205
		return;
206
	if (access(map->to, AEXIST) >= 0)
207
{ print("map: mapped wren %Z to existing file %s\n", d, map->to); // DEBUG
208
		d->wren.file = map->to;		/* wren -> file mapping */
209
}
210
	else if (map->tdev != nil)
211
{ print("map: mapped wren %Z to dev %Z\n", d, map->tdev); // DEBUG
212
		*d = *map->tdev;		/* wren -> wren mapping */
213
}
214
	else
215
		print("bad mapping %Z to %s; no such file or device",
216
			d, map->to);
217
	d->wren.mapped = 1;
218
}
219
 
220
Device*
221
config(void)
222
{
223
	int c, m;
224
	Device *d;
225
	char *icp;
226
 
227
	if(f.error)
228
		return devnone;
229
	d = malloc(sizeof(Device));
230
 
231
	c = *f.charp++;
232
	switch(c) {
233
	default:
234
		cdiag("unknown type", c);
235
		return devnone;
236
 
237
	case '(':	/* (d+) one or multiple cat */
238
	case '[':	/* [d+] one or multiple interleave */
239
	case '{':	/* {d+} a mirrored device and optional mirrors */
240
		return config1(c);
241
 
242
	case 'f':	/* fd fake worm */
243
		d->type = Devfworm;
244
		d->fw.fw = config();
245
		break;
246
 
247
	case 'n':
248
		d->type = Devnone;
249
		break;
250
 
251
	case 'w':	/* w[#.]#[.#] wren	[ctrl] unit [lun] */
252
	case 'r':	/* r# worm side */
253
	case 'l':	/* l# labelled-worm side */
254
		icp = f.charp;
255
		d->type = Devwren;
256
		d->wren.ctrl = 0;
257
		d->wren.targ = cnumb();
258
		d->wren.lun = 0;
259
		m = *f.charp;
260
		if(m == '.') {
261
			f.charp++;
262
			d->wren.lun = cnumb();
263
			m = *f.charp;
264
			if(m == '.') {
265
				f.charp++;
266
				d->wren.ctrl = d->wren.targ;
267
				d->wren.targ = d->wren.lun;
268
				d->wren.lun = cnumb();
269
			}
270
		}
271
		if(f.nextiter >= 0)
272
			f.charp = icp-1;
273
		if(c == 'r')		/* worms are virtual and not uniqued */
274
			d->type = Devworm;
275
		else if(c == 'l')
276
			d->type = Devlworm;
277
		else
278
			map(d);		/* subject wrens to optional mapping */
279
		break;
280
 
281
	case 'o':	/* o ro part of last cw */
282
		if(f.lastcw == 0) {
283
			cdiag("no cw to match", c);
284
			return devnone;
285
		}
286
		return f.lastcw->cw.ro;
287
 
288
	case 'j':	/* DD jukebox */
289
		d->type = Devjuke;
290
		d->j.j = config();
291
		d->j.m = config();
292
		break;
293
 
294
	case 'c':	/* cache/worm */
295
		d->type = Devcw;
296
		d->cw.c = config();
297
		d->cw.w = config();
298
		d->cw.ro = malloc(sizeof(Device));
299
		d->cw.ro->type = Devro;
300
		d->cw.ro->ro.parent = d;
301
		f.lastcw = d;
302
		break;
303
 
304
	case 'p':	/* pd#.# partition base% size% */
305
		d->type = Devpart;
306
		d->part.d = config();
307
		d->part.base = cnumb();
308
		c = *f.charp++;
309
		if(c != '.')
310
			cdiag("dot expected", c);
311
		d->part.size = cnumb();
312
		break;
313
 
314
	case 'x':	/* xD swab a device's metadata */
315
		d->type = Devswab;
316
		d->swab.d = config();
317
		break;
318
	}
319
	d->dlink = f.devlist;
320
	f.devlist = d;
321
	return d;
322
}
323
 
324
Device*
325
iconfig(char *s)
326
{
327
	Device *d;
328
 
329
	f.nextiter = -1;
330
	f.lastiter = -1;
331
	f.error = 0;
332
	f.icharp = s;
333
	f.charp = f.icharp;
334
	d = config();
335
	if(*f.charp) {
336
		cdiag("junk on end", *f.charp);
337
		f.error = 1;
338
	}
339
	return d;
340
}
341
 
342
int
343
testconfig(char *s)
344
{
345
	iconfig(s);
346
	return f.error;
347
}
348
 
349
/*
350
 * if b is a prefix of a, return 0.
351
 */
352
int
353
astrcmp(char *a, char *b)
354
{
355
	int n, c;
356
 
357
	n = strlen(b);
358
	if(memcmp(a, b, n) != 0)
359
		return 1;
360
	c = a[n];
361
	if(c == '\0')
362
		return 0;
363
	if(a[n+1])
364
		return 1;
365
	if(isascii(c) && isdigit(c))
366
		return 0;
367
	return 1;
368
}
369
 
370
static Fspar *
371
getpar(char *name)
372
{
373
	Fspar *fsp;
374
 
375
	for (fsp = fspar; fsp->name != nil; fsp++)
376
		if (strcmp(name, fsp->name) == 0)
377
			return fsp;
378
	return nil;
379
}
380
 
381
/*
382
 * continue to parse obsolete keywords so that old configurations can
383
 * still work.
384
 */
385
void
386
mergeconf(Iobuf *p)
387
{
388
	char word[Maxword+1];
389
	char *cp;
390
	Filsys *fs;
391
	Fspar *fsp;
392
 
393
	for (cp = p->iobuf; *cp != '\0'; cp++) {
394
		cp = getwrd(word, cp);
395
		if(word[0] == '\0')
396
			break;
397
		else if (word[0] == '#')
398
			while (*cp != '\n' && *cp != '\0')
399
				cp++;
400
		else if(strcmp(word, "service") == 0) {
401
			cp = getwrd(word, cp);
402
			if(service[0] == 0)
403
				strncpy(service, word, sizeof service);
404
		} else if(strcmp(word, "ipauth") == 0)	/* obsolete */
405
			cp = getwrd(word, cp);
406
		else if(astrcmp(word, "ip") == 0)	/* obsolete */
407
			cp = getwrd(word, cp);
408
		else if(astrcmp(word, "ipgw") == 0)	/* obsolete */
409
			cp = getwrd(word, cp);
410
		else if(astrcmp(word, "ipsntp") == 0)	/* obsolete */
411
			cp = getwrd(word, cp);
412
		else if(astrcmp(word, "ipmask") == 0)	/* obsolete */
413
			cp = getwrd(word, cp);
414
		else if(strcmp(word, "filsys") == 0) {
415
			cp = getwrd(word, cp);
416
			for(fs = filsys; fs < filsys + nelem(filsys) - 1 &&
417
			    fs->name; fs++)
418
				if(strcmp(fs->name, word) == 0)
419
					break;
420
			if (fs >= filsys + nelem(filsys) - 1)
421
				panic("out of filsys structures");
422
			if (fs->name && strcmp(fs->name, word) == 0 &&
423
			    fs->flags & FEDIT)
424
				cp = getwrd(word, cp);	/* swallow conf */
425
			else {
426
				fs->name = strdup(word);
427
				cp = getwrd(word, cp);
428
				if (word[0] == '\0')
429
					fs->conf = nil;
430
				else
431
					fs->conf = strdup(word);
432
			}
433
		} else if ((fsp = getpar(word)) != nil) {
434
			cp = getwrd(word, cp);
435
			if (!isascii(word[0]) || !isdigit(word[0]))
436
				print("bad %s value: %s", fsp->name, word);
437
			else
438
				fsp->declared = atol(word);
439
		} else {
440
			putbuf(p);
441
			panic("unknown keyword in config block: %s", word);
442
		}
443
 
444
		if(*cp != '\n') {
445
			putbuf(p);
446
			panic("syntax error in config block at `%s'", word);
447
		}
448
	}
449
}
450
 
451
void
452
cmd_printconf(int, char *[])
453
{
454
	char *p, *s;
455
	Iobuf *iob;
456
 
457
	iob = getbuf(confdev, 0, Brd);
458
	if(iob == nil)
459
		return;
460
	if(checktag(iob, Tconfig, 0)){
461
		putbuf(iob);
462
		return;
463
	}
464
 
465
	print("config %s\n", nvrgetconfig());
466
	for(s = p = iob->iobuf; *p != 0 && p < iob->iobuf+BUFSIZE; ){
467
		if(*p++ != '\n')
468
			continue;
469
		if (strncmp(s, "ip", 2) != 0)	/* don't print obsolete cmds */
470
			print("%.*s", (int)(p-s), s);
471
		s = p;
472
	}
473
	if(p != s)
474
		print("%.*s", (int)(p-s), s);
475
	print("end\n");
476
 
477
	putbuf(iob);
478
}
479
 
480
void
481
sysinit(void)
482
{
483
	int error;
484
	char *cp, *ep;
485
	Device *d;
486
	Filsys *fs;
487
	Fspar *fsp;
488
	Iobuf *p;
489
 
490
	cons.chan = fs_chaninit(Devcon, 1, 0);
491
 
492
start:
493
	/*
494
	 * part 1 -- read the config file
495
	 */
496
	devnone = iconfig("n");
497
 
498
	cp = nvrgetconfig();
499
	print("config %s\n", cp);
500
 
501
	confdev = d = iconfig(cp);
502
	devinit(d);
503
	if(f.newconf) {
504
		p = getbuf(d, 0, Bmod);
505
		memset(p->iobuf, 0, RBUFSIZE);
506
		settag(p, Tconfig, 0);
507
	} else
508
		p = getbuf(d, 0, Brd|Bmod);
509
	if(!p || checktag(p, Tconfig, 0))
510
		panic("config io");
511
 
512
	mergeconf(p);
513
 
514
	if (resetparams) {
515
		for (fsp = fspar; fsp->name != nil; fsp++)
516
			fsp->declared = 0;
517
		resetparams = 0;
518
	}
519
 
520
	for (fsp = fspar; fsp->name != nil; fsp++) {
521
		/* supply defaults from this cwfs instance */
522
		if (fsp->declared == 0) {
523
			fsp->declared = fsp->actual;
524
			f.modconf = 1;
525
		}
526
		/* warn if declared value is not our compiled-in value */
527
		if (fsp->declared != fsp->actual)
528
			print("warning: config %s %ld != compiled-in %ld\n",
529
				fsp->name, fsp->declared, fsp->actual);
530
	}
531
 
532
	if(f.modconf) {
533
		memset(p->iobuf, 0, BUFSIZE);
534
		p->flags |= Bmod|Bimm;
535
		cp = p->iobuf;
536
		ep = p->iobuf + RBUFSIZE - 1;
537
		if(service[0])
538
			cp = seprint(cp, ep, "service %s\n", service);
539
		for(fs=filsys; fs->name; fs++)
540
			if(fs->conf && fs->conf[0] != '\0')
541
				cp = seprint(cp, ep, "filsys %s %s\n", fs->name,
542
					fs->conf);
543
 
544
		for (fsp = fspar; fsp->name != nil; fsp++)
545
			cp = seprint(cp, ep, "%s %ld\n",
546
				fsp->name, fsp->declared);
547
 
548
		putbuf(p);
549
		f.modconf = f.newconf = 0;
550
		print("config block written\n");
551
		goto start;
552
	}
553
	putbuf(p);
554
 
555
	print("service    %s\n", service);
556
 
557
loop:
558
	/*
559
	 * part 2 -- squeeze out the deleted filesystems
560
	 */
561
	for(fs=filsys; fs->name; fs++)
562
		if(fs->conf == nil || fs->conf[0] == '\0') {
563
			for(; fs->name; fs++)
564
				*fs = *(fs+1);
565
			goto loop;
566
		}
567
	if(filsys[0].name == nil)
568
		panic("no filsys");
569
 
570
	/*
571
	 * part 3 -- compile the device expression
572
	 */
573
	error = 0;
574
	for(fs=filsys; fs->name; fs++) {
575
		print("filsys %s %s\n", fs->name, fs->conf);
576
		fs->dev = iconfig(fs->conf);
577
		if(f.error) {
578
			error = 1;
579
			continue;
580
		}
581
	}
582
	if(error)
583
		panic("fs config");
584
 
585
	/*
586
	 * part 4 -- initialize the devices
587
	 */
588
	for(fs=filsys; fs->name; fs++) {
589
		delay(3000);
590
		print("sysinit: %s\n", fs->name);
591
		if(fs->flags & FREAM)
592
			devream(fs->dev, 1);
593
		if(fs->flags & FRECOVER)
594
			devrecover(fs->dev);
595
		devinit(fs->dev);
596
	}
597
 
598
	/*
599
	 * part 5 -- optionally copy devices or worms
600
	 */
601
	if (copyworm) {
602
		dowormcopy();		/* can return if user quits early */
603
		panic("copyworm bailed out!");
604
	}
605
	if (copydev)
606
		if (dodevcopy() < 0)
607
			panic("copydev failed!");
608
		else
609
			panic("copydev done.");
610
}
611
 
612
/* an unfinished idea.  a non-blocking rawchar() would help. */
613
static int
614
userabort(char *msg)
615
{
616
	USED(msg);
617
	return 0;
618
}
619
 
620
static int
621
blockok(Device *d, Off a)
622
{
623
	Iobuf *p = getbuf(d, a, Brd);
624
 
625
	if (p == 0) {
626
		print("i/o error reading %Z block %lld\n", d, (Wideoff)a);
627
		return 0;
628
	}
629
	putbuf(p);
630
	return 1;
631
}
632
 
633
/*
634
 * special case for fake worms only:
635
 * we need to size the inner cw's worm device.
636
 * in particular, we want to avoid copying the fake-worm bitmap
637
 * at the end of the device.
638
 *
639
 * N.B.: for real worms (e.g. cw jukes), we need to compute devsize(cw(juke)),
640
 * *NOT* devsize(juke).
641
 */
642
static Device *
643
wormof(Device *dev)
644
{
645
	Device *worm = dev, *cw;
646
 
647
	if (dev->type == Devfworm) {
648
		cw = dev->fw.fw;
649
		if (cw != nil && cw->type == Devcw)
650
			worm = cw->cw.w;
651
	}
652
	// print("wormof(%Z)=%Z\n", dev, worm);
653
	return worm;
654
}
655
 
656
/*
657
 * return the number of the highest-numbered block actually written, plus 1.
658
 * 0 indicates an error.
659
 */
660
static Devsize
661
writtensize(Device *worm)
662
{
663
	Devsize lim = devsize(worm);
664
	Iobuf *p;
665
 
666
	print("devsize(%Z) = %lld\n", worm, (Wideoff)lim);
667
	if (!blockok(worm, 0) || !blockok(worm, lim-1))
668
		return 0;
669
	delay(5*1000);
670
	if (userabort("sanity checks"))
671
		return 0;
672
 
673
	/* find worm's last valid block in case "worm" is an (f)worm */
674
	while (lim > 0) {
675
		if (userabort("sizing")) {
676
			lim = 0;		/* you lose */
677
			break;
678
		}
679
		--lim;
680
		p = getbuf(worm, lim, Brd);
681
		if (p != 0) {			/* actually read one okay? */
682
			putbuf(p);
683
			break;
684
		}
685
	}
686
	print("limit(%Z) = %lld\n", worm, (Wideoff)lim);
687
	if (lim <= 0)
688
		return 0;
689
	return lim + 1;
690
}
691
 
692
/* copy worm fs from "main"'s inner worm to "output" */
693
static void
694
dowormcopy(void)
695
{
696
	Filsys *f1, *f2;
697
	Device *fdev, *from, *to = nil;
698
	Iobuf *p;
699
	Off a;
700
	Devsize lim;
701
 
702
	/*
703
	 * convert file system names into Filsyss and Devices.
704
	 */
705
 
706
	f1 = fsstr("main");
707
	if(f1 == nil)
708
		panic("main file system missing");
709
	fdev = f1->dev;
710
	from = wormof(fdev);			/* fake worm special */
711
	if (from->type != Devfworm && from->type != Devcw) {
712
		print("main file system is not a worm; copyworm may not do what you want!\n");
713
		print("waiting for 20 seconds...\n");
714
		delay(20000);
715
	}
716
 
717
	f2 = fsstr("output");
718
	if(f2 == nil) {
719
		print("no output file system - check only\n\n");
720
		print("reading worm from %Z (worm %Z)\n", fdev, from);
721
	} else {
722
		to = f2->dev;
723
		print("\ncopying worm from %Z (worm %Z) to %Z, starting in 8 seconds\n",
724
			fdev, from, to);
725
		delay(8000);
726
	}
727
	if (userabort("preparing to copy"))
728
		return;
729
 
730
	/*
731
	 * initialise devices, size them, more sanity checking.
732
	 */
733
 
734
	devinit(from);
735
	if (0 && fdev != from) {
736
		devinit(fdev);
737
		print("debugging, sizing %Z first\n", fdev);
738
		writtensize(fdev);
739
	}
740
	lim = writtensize(from);
741
	if(lim == 0)
742
		panic("no blocks to copy on %Z", from);
743
	if (to) {
744
		print("reaming %Z in 8 seconds\n", to);
745
		delay(8000);
746
		if (userabort("preparing to ream & copy"))
747
			return;
748
		devream(to, 0);
749
		devinit(to);
750
		print("copying worm: %lld blocks from %Z to %Z\n",
751
			(Wideoff)lim, from, to);
752
	}
753
	/* can't read to's blocks in case to is a real WORM device */
754
 
755
	/*
756
	 * Copy written fs blocks, a block at a time (or just read
757
	 * if no "output" fs).
758
	 */
759
 
760
	for (a = 0; a < lim; a++) {
761
		if (userabort("copy"))
762
			break;
763
		p = getbuf(from, a, Brd);
764
		/*
765
		 * if from is a real WORM device, we'll get errors trying to
766
		 * read unwritten blocks, but the unwritten blocks need not
767
		 * be contiguous.
768
		 */
769
		if (p == 0) {
770
			print("%lld not written yet; can't read\n", (Wideoff)a);
771
			continue;
772
		}
773
		if (to != 0 && devwrite(to, p->addr, p->iobuf) != 0) {
774
			print("out block %lld: write error; bailing",
775
				(Wideoff)a);
776
			break;
777
		}
778
		putbuf(p);
779
		if(a % 20000 == 0)
780
			print("block %lld %T\n", (Wideoff)a, time(nil));
781
	}
782
 
783
	/*
784
	 * wrap up: sync target, loop
785
	 */
786
	print("copied %lld blocks from %Z to %Z\n", (Wideoff)a, from, to);
787
	sync("wormcopy");
788
	delay(2000);
789
	print("looping; reset the machine at any time.\n");
790
	for (; ; )
791
		continue;		/* await reset */
792
}
793
 
794
/* copy device from src to dest */
795
static int
796
dodevcopy(void)
797
{
798
	Device *from, *to;
799
	Iobuf *p;
800
	Off a;
801
	Devsize lim, tosize;
802
 
803
	/*
804
	 * convert config strings into Devices.
805
	 */
806
	from = iconfig(src);
807
	if(f.error || from == nil) {
808
		print("bad src device %s\n", src);
809
		return -1;
810
	}
811
	to = iconfig(dest);
812
	if(f.error || to == nil) {
813
		print("bad dest device %s\n", dest);
814
		return -1;
815
	}
816
 
817
	/*
818
	 * initialise devices, size them, more sanity checking.
819
	 */
820
 
821
	devinit(from);
822
	lim = devsize(from);
823
	if(lim == 0)
824
		panic("no blocks to copy on %Z", from);
825
	devinit(to);
826
	tosize = devsize(to);
827
	if(tosize == 0)
828
		panic("no blocks to copy on %Z", to);
829
 
830
	/* use smaller of the device sizes */
831
	if (tosize < lim)
832
		lim = tosize;
833
 
834
	print("copy %Z to %Z in 8 seconds\n", from, to);
835
	delay(8000);
836
	if (userabort("preparing to copy"))
837
		return -1;
838
	print("copying dev: %lld blocks from %Z to %Z\n", (Wideoff)lim,
839
		from, to);
840
 
841
	/*
842
	 * Copy all blocks, a block at a time.
843
	 */
844
 
845
	for (a = 0; a < lim; a++) {
846
		if (userabort("copy"))
847
			break;
848
		p = getbuf(from, a, Brd);
849
		/*
850
		 * if from is a real WORM device, we'll get errors trying to
851
		 * read unwritten blocks, but the unwritten blocks need not
852
		 * be contiguous.
853
		 */
854
		if (p == 0) {
855
			print("%lld not written yet; can't read\n", (Wideoff)a);
856
			continue;
857
		}
858
		if (to != 0 && devwrite(to, p->addr, p->iobuf) != 0) {
859
			print("out block %lld: write error; bailing",
860
				(Wideoff)a);
861
			break;
862
		}
863
		putbuf(p);
864
		if(a % 20000 == 0)
865
			print("block %lld %T\n", (Wideoff)a, time(nil));
866
	}
867
 
868
	/*
869
	 * wrap up: sync target
870
	 */
871
	print("copied %lld blocks from %Z to %Z\n", (Wideoff)a, from, to);
872
	sync("devcopy");
873
	return 0;
874
}
875
 
876
static void
877
setconfig(char *dev)
878
{
879
	if (dev != nil && !testconfig(dev))
880
		nvrsetconfig(dev);	/* if it fails, it will complain */
881
}
882
 
883
void
884
arginit(void)
885
{
886
	int verb;
887
	char *line;
888
	char word[Maxword+1], *cp;
889
	Filsys *fs;
890
 
891
	if(nvrcheck() == 0) {
892
		setconfig(conf.confdev);
893
		if (!conf.configfirst)
894
			return;
895
	}
896
 
897
	/* nvr was bad or invoker requested configuration step */
898
	setconfig(conf.confdev);
899
	for (;;) {
900
		print("config: ");
901
		if ((line = Brdline(&bin, '\n')) == nil)
902
			return;
903
		line[Blinelen(&bin)-1] = '\0';
904
 
905
		cp = getwrd(word, line);
906
		if (word[0] == '\0' || word[0] == '#')
907
			continue;
908
		if(strcmp(word, "end") == 0)
909
			return;
910
		if(strcmp(word, "halt") == 0)
911
			exit();
912
		if(strcmp(word, "queryjuke") == 0) {
913
			getwrd(word, cp);
914
			if(testconfig(word) == 0)
915
				querychanger(iconfig(word));
916
			continue;
917
		}
918
 
919
		if(strcmp(word, "allow") == 0) {
920
			wstatallow = 1;
921
			writeallow = 1;
922
			continue;
923
		}
924
		if(strcmp(word, "copyworm") == 0) {
925
			copyworm = 1;
926
			continue;
927
		}
928
		if(strcmp(word, "copydev") == 0) {
929
			cp = getwrd(word, cp);
930
			if(testconfig(word))
931
				continue;
932
			src = strdup(word);
933
			getwrd(word, cp);
934
			if(testconfig(word))
935
				continue;
936
			dest = strdup(word);
937
			copydev = 1;
938
			continue;
939
		}
940
		if(strcmp(word, "noauth") == 0) {
941
			noauth = !noauth;
942
			continue;
943
		}
944
		if(strcmp(word, "noattach") == 0) {
945
			noattach = !noattach;
946
			continue;
947
		}
948
		if(strcmp(word, "readonly") == 0) {
949
			readonly = 1;
950
			continue;
951
		}
952
 
953
		if(strcmp(word, "ream") == 0) {
954
			verb = FREAM;
955
			goto gfsname;
956
		}
957
		if(strcmp(word, "recover") == 0) {
958
			verb = FRECOVER;
959
			goto gfsname;
960
		}
961
		if(strcmp(word, "filsys") == 0) {
962
			verb = FEDIT;
963
			goto gfsname;
964
		}
965
 
966
		if(strcmp(word, "nvram") == 0) {
967
			getwrd(word, cp);
968
			if(testconfig(word))
969
				continue;
970
			/* if it fails, it will complain */
971
			nvrsetconfig(word);
972
			continue;
973
		}
974
		if(strcmp(word, "config") == 0) {
975
			getwrd(word, cp);
976
			if(!testconfig(word) && nvrsetconfig(word) == 0)
977
				f.newconf = 1;
978
			continue;
979
		}
980
		if(strcmp(word, "service") == 0) {
981
			getwrd(word, cp);
982
			strncpy(service, word, sizeof service);
983
			f.modconf = 1;
984
			continue;
985
		}
986
		if (strcmp(word, "resetparams") == 0) {
987
			resetparams++;
988
			continue;
989
		}
990
 
991
		/*
992
		 * continue to parse obsolete keywords so that old
993
		 * configurations can still work.
994
		 */
995
		if (strcmp(word, "ipauth") != 0 &&
996
		    astrcmp(word, "ip") != 0 &&
997
		    astrcmp(word, "ipgw") != 0 &&
998
		    astrcmp(word, "ipmask") != 0 &&
999
		    astrcmp(word, "ipsntp") != 0) {
1000
			print("unknown config command\n");
1001
			print("\ttype end to get out\n");
1002
			continue;
1003
		}
1004
 
1005
		getwrd(word, cp);
1006
		f.modconf = 1;
1007
		continue;
1008
 
1009
	gfsname:
1010
		cp = getwrd(word, cp);
1011
		for(fs=filsys; fs->name; fs++)
1012
			if(strcmp(word, fs->name) == 0)
1013
				break;
1014
		if (fs->name == nil) {
1015
			memset(fs, 0, sizeof *fs);
1016
			fs->name = strdup(word);
1017
		}
1018
		switch(verb) {
1019
		case FREAM:
1020
			if(strcmp(fs->name, "main") == 0)
1021
				wstatallow = 1;	/* only set, never reset */
1022
			/* fallthrough */
1023
		case FRECOVER:
1024
			fs->flags |= verb;
1025
			break;
1026
		case FEDIT:
1027
			f.modconf = 1;
1028
			getwrd(word, cp);
1029
			fs->flags |= verb;
1030
			if(word[0] == 0)
1031
				fs->conf = nil;
1032
			else if(!testconfig(word))
1033
				fs->conf = strdup(word);
1034
			break;
1035
		}
1036
	}
1037
}