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
 * parse plan.ini or /cfg/pxe/%E file into low memory
3
 */
4
#include	"u.h"
5
#include	"../port/lib.h"
6
#include	"mem.h"
7
#include	"dat.h"
8
#include	"fns.h"
9
#include	"io.h"
10
#include	"ureg.h"
11
#include	"pool.h"
12
#include	"../port/netif.h"
13
#include	"../ip/ip.h"
14
#include	"pxe.h"
15
 
16
typedef struct {
17
	char*	name;
18
	int	start;
19
	int	end;
20
} Mblock;
21
 
22
typedef struct {
23
	char*	tag;
24
	Mblock*	mb;
25
} Mitem;
26
 
27
Chan *conschan;
28
 
29
static Mblock mblock[MAXCONF];
30
static int nmblock;
31
static Mitem mitem[MAXCONF];
32
static int nmitem;
33
static char* mdefault;
34
static char mdefaultbuf[10];
35
static int mtimeout;
36
 
37
static char*
38
comma(char* line, char** residue)
39
{
40
	char *q, *r;
41
 
42
	if((q = strchr(line, ',')) != nil){
43
		*q++ = 0;
44
		if(*q == ' ')
45
			q++;
46
	}
47
	*residue = q;
48
 
49
	if((r = strchr(line, ' ')) != nil)
50
		*r = 0;
51
 
52
	if(*line == ' ')
53
		line++;
54
	return line;
55
}
56
 
57
static Mblock*
58
findblock(char* name, char** residue)
59
{
60
	int i;
61
	char *p;
62
 
63
	p = comma(name, residue);
64
	for(i = 0; i < nmblock; i++){
65
		if(strcmp(p, mblock[i].name) == 0)
66
			return &mblock[i];
67
	}
68
	return nil;
69
}
70
 
71
static Mitem*
72
finditem(char* name, char** residue)
73
{
74
	int i;
75
	char *p;
76
 
77
	p = comma(name, residue);
78
	for(i = 0; i < nmitem; i++){
79
		if(strcmp(p, mitem[i].mb->name) == 0)
80
			return &mitem[i];
81
	}
82
	return nil;
83
}
84
 
85
/* timeout is in seconds */
86
int
87
getstr(char *prompt, char *buf, int size, char *def, int timeout)
88
{
89
	int len, isdefault;
90
	static char pbuf[PRINTSIZE];
91
 
92
	if(conschan == nil)
93
		panic("getstr: #c/cons not open");
94
	buf[0] = 0;
95
	isdefault = (def && *def);
96
	if(isdefault == 0){
97
		timeout = 0;
98
		snprint(pbuf, sizeof pbuf, "%s: ", prompt);
99
	}
100
	else if(timeout)
101
		snprint(pbuf, sizeof pbuf, "%s[default==%s (%ds timeout)]: ",
102
			prompt, def, timeout);
103
	else
104
		snprint(pbuf, sizeof pbuf, "%s[default==%s]: ", prompt, def);
105
	for (;;) {
106
		print("%s", pbuf);
107
		if (timeout > 0) {
108
			for(timeout *= 1000; timeout > 0; timeout -= 100) {
109
				if (qlen(kbdq) > 0)	/* if input queued */
110
					break; 
111
				tsleep(&up->sleep, return0, 0, 100);
112
			}
113
			if (timeout <= 0) {		/* use default */
114
				print("\n");
115
				len = 0;
116
				break;
117
			}
118
		}
119
		buf[0] = '\0';
120
		len = devtab[conschan->type]->read(conschan, buf, size - 1,
121
			conschan->offset);
122
		if(len >= 0)
123
			buf[len] = '\0';
124
		switch(len){
125
		case 0:				/* eof */
126
		case 1:				/* newline */
127
			len = 0;
128
			buf[len] = '\0';
129
			if(!isdefault)
130
				continue;
131
			break;
132
		}
133
		if(len < size - 1)
134
			break;
135
		print("line too long\n");
136
	}
137
	if(len == 0 && isdefault)
138
		strncpy(buf, def, size);
139
	return 0;
140
}
141
 
142
void
143
askbootfile(char *buf, int len, char **bootfp, int secs, char *def)
144
{
145
	getstr("\nBoot from", buf, len, def, secs);
146
	trimnl(buf);
147
	if (bootfp)
148
		kstrdup(bootfp, buf);
149
}
150
 
151
int
152
isconf(char *name)
153
{
154
	int i;
155
 
156
	for(i = 0; i < nconf; i++)
157
		if(cistrcmp(confname[i], name) == 0)
158
			return 1;
159
	return 0;
160
}
161
 
162
/* result is not malloced, unlike user-mode getenv() */
163
char*
164
getconf(char *name)
165
{
166
	int i, n, nmatch;
167
	char buf[120];
168
 
169
	nmatch = 0;
170
	for(i = 0; i < nconf; i++)
171
		if(cistrcmp(confname[i], name) == 0)
172
			nmatch++;
173
 
174
	switch(nmatch) {
175
	default:
176
		print("\n");
177
		nmatch = 0;
178
		for(i = 0; i < nconf; i++)
179
			if(cistrcmp(confname[i], name) == 0)
180
				print("%d. %s\n", ++nmatch, confval[i]);
181
		print("%d. none of the above\n", ++nmatch);
182
		do {
183
			getstr(name, buf, sizeof(buf), nil, 0);
184
			n = atoi(buf);
185
		} while(n < 1 || n > nmatch);
186
 
187
		for(i = 0; i < nconf; i++)
188
			if(cistrcmp(confname[i], name) == 0)
189
				if(--n == 0)
190
					return confval[i];
191
		break;
192
 
193
	case 1:
194
		for(i = 0; i < nconf; i++)
195
			if(cistrcmp(confname[i], name) == 0)
196
				return confval[i];
197
		break;
198
 
199
	case 0:
200
		break;
201
	}
202
	return nil;
203
}
204
 
205
static void
206
parsemenu(char* str, char* scratch, int len)
207
{
208
	Mitem *mi;
209
	Mblock *mb, *menu;
210
	char buf[20], *p, *q, *line[MAXCONF];
211
	int i, inblock, n, show;
212
 
213
	inblock = 0;
214
	menu = nil;
215
	memmove(scratch, str, len);
216
	n = getfields(scratch, line, MAXCONF, 0, "\n");
217
	if(n >= MAXCONF)
218
		print("warning: possibly too many lines in plan9.ini\n");
219
	for(i = 0; i < n; i++){
220
		p = line[i];
221
		if(inblock && *p == '['){
222
			mblock[nmblock].end = i;
223
			if(strcmp(mblock[nmblock].name, "menu") == 0)
224
				menu = &mblock[nmblock];
225
			nmblock++;
226
			inblock = 0;
227
		}
228
		if(*p == '['){
229
			if(nmblock == 0 && i != 0){
230
				mblock[nmblock].name = "common";
231
				mblock[nmblock].start = 0;
232
				mblock[nmblock].end = i;
233
				nmblock++;
234
			}
235
			q = strchr(p+1, ']');
236
			if(q == nil || *(q+1) != 0){
237
				print("malformed menu block header - %s\n", p);
238
				return;
239
			}
240
			*q = 0;
241
			mblock[nmblock].name = p+1;
242
			mblock[nmblock].start = i+1;
243
			inblock = 1;
244
		}
245
	}
246
 
247
	if(inblock){
248
		mblock[nmblock].end = i;
249
		nmblock++;
250
	}
251
	if(menu == nil)
252
		return;
253
	if(nmblock < 2){
254
		print("incomplete menu specification\n");
255
		return;
256
	}
257
 
258
	for(i = menu->start; i < menu->end; i++){
259
		p = line[i];
260
		if(cistrncmp(p, "menuitem=", 9) == 0){
261
			p += 9;
262
			if((mb = findblock(p, &q)) == nil){
263
				print("no block for menuitem %s\n", p);
264
				return;
265
			}
266
			if(q != nil)
267
				mitem[nmitem].tag = q;
268
			else
269
				mitem[nmitem].tag = mb->name;
270
			mitem[nmitem].mb = mb;
271
			nmitem++;
272
		}
273
		else if(cistrncmp(p, "menudefault=", 12) == 0){
274
			p += 12;
275
			if((mi = finditem(p, &q)) == nil){
276
				print("no item for menudefault %s\n", p);
277
				return;
278
			}
279
			if(q != nil)
280
				mtimeout = strtol(q, 0, 0);
281
			snprint(mdefaultbuf, sizeof mdefaultbuf, "%ld",
282
				mi-mitem+1);
283
			mdefault = mdefaultbuf;
284
		}
285
		else if(cistrncmp(p, "menuconsole=", 12) == 0){
286
			p += 12;
287
			p = comma(p, &q);
288
			i8250config(p);
289
		}
290
		else{
291
			print("invalid line in [menu] block - %s\n", p);
292
			return;
293
		}
294
	}
295
 
296
again:
297
	print("\nPlan 9 Startup Menu:\n====================\n");
298
	for(i = 0; i < nmitem; i++)
299
		print("    %d. %s\n", i+1, mitem[i].tag);
300
	for(;;){
301
		getstr("Selection", buf, sizeof(buf), mdefault, mtimeout);
302
		mtimeout = 0;
303
		i = strtol(buf, &p, 0)-1;
304
		if(i < 0 || i >= nmitem)
305
			goto again;
306
		switch(*p){
307
		case 'p':
308
		case 'P':
309
			show = 1;
310
			print("\n");
311
			break;
312
		case 0:
313
		case '\n':
314
			show = 0;
315
			break;
316
		default:
317
			continue;
318
 
319
		}
320
		mi = &mitem[i];
321
 
322
		p = str;
323
		p += snprint(p, len, "menuitem=%s\n", mi->mb->name);
324
		for(i = 0; i < nmblock; i++){
325
			mb = &mblock[i];
326
			if(mi->mb != mb && cistrcmp(mb->name, "common") != 0)
327
				continue;
328
			for(n = mb->start; n < mb->end; n++)
329
				p += snprint(p, &str[len] - p, "%s\n", line[n]);
330
		}
331
 
332
		if(show){
333
			for(q = str; q < p; q += i){
334
				if((i = print(q)) <= 0)
335
					break;
336
			}
337
			goto again;
338
		}
339
		break;
340
	}
341
	print("\n");
342
}
343
 
344
/* dig out tables created by l16r.s in real mode */
345
void
346
readlsconf(void)
347
{
348
	int i, n;
349
	uchar *p;
350
	MMap *map;
351
	u64int addr, len;
352
 
353
	/*
354
	 * we could be running above 1MB, so put bios tables in low memory,
355
	 * not after end.
356
	 */
357
	p = (uchar*)KADDR(BIOSTABLES);
358
	for(n = 0; n < nelem(mmap); n++){
359
		if(*p == 0)
360
			break;
361
		if(memcmp(p, "APM\0", 4) == 0){
362
			p += 20;
363
			continue;
364
		}
365
		else if(memcmp(p, "MAP\0", 4) == 0){
366
			map = (MMap*)p;
367
 
368
			switch(map->type){
369
			default:
370
				if(v_flag)
371
					print("type %ud", map->type);
372
				break;
373
			case 1:
374
				if(v_flag)
375
					print("Memory");
376
				break;
377
			case 2:
378
				if(v_flag)
379
					print("reserved");
380
				break;
381
			case 3:
382
				if(v_flag)
383
					print("ACPI Reclaim Memory");
384
				break;
385
			case 4:
386
				if(v_flag)
387
					print("ACPI NVS Memory");
388
				break;
389
			}
390
			addr = (((u64int)map->base[1])<<32)|map->base[0];
391
			len = (((u64int)map->length[1])<<32)|map->length[0];
392
			if(v_flag)
393
				print("\t%#16.16lluX %#16.16lluX (%llud)\n",
394
					addr, addr+len, len);
395
 
396
			if(nmmap < nelem(mmap)){
397
				memmove(&mmap[nmmap], map, sizeof(MMap));
398
				mmap[nmmap].size = 20;
399
				nmmap++;
400
			}
401
			p += 24;
402
			continue;
403
		}
404
		else{
405
			 /* ideally we shouldn't print here */
406
			print("\nweird low-memory map at %#p:\n", p);
407
			for(i = 0; i < 24; i++)
408
				print(" %2.2uX", *(p+i));
409
			print("\n");
410
			delay(5000);
411
		}
412
		break;
413
	}
414
}
415
 
416
void
417
addconf(char *fmt, ...)
418
{
419
	va_list arg;
420
 
421
	va_start(arg, fmt);
422
	vseprint(BOOTARGS+strlen(BOOTARGS), BOOTARGS+BOOTARGSLEN, fmt, arg);
423
	va_end(arg);
424
}
425
 
426
void
427
dumpbootargs(void)
428
{
429
	char *p, *nl;
430
 
431
	/* in the boot, we can only print PRINTSIZE (256) bytes at a time. */
432
	print("boot args: ");
433
	for (p = (char *)BOOTARGS; *p != '\0'; p = nl) {
434
		nl = strchr(p, '\n');
435
		if (nl != nil) {
436
			++nl;
437
			print("%.*s", (int)(nl - p), p);
438
		}
439
	}
440
}
441
 
442
void
443
changeconf(char *fmt, ...)
444
{
445
	va_list arg;
446
	char *p, *q, pref[20], buf[128];
447
 
448
	va_start(arg, fmt);
449
	vseprint(buf, buf+sizeof buf, fmt, arg);
450
	va_end(arg);
451
 
452
	pref[0] = '\n';
453
	strncpy(pref+1, buf, 19);
454
	pref[19] = '\0';
455
	if(p = strchr(pref, '='))
456
		*(p+1) = '\0';
457
	else
458
		print("warning: did not change %s in plan9.ini\n", buf);
459
 
460
	/* find old line by looking for \nwhat= */
461
	if(strncmp(BOOTARGS, pref+1, strlen(pref+1)) == 0)
462
		p = BOOTARGS;
463
	else if(p = strstr(BOOTARGS, pref))
464
		p++;
465
	else
466
		p = nil;
467
 
468
	/* move rest of args up, deleting what= line. */
469
	if(p != nil && (q = strchr(p, '\n')) != nil)
470
		memmove(p, q+1, strlen(q+1)+1);
471
 
472
	/* add replacement to end */
473
	addconf("%s", buf);
474
}
475
 
476
/*
477
 *  read configuration file
478
 */
479
static char id[8] = "ZORT 0\r\n";
480
 
481
int
482
dotini(char *inibuf)
483
{
484
	int blankline, i, incomment, inspace, n;
485
	char *cp, *p, *q, *line[MAXCONF];
486
 
487
	cp = inibuf;
488
 
489
	/*
490
	 * Strip out '\r', change '\t' -> ' '.
491
	 * Change runs of spaces into single spaces.
492
	 * Strip out trailing spaces, blank lines.
493
	 *
494
	 * We do this before we make the copy so that if we 
495
	 * need to change the copy, it is already fairly clean.
496
	 * The main need is in the case when plan9.ini has been
497
	 * padded with lots of trailing spaces, as is the case 
498
	 * for those created during a distribution install.
499
	 */
500
	p = cp;
501
	blankline = 1;
502
	incomment = inspace = 0;
503
	for(q = cp; *q; q++){
504
		if(*q == '\r')
505
			continue;
506
		if(*q == '\t')
507
			*q = ' ';
508
		if(*q == ' '){
509
			inspace = 1;
510
			continue;
511
		}
512
		if(*q == '\n'){
513
			if(!blankline){
514
				if(!incomment)
515
					*p++ = '\n';
516
				blankline = 1;
517
			}
518
			incomment = inspace = 0;
519
			continue;
520
		}
521
		if(inspace){
522
			if(!blankline && !incomment)
523
				*p++ = ' ';
524
			inspace = 0;
525
		}
526
		if(blankline && *q == '#')
527
			incomment = 1;
528
		blankline = 0;
529
		if(!incomment)
530
			*p++ = *q;	
531
	}
532
	if(p > cp && p[-1] != '\n')
533
		*p++ = '\n';
534
	*p++ = 0;
535
	n = p-cp;
536
 
537
	parsemenu(cp, BOOTARGS, n);
538
 
539
	/*
540
	 * Keep a copy.
541
	 * We could change this to pass the parsed strings
542
	 * to the booted programme instead of the raw
543
	 * string, then it only gets done once.
544
	 */
545
	if(strncmp(cp, id, sizeof(id))){
546
		memmove(BOOTARGS, id, sizeof(id));
547
		if(n+1+sizeof(id) >= BOOTARGSLEN)
548
			n -= sizeof(id);
549
		memmove(BOOTARGS+sizeof(id), cp, n+1);
550
	}
551
	else
552
		memmove(BOOTARGS, cp, n+1);
553
 
554
	n = getfields(cp, line, MAXCONF, 0, "\n");
555
	for(i = 0; i < n; i++){
556
		cp = strchr(line[i], '=');
557
		if(cp == 0)
558
			continue;
559
		*cp++ = 0;
560
		if(cp - line[i] >= NAMELEN+1)
561
			*(line[i]+NAMELEN-1) = 0;
562
		confname[nconf] = line[i];
563
		confval[nconf] = cp;
564
		nconf++;
565
	}
566
	return 0;
567
}