xref: /minix3/minix/commands/minix-service/parse.c (revision c58da9fbc35f86051ff0a75e6dd91e937d83cfff)
1 
2 #define _MINIX_SYSTEM 1
3 
4 #include <stdarg.h>
5 #include <assert.h>
6 #include <stdlib.h>
7 #include <stdio.h>
8 #include <string.h>
9 #include <errno.h>
10 #include <pwd.h>
11 #include <err.h>
12 #include <unistd.h>
13 #include <limits.h>
14 #include <lib.h>
15 #include <minix/config.h>
16 #include <minix/com.h>
17 #include <minix/const.h>
18 #include <minix/type.h>
19 #include <minix/ipc.h>
20 #include <minix/rs.h>
21 #include <minix/syslib.h>
22 #include <minix/bitmap.h>
23 #include <minix/paths.h>
24 #include <minix/sef.h>
25 #include <minix/dmap.h>
26 #include <minix/priv.h>
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 #include <configfile.h>
30 
31 #include <machine/archtypes.h>
32 #include <minix/timers.h>
33 
34 #include "config.h"
35 #include "proto.h"
36 
37 static int class_recurs;       /* Nesting level of class statements */
38 #define MAX_CLASS_RECURS        100     /* Max nesting level for classes */
39 
40 #include "parse.h"
41 
42 static void do_service(config_t *cpe, config_t *config, struct rs_config *);
43 
44 static void do_class(config_t *cpe, config_t *config, struct rs_config *rs_config)
45 {
46 	config_t *cp, *cp1;
47 
48 	if (class_recurs > MAX_CLASS_RECURS)
49 	{
50 		fatal(
51 		"do_class: nesting level too high for class '%s' at %s:%d",
52 			cpe->word, cpe->file, cpe->line);
53 	}
54 	class_recurs++;
55 
56 	/* Process classes */
57 	for (; cpe; cpe= cpe->next)
58 	{
59 		if (cpe->flags & CFG_SUBLIST)
60 		{
61 			fatal("do_class: unexpected sublist at %s:%d",
62 				cpe->file, cpe->line);
63 		}
64 		if (cpe->flags & CFG_STRING)
65 		{
66 			fatal("do_uid: unexpected string at %s:%d",
67 				cpe->file, cpe->line);
68 		}
69 
70 		/* Find entry for the class */
71 		for (cp= config; cp; cp= cp->next)
72 		{
73 			if (!(cp->flags & CFG_SUBLIST))
74 			{
75 				fatal("do_class: expected list at %s:%d",
76 					cp->file, cp->line);
77 			}
78 			cp1= cp->list;
79 			if ((cp1->flags & CFG_STRING) ||
80 				(cp1->flags & CFG_SUBLIST))
81 			{
82 				fatal("do_class: expected word at %s:%d",
83 					cp1->file, cp1->line);
84 			}
85 
86 			/* At this place we expect the word KW_SERVICE */
87 			if (strcmp(cp1->word, KW_SERVICE) != 0)
88 				fatal("do_class: exected word '%S' at %s:%d",
89 					KW_SERVICE, cp1->file, cp1->line);
90 
91 			cp1= cp1->next;
92 			if ((cp1->flags & CFG_STRING) ||
93 				(cp1->flags & CFG_SUBLIST))
94 			{
95 				fatal("do_class: expected word at %s:%d",
96 					cp1->file, cp1->line);
97 			}
98 
99 			/* At this place we expect the name of the service */
100 			if (strcmp(cp1->word, cpe->word) == 0)
101 				break;
102 		}
103 		if (cp == NULL)
104 		{
105 			fatal(
106 			"do_class: no entry found for class '%s' at %s:%d",
107 				cpe->word, cpe->file, cpe->line);
108 		}
109 		do_service(cp1->next, config, rs_config);
110 	}
111 
112 	class_recurs--;
113 }
114 
115 static void do_uid(config_t *cpe, struct rs_start *rs_start)
116 {
117 	uid_t uid;
118 	struct passwd *pw;
119 	char *check;
120 
121 	/* Process a uid */
122 	if (cpe->next != NULL)
123 	{
124 		fatal("do_uid: just one uid/login expected at %s:%d",
125 			cpe->file, cpe->line);
126 	}
127 
128 	if (cpe->flags & CFG_SUBLIST)
129 	{
130 		fatal("do_uid: unexpected sublist at %s:%d",
131 			cpe->file, cpe->line);
132 	}
133 	if (cpe->flags & CFG_STRING)
134 	{
135 		fatal("do_uid: unexpected string at %s:%d",
136 			cpe->file, cpe->line);
137 	}
138 	pw= getpwnam(cpe->word);
139 	if (pw != NULL)
140 		uid= pw->pw_uid;
141 	else
142 	{
143 		if (!strncmp(cpe->word, KW_SELF, strlen(KW_SELF)+1))
144 		{
145 			uid= getuid();	/* Real uid */
146 		}
147 		else {
148 			uid= strtol(cpe->word, &check, 0);
149 			if (check[0] != '\0')
150 			{
151 				fatal("do_uid: bad uid/login '%s' at %s:%d",
152 					cpe->word, cpe->file, cpe->line);
153 			}
154 		}
155 	}
156 
157 	rs_start->rss_uid= uid;
158 }
159 
160 static void do_sigmgr(config_t *cpe, struct rs_start *rs_start)
161 {
162 	endpoint_t sigmgr_ep;
163 	int r;
164 
165 	/* Process a signal manager value */
166 	if (cpe->next != NULL)
167 	{
168 		fatal("do_sigmgr: just one sigmgr value expected at %s:%d",
169 			cpe->file, cpe->line);
170 	}
171 
172 
173 	if (cpe->flags & CFG_SUBLIST)
174 	{
175 		fatal("do_sigmgr: unexpected sublist at %s:%d",
176 			cpe->file, cpe->line);
177 	}
178 	if (cpe->flags & CFG_STRING)
179 	{
180 		fatal("do_sigmgr: unexpected string at %s:%d",
181 			cpe->file, cpe->line);
182 	}
183 
184 	if(!strcmp(cpe->word, "SELF")) {
185 		sigmgr_ep = SELF;
186 	}
187 	else {
188 		if((r = minix_rs_lookup(cpe->word, &sigmgr_ep))) {
189 			fatal("do_sigmgr: unknown sigmgr %s at %s:%d",
190 			cpe->word, cpe->file, cpe->line);
191 		}
192 	}
193 
194 	rs_start->rss_sigmgr= sigmgr_ep;
195 }
196 
197 static void do_type(config_t *cpe, struct rs_config *rs_config)
198 {
199 	if (cpe->next != NULL)
200 	{
201 		fatal("do_type: just one type value expected at %s:%d",
202 			cpe->file, cpe->line);
203 	}
204 
205 
206 	if (cpe->flags & CFG_SUBLIST)
207 	{
208 		fatal("do_type: unexpected sublist at %s:%d",
209 			cpe->file, cpe->line);
210 	}
211 	if ((cpe->flags & CFG_STRING))
212 	{
213 		fatal("do_type: unexpected string at %s:%d",
214 			cpe->file, cpe->line);
215 	}
216 
217 	if(rs_config->type)
218 		fatal("do_type: another type at %s:%d",
219 			cpe->file, cpe->line);
220 
221 	if(!strcmp(cpe->word, KW_NET))
222 		rs_config->type = KW_NET;
223 	else
224 		fatal("do_type: odd type at %s:%d",
225 			cpe->file, cpe->line);
226 }
227 
228 static void do_descr(config_t *cpe, struct rs_config *rs_config)
229 {
230 	if (cpe->next != NULL)
231 	{
232 		fatal("do_descr: just one description expected at %s:%d",
233 			cpe->file, cpe->line);
234 	}
235 
236 
237 	if (cpe->flags & CFG_SUBLIST)
238 	{
239 		fatal("do_descr: unexpected sublist at %s:%d",
240 			cpe->file, cpe->line);
241 	}
242 	if (!(cpe->flags & CFG_STRING))
243 	{
244 		fatal("do_descr: expected string at %s:%d",
245 			cpe->file, cpe->line);
246 	}
247 
248 	if(rs_config->descr)
249 		fatal("do_descr: another descr at %s:%d",
250 			cpe->file, cpe->line);
251 	rs_config->descr = cpe->word;
252 }
253 
254 static void do_scheduler(config_t *cpe, struct rs_start *rs_start)
255 {
256 	endpoint_t scheduler_ep;
257 	int r;
258 
259 	/* Process a scheduler value */
260 	if (cpe->next != NULL)
261 	{
262 		fatal("do_scheduler: just one scheduler value expected at %s:%d",
263 			cpe->file, cpe->line);
264 	}
265 
266 
267 	if (cpe->flags & CFG_SUBLIST)
268 	{
269 		fatal("do_scheduler: unexpected sublist at %s:%d",
270 			cpe->file, cpe->line);
271 	}
272 	if (cpe->flags & CFG_STRING)
273 	{
274 		fatal("do_scheduler: unexpected string at %s:%d",
275 			cpe->file, cpe->line);
276 	}
277 
278 	if(!strcmp(cpe->word, "KERNEL")) {
279 		scheduler_ep = KERNEL;
280 	}
281 	else {
282 		if((r = minix_rs_lookup(cpe->word, &scheduler_ep))) {
283 			fatal("do_scheduler: unknown scheduler %s at %s:%d",
284 			cpe->word, cpe->file, cpe->line);
285 		}
286 	}
287 
288 	rs_start->rss_scheduler= scheduler_ep;
289 }
290 
291 static void do_priority(config_t *cpe, struct rs_start *rs_start)
292 {
293 	int priority_val;
294 	char *check;
295 
296 	/* Process a priority value */
297 	if (cpe->next != NULL)
298 	{
299 		fatal("do_priority: just one priority value expected at %s:%d",
300 			cpe->file, cpe->line);
301 	}
302 
303 
304 	if (cpe->flags & CFG_SUBLIST)
305 	{
306 		fatal("do_priority: unexpected sublist at %s:%d",
307 			cpe->file, cpe->line);
308 	}
309 	if (cpe->flags & CFG_STRING)
310 	{
311 		fatal("do_priority: unexpected string at %s:%d",
312 			cpe->file, cpe->line);
313 	}
314 	priority_val= strtol(cpe->word, &check, 0);
315 	if (check[0] != '\0')
316 	{
317 		fatal("do_priority: bad priority value '%s' at %s:%d",
318 			cpe->word, cpe->file, cpe->line);
319 	}
320 
321 	if (priority_val < 0 || priority_val >= NR_SCHED_QUEUES)
322 	{
323 		fatal("do_priority: priority %d out of range at %s:%d",
324 			priority_val, cpe->file, cpe->line);
325 	}
326 	rs_start->rss_priority= priority_val;
327 }
328 
329 static void do_quantum(config_t *cpe, struct rs_start *rs_start)
330 {
331 	int quantum_val;
332 	char *check;
333 
334 	/* Process a quantum value */
335 	if (cpe->next != NULL)
336 	{
337 		fatal("do_quantum: just one quantum value expected at %s:%d",
338 			cpe->file, cpe->line);
339 	}
340 
341 
342 	if (cpe->flags & CFG_SUBLIST)
343 	{
344 		fatal("do_quantum: unexpected sublist at %s:%d",
345 			cpe->file, cpe->line);
346 	}
347 	if (cpe->flags & CFG_STRING)
348 	{
349 		fatal("do_quantum: unexpected string at %s:%d",
350 			cpe->file, cpe->line);
351 	}
352 	quantum_val= strtol(cpe->word, &check, 0);
353 	if (check[0] != '\0')
354 	{
355 		fatal("do_quantum: bad quantum value '%s' at %s:%d",
356 			cpe->word, cpe->file, cpe->line);
357 	}
358 
359 	if (quantum_val <= 0)
360 	{
361 		fatal("do_quantum: quantum %d out of range at %s:%d",
362 			quantum_val, cpe->file, cpe->line);
363 	}
364 	rs_start->rss_quantum= quantum_val;
365 }
366 
367 static void do_cpu(config_t *cpe, struct rs_start *rs_start)
368 {
369 	int cpu;
370 	char *check;
371 
372 	/* Process a quantum value */
373 	if (cpe->next != NULL)
374 	{
375 		fatal("do_cpu: just one value expected at %s:%d",
376 			cpe->file, cpe->line);
377 	}
378 
379 
380 	if (cpe->flags & CFG_SUBLIST)
381 	{
382 		fatal("do_cpu: unexpected sublist at %s:%d",
383 			cpe->file, cpe->line);
384 	}
385 	if (cpe->flags & CFG_STRING)
386 	{
387 		fatal("do_cpu: unexpected string at %s:%d",
388 			cpe->file, cpe->line);
389 	}
390 	cpu= strtol(cpe->word, &check, 0);
391 	if (check[0] != '\0')
392 	{
393 		fatal("do_cpu: bad value '%s' at %s:%d",
394 			cpe->word, cpe->file, cpe->line);
395 	}
396 
397 	if (cpu < 0)
398 	{
399 		fatal("do_cpu: %d out of range at %s:%d",
400 			cpu, cpe->file, cpe->line);
401 	}
402 	rs_start->rss_cpu= cpu;
403 }
404 
405 static void do_irq(config_t *cpe, struct rs_start *rs_start)
406 {
407 	int irq;
408 	int first;
409 	char *check;
410 
411 	/* Process a list of IRQs */
412 	first = TRUE;
413 	for (; cpe; cpe= cpe->next)
414 	{
415 		if (cpe->flags & CFG_SUBLIST)
416 		{
417 			fatal("do_irq: unexpected sublist at %s:%d",
418 				cpe->file, cpe->line);
419 		}
420 		if (cpe->flags & CFG_STRING)
421 		{
422 			fatal("do_irq: unexpected string at %s:%d",
423 				cpe->file, cpe->line);
424 		}
425 
426 		/* No IRQ allowed? (default) */
427 		if(!strcmp(cpe->word, KW_NONE)) {
428 			if(!first || cpe->next) {
429 				fatal("do_irq: %s keyword not allowed in list",
430 				KW_NONE);
431 			}
432 			break;
433 		}
434 
435 		/* All IRQs are allowed? */
436 		if(!strcmp(cpe->word, KW_ALL)) {
437 			if(!first || cpe->next) {
438 				fatal("do_irq: %s keyword not allowed in list",
439 				KW_ALL);
440 			}
441 			rs_start->rss_nr_irq = RSS_IO_ALL;
442 			break;
443 		}
444 
445 		/* Set single IRQs as specified in the configuration. */
446 		irq= strtoul(cpe->word, &check, 0);
447 		if (check[0] != '\0')
448 		{
449 			fatal("do_irq: bad irq '%s' at %s:%d",
450 				cpe->word, cpe->file, cpe->line);
451 		}
452 		if (rs_start->rss_nr_irq >= RSS_NR_IRQ)
453 			fatal("do_irq: too many IRQs (max %d)", RSS_NR_IRQ);
454 		rs_start->rss_irq[rs_start->rss_nr_irq]= irq;
455 		rs_start->rss_nr_irq++;
456 		first = FALSE;
457 	}
458 }
459 
460 static void do_io(config_t *cpe, struct rs_start *rs_start)
461 {
462 	unsigned base, len;
463 	int first;
464 	char *check;
465 
466 	/* Process a list of I/O ranges */
467 	first = TRUE;
468 	for (; cpe; cpe= cpe->next)
469 	{
470 		if (cpe->flags & CFG_SUBLIST)
471 		{
472 			fatal("do_io: unexpected sublist at %s:%d",
473 				cpe->file, cpe->line);
474 		}
475 		if (cpe->flags & CFG_STRING)
476 		{
477 			fatal("do_io: unexpected string at %s:%d",
478 				cpe->file, cpe->line);
479 		}
480 
481 		/* No range allowed? (default) */
482 		if(!strcmp(cpe->word, KW_NONE)) {
483 			if(!first || cpe->next) {
484 				fatal("do_io: %s keyword not allowed in list",
485 				KW_NONE);
486 			}
487 			break;
488 		}
489 
490 		/* All ranges are allowed? */
491 		if(!strcmp(cpe->word, KW_ALL)) {
492 			if(!first || cpe->next) {
493 				fatal("do_io: %s keyword not allowed in list",
494 				KW_ALL);
495 			}
496 			rs_start->rss_nr_io = RSS_IO_ALL;
497 			break;
498 		}
499 
500 		/* Set single ranges as specified in the configuration. */
501 		base= strtoul(cpe->word, &check, 0x10);
502 		len= 1;
503 		if (check[0] == ':')
504 		{
505 			len= strtoul(check+1, &check, 0x10);
506 		}
507 		if (check[0] != '\0')
508 		{
509 			fatal("do_io: bad I/O range '%s' at %s:%d",
510 				cpe->word, cpe->file, cpe->line);
511 		}
512 
513 		if (rs_start->rss_nr_io >= RSS_NR_IO)
514 			fatal("do_io: too many I/O ranges (max %d)", RSS_NR_IO);
515 		rs_start->rss_io[rs_start->rss_nr_io].base= base;
516 		rs_start->rss_io[rs_start->rss_nr_io].len= len;
517 		rs_start->rss_nr_io++;
518 		first = FALSE;
519 	}
520 }
521 
522 static void do_pci_device(config_t *cpe, struct rs_start *rs_start)
523 {
524 	u16_t vid, did, sub_vid, sub_did;
525 	char *check, *check2;
526 
527 	/* Process a list of PCI device IDs */
528 	for (; cpe; cpe= cpe->next)
529 	{
530 		if (cpe->flags & CFG_SUBLIST)
531 		{
532 			fatal("do_pci_device: unexpected sublist at %s:%d",
533 				cpe->file, cpe->line);
534 		}
535 		if (cpe->flags & CFG_STRING)
536 		{
537 			fatal("do_pci_device: unexpected string at %s:%d",
538 				cpe->file, cpe->line);
539 		}
540 		vid= strtoul(cpe->word, &check, 0x10);
541 		if (check[0] != ':' && /* LEGACY: */ check[0] != '/') {
542 			fatal("do_pci_device: bad ID '%s' at %s:%d",
543 				cpe->word, cpe->file, cpe->line);
544 		}
545 		did= strtoul(check+1, &check, 0x10);
546 		if (check[0] == '/') {
547 			sub_vid= strtoul(check+1, &check, 0x10);
548 			if (check[0] == ':')
549 				sub_did= strtoul(check+1, &check2, 0x10);
550 			if (check[0] != ':' || check2[0] != '\0') {
551 				fatal("do_pci_device: bad ID '%s' at %s:%d",
552 					cpe->word, cpe->file, cpe->line);
553 			}
554 		} else if (check[0] != '\0') {
555 			fatal("do_pci_device: bad ID '%s' at %s:%d",
556 				cpe->word, cpe->file, cpe->line);
557 		} else {
558 			sub_vid = NO_SUB_VID;
559 			sub_did = NO_SUB_DID;
560 		}
561 		if (rs_start->rss_nr_pci_id >= RS_NR_PCI_DEVICE)
562 		{
563 			fatal("do_pci_device: too many device IDs (max %d)",
564 				RS_NR_PCI_DEVICE);
565 		}
566 		rs_start->rss_pci_id[rs_start->rss_nr_pci_id].vid= vid;
567 		rs_start->rss_pci_id[rs_start->rss_nr_pci_id].did= did;
568 		rs_start->rss_pci_id[rs_start->rss_nr_pci_id].sub_vid= sub_vid;
569 		rs_start->rss_pci_id[rs_start->rss_nr_pci_id].sub_did= sub_did;
570 		rs_start->rss_nr_pci_id++;
571 	}
572 }
573 
574 static void do_pci_class(config_t *cpe, struct rs_start *rs_start)
575 {
576 	u8_t baseclass, subclass, interface;
577 	u32_t class_id, mask;
578 	char *check;
579 
580 	/* Process a list of PCI device class IDs */
581 	for (; cpe; cpe= cpe->next)
582 	{
583 		if (cpe->flags & CFG_SUBLIST)
584 		{
585 			fatal("do_pci_device: unexpected sublist at %s:%d",
586 				cpe->file, cpe->line);
587 		}
588 		if (cpe->flags & CFG_STRING)
589 		{
590 			fatal("do_pci_device: unexpected string at %s:%d",
591 				cpe->file, cpe->line);
592 		}
593 
594 		baseclass= strtoul(cpe->word, &check, 0x10);
595 		subclass= 0;
596 		interface= 0;
597 		mask= 0xff0000;
598 		if (check[0] == '/')
599 		{
600 			subclass= strtoul(check+1, &check, 0x10);
601 			mask= 0xffff00;
602 			if (check[0] == '/')
603 			{
604 				interface= strtoul(check+1, &check, 0x10);
605 				mask= 0xffffff;
606 			}
607 		}
608 
609 		if (check[0] != '\0')
610 		{
611 			fatal("do_pci_class: bad class ID '%s' at %s:%d",
612 				cpe->word, cpe->file, cpe->line);
613 		}
614 		class_id= (baseclass << 16) | (subclass << 8) | interface;
615 		if (rs_start->rss_nr_pci_class >= RS_NR_PCI_CLASS)
616 		{
617 			fatal("do_pci_class: too many class IDs (max %d)",
618 				RS_NR_PCI_CLASS);
619 		}
620 		rs_start->rss_pci_class[rs_start->rss_nr_pci_class].pciclass=
621 			class_id;
622 		rs_start->rss_pci_class[rs_start->rss_nr_pci_class].mask= mask;
623 		rs_start->rss_nr_pci_class++;
624 	}
625 }
626 
627 static void do_pci(config_t *cpe, struct rs_start *rs_start)
628 {
629 	if (cpe == NULL)
630 		return;	/* Empty PCI statement */
631 
632 	if (cpe->flags & CFG_SUBLIST)
633 	{
634 		fatal("do_pci: unexpected sublist at %s:%d",
635 			cpe->file, cpe->line);
636 	}
637 	if (cpe->flags & CFG_STRING)
638 	{
639 		fatal("do_pci: unexpected string at %s:%d",
640 			cpe->file, cpe->line);
641 	}
642 
643 	if (strcmp(cpe->word, KW_DEVICE) == 0)
644 	{
645 		do_pci_device(cpe->next, rs_start);
646 		return;
647 	}
648 	if (strcmp(cpe->word, KW_CLASS) == 0)
649 	{
650 		do_pci_class(cpe->next, rs_start);
651 		return;
652 	}
653 	fatal("do_pci: unexpected word '%s' at %s:%d",
654 		cpe->word, cpe->file, cpe->line);
655 }
656 
657 static void do_ipc(config_t *cpe, struct rs_start *rs_start)
658 {
659 	char *list;
660 	const char *word;
661 	char *word_all = RSS_IPC_ALL;
662 	char *word_all_sys = RSS_IPC_ALL_SYS;
663 	size_t listsize, wordlen;
664 	int first;
665 
666 	list= NULL;
667 	listsize= 1;
668 	list= malloc(listsize);
669 	if (list == NULL)
670 		fatal("do_ipc: unable to malloc %d bytes", listsize);
671 	list[0]= '\0';
672 
673 	/* Process a list of process names that are allowed to be
674 	 * contacted
675 	 */
676 	first = TRUE;
677 	for (; cpe; cpe= cpe->next)
678 	{
679 		if (cpe->flags & CFG_SUBLIST)
680 		{
681 			fatal("do_ipc: unexpected sublist at %s:%d",
682 				cpe->file, cpe->line);
683 		}
684 		if (cpe->flags & CFG_STRING)
685 		{
686 			fatal("do_ipc: unexpected string at %s:%d",
687 				cpe->file, cpe->line);
688 		}
689 		word = cpe->word;
690 
691 		/* All (system) ipc targets are allowed? */
692 		if(!strcmp(word, KW_ALL) || !strcmp(word, KW_ALL_SYS)) {
693 			if(!first || cpe->next) {
694 				fatal("do_ipc: %s keyword not allowed in list",
695 				word);
696 			}
697 			word = !strcmp(word, KW_ALL) ? word_all : word_all_sys;
698 		}
699 
700 		wordlen= strlen(word);
701 
702 		listsize += 1 + wordlen;
703 		list= realloc(list, listsize);
704 		if (list == NULL)
705 		{
706 			fatal("do_ipc: unable to realloc %d bytes",
707 				listsize);
708 		}
709 		strcat(list, " ");
710 		strcat(list, word);
711 		first = FALSE;
712 	}
713 #if 0
714 	printf("do_ipc: got list '%s'\n", list);
715 #endif
716 
717 	if (rs_start->rss_ipc)
718 		fatal("do_ipc: req_ipc is set");
719         rs_start->rss_ipc = list+1;
720 	rs_start->rss_ipclen= strlen(rs_start->rss_ipc);
721 }
722 
723 
724 struct
725 {
726 	char *label;
727 	int call_nr;
728 } vm_table[] =
729 {
730 	{ "EXIT",		VM_EXIT },
731 	{ "FORK",		VM_FORK },
732 	{ "EXEC_NEWMEM",	VM_EXEC_NEWMEM },
733 	{ "PUSH_SIG",		0 },
734 	{ "WILLEXIT",		VM_WILLEXIT },
735 	{ "ADDDMA",		VM_ADDDMA },
736 	{ "DELDMA",		VM_DELDMA },
737 	{ "GETDMA",		VM_GETDMA },
738 	{ "REMAP",		VM_REMAP },
739 	{ "REMAP_RO",		VM_REMAP_RO },
740 	{ "SHM_UNMAP",		VM_SHM_UNMAP },
741 	{ "GETPHYS",		VM_GETPHYS },
742 	{ "GETREF",		VM_GETREF },
743 	{ "RS_SET_PRIV",	VM_RS_SET_PRIV },
744 	{ "INFO",		VM_INFO },
745 	{ "RS_UPDATE",		VM_RS_UPDATE },
746 	{ "RS_MEMCTL",		VM_RS_MEMCTL },
747 	{ "PROCCTL",		VM_PROCCTL },
748 	{ "MAPCACHEPAGE",	VM_MAPCACHEPAGE },
749 	{ "SETCACHEPAGE",	VM_SETCACHEPAGE },
750 	{ "FORGETCACHEPAGE",	VM_FORGETCACHEPAGE },
751 	{ "CLEARCACHE",		VM_CLEARCACHE },
752 	{ "VFS_MMAP",		VM_VFS_MMAP },
753 	{ "VFS_REPLY",		VM_VFS_REPLY },
754 	{ "GETRUSAGE",		VM_GETRUSAGE },
755 	{ "RS_PREPARE",		VM_RS_PREPARE },
756 	{ NULL,			0 },
757 };
758 
759 static void do_vm(config_t *cpe, struct rs_start *rs_start)
760 {
761 	int i, first;
762 
763 	first = TRUE;
764 	for (; cpe; cpe = cpe->next)
765 	{
766 		if (cpe->flags & CFG_SUBLIST)
767 		{
768 			fatal("do_vm: unexpected sublist at %s:%d",
769 			      cpe->file, cpe->line);
770 		}
771 		if (cpe->flags & CFG_STRING)
772 		{
773 			fatal("do_vm: unexpected string at %s:%d",
774 			      cpe->file, cpe->line);
775 		}
776 
777 		/* Only basic calls allowed? (default). */
778 		if(!strcmp(cpe->word, KW_BASIC)) {
779 			if(!first || cpe->next) {
780 				fatal("do_vm: %s keyword not allowed in list",
781 				KW_NONE);
782 			}
783 			break;
784 		}
785 
786 		/* No calls allowed? */
787 		if(!strcmp(cpe->word, KW_NONE)) {
788 			if(!first || cpe->next) {
789 				fatal("do_vm: %s keyword not allowed in list",
790 				KW_NONE);
791 			}
792 			rs_start->rss_flags &= ~RSS_VM_BASIC_CALLS;
793 			break;
794 		}
795 
796 		/* All calls are allowed? */
797 		if(!strcmp(cpe->word, KW_ALL)) {
798 			if(!first || cpe->next) {
799 				fatal("do_vm: %s keyword not allowed in list",
800 				KW_ALL);
801 			}
802 			for (i = 0; i < NR_VM_CALLS; i++)
803 				SET_BIT(rs_start->rss_vm, i);
804 			break;
805 		}
806 
807 		/* Set single calls as specified in the configuration. */
808 		for (i = 0; vm_table[i].label != NULL; i++)
809 			if (!strcmp(cpe->word, vm_table[i].label))
810 				break;
811 		if (vm_table[i].label == NULL) {
812 			warning("do_vm: ignoring unknown call '%s' at %s:%d",
813 				cpe->word, cpe->file, cpe->line);
814 		} else if(vm_table[i].call_nr) {
815 			SET_BIT(rs_start->rss_vm,
816 				vm_table[i].call_nr - VM_RQ_BASE);
817 		}
818 
819 		first = FALSE;
820 	}
821 }
822 
823 struct
824 {
825 	char *label;
826 	int call_nr;
827 } system_tab[]=
828 {
829 	{ "PRIVCTL",		SYS_PRIVCTL },
830 	{ "TRACE",		SYS_TRACE },
831 	{ "KILL",		SYS_KILL },
832 	{ "UMAP",		SYS_UMAP },
833 	{ "VIRCOPY",		SYS_VIRCOPY },
834 	{ "PHYSCOPY",		SYS_PHYSCOPY },
835 	{ "UMAP_REMOTE",	SYS_UMAP_REMOTE },
836 	{ "VUMAP",		SYS_VUMAP },
837 	{ "IRQCTL",		SYS_IRQCTL },
838 	{ "DEVIO",		SYS_DEVIO },
839 	{ "SDEVIO",		SYS_SDEVIO },
840 	{ "VDEVIO",		SYS_VDEVIO },
841 	{ "ABORT",		SYS_ABORT },
842 	{ "IOPENABLE",		SYS_IOPENABLE },
843 	{ "READBIOS",		SYS_READBIOS },
844 	{ "STIME",		SYS_STIME },
845 	{ "VMCTL",		SYS_VMCTL },
846 	{ "MEMSET",		SYS_MEMSET },
847 	{ "PADCONF",		SYS_PADCONF },
848 	{ NULL,		0 }
849 };
850 
851 static void do_system(config_t *cpe, struct rs_start *rs_start)
852 {
853 	int i, first;
854 
855 	/* Process a list of 'system' calls that are allowed */
856 	first = TRUE;
857 	for (; cpe; cpe= cpe->next)
858 	{
859 		if (cpe->flags & CFG_SUBLIST)
860 		{
861 			fatal("do_system: unexpected sublist at %s:%d",
862 				cpe->file, cpe->line);
863 		}
864 		if (cpe->flags & CFG_STRING)
865 		{
866 			fatal("do_system: unexpected string at %s:%d",
867 				cpe->file, cpe->line);
868 		}
869 
870 		/* Only basic calls allowed? (default). */
871 		if(!strcmp(cpe->word, KW_BASIC)) {
872 			if(!first || cpe->next) {
873 				fatal("do_system: %s keyword not allowed in list",
874 				KW_NONE);
875 			}
876 			break;
877 		}
878 
879 		/* No calls allowed? */
880 		if(!strcmp(cpe->word, KW_NONE)) {
881 			if(!first || cpe->next) {
882 				fatal("do_system: %s keyword not allowed in list",
883 				KW_NONE);
884 			}
885 			rs_start->rss_flags &= ~RSS_SYS_BASIC_CALLS;
886 			break;
887 		}
888 
889 		/* All calls are allowed? */
890 		if(!strcmp(cpe->word, KW_ALL)) {
891 			if(!first || cpe->next) {
892 				fatal("do_system: %s keyword not allowed in list",
893 				KW_ALL);
894 			}
895 			for (i = 0; i < NR_SYS_CALLS; i++)
896 				SET_BIT(rs_start->rss_system, i);
897 			break;
898 		}
899 
900 		/* Set single calls as specified in the configuration. */
901 		for (i = 0; system_tab[i].label != NULL; i++)
902 			if (!strcmp(cpe->word, system_tab[i].label))
903 				break;
904 		if (system_tab[i].label == NULL) {
905 		   warning("do_system: ignoring unknown call '%s' at %s:%d",
906 				cpe->word, cpe->file, cpe->line);
907 		} else {
908 			SET_BIT(rs_start->rss_system,
909 				system_tab[i].call_nr - KERNEL_CALL);
910 		}
911 		first = FALSE;
912 	}
913 }
914 
915 static void do_control(config_t *cpe, struct rs_start *rs_start)
916 {
917 	int nr_control = 0;
918 
919 	/* Process a list of 'control' labels. */
920 	for (; cpe; cpe= cpe->next)
921 	{
922 		if (cpe->flags & CFG_SUBLIST)
923 		{
924 			fatal("do_control: unexpected sublist at %s:%d",
925 				cpe->file, cpe->line);
926 		}
927 		if (cpe->flags & CFG_STRING)
928 		{
929 			fatal("do_control: unexpected string at %s:%d",
930 				cpe->file, cpe->line);
931 		}
932 		if (nr_control >= RS_NR_CONTROL)
933 		{
934 			fatal(
935 			"do_control: RS_NR_CONTROL is too small (%d needed)",
936 				nr_control+1);
937 		}
938 
939 		rs_start->rss_control[nr_control].l_addr = (char*) cpe->word;
940 		rs_start->rss_control[nr_control].l_len = strlen(cpe->word);
941 		rs_start->rss_nr_control = ++nr_control;
942 	}
943 }
944 
945 static void do_service(config_t *cpe, config_t *config, struct rs_config *rs_config)
946 {
947 	struct rs_start *rs_start = &rs_config->rs_start;
948 	config_t *cp;
949 
950 	/* At this point we expect one sublist that contains the varios
951 	 * resource allocations
952 	 */
953 	if (!(cpe->flags & CFG_SUBLIST))
954 	{
955 		fatal("do_service: expected list at %s:%d",
956 			cpe->file, cpe->line);
957 	}
958 	if (cpe->next != NULL)
959 	{
960 		cpe= cpe->next;
961 		fatal("do_service: expected end of list at %s:%d",
962 			cpe->file, cpe->line);
963 	}
964 	cpe= cpe->list;
965 
966 	/* Process the list */
967 	for (cp= cpe; cp; cp= cp->next)
968 	{
969 		if (!(cp->flags & CFG_SUBLIST))
970 		{
971 			fatal("do_service: expected list at %s:%d",
972 				cp->file, cp->line);
973 		}
974 		cpe= cp->list;
975 		if ((cpe->flags & CFG_STRING) || (cpe->flags & CFG_SUBLIST))
976 		{
977 			fatal("do_service: expected word at %s:%d",
978 				cpe->file, cpe->line);
979 		}
980 
981 		if (strcmp(cpe->word, KW_CLASS) == 0)
982 		{
983 			do_class(cpe->next, config, rs_config);
984 			continue;
985 		}
986 		if (strcmp(cpe->word, KW_UID) == 0)
987 		{
988 			do_uid(cpe->next, rs_start);
989 			continue;
990 		}
991 		if (strcmp(cpe->word, KW_SIGMGR) == 0)
992 		{
993 			do_sigmgr(cpe->next, rs_start);
994 			continue;
995 		}
996 		if (strcmp(cpe->word, KW_TYPE) == 0)
997 		{
998 			do_type(cpe->next, rs_config);
999 			continue;
1000 		}
1001 		if (strcmp(cpe->word, KW_DESCR) == 0)
1002 		{
1003 			do_descr(cpe->next, rs_config);
1004 			continue;
1005 		}
1006 		if (strcmp(cpe->word, KW_SCHEDULER) == 0)
1007 		{
1008 			do_scheduler(cpe->next, rs_start);
1009 			continue;
1010 		}
1011 		if (strcmp(cpe->word, KW_PRIORITY) == 0)
1012 		{
1013 			do_priority(cpe->next, rs_start);
1014 			continue;
1015 		}
1016 		if (strcmp(cpe->word, KW_QUANTUM) == 0)
1017 		{
1018 			do_quantum(cpe->next, rs_start);
1019 			continue;
1020 		}
1021 		if (strcmp(cpe->word, KW_CPU) == 0)
1022 		{
1023 			do_cpu(cpe->next, rs_start);
1024 			continue;
1025 		}
1026 		if (strcmp(cpe->word, KW_IRQ) == 0)
1027 		{
1028 			do_irq(cpe->next, rs_start);
1029 			continue;
1030 		}
1031 		if (strcmp(cpe->word, KW_IO) == 0)
1032 		{
1033 			do_io(cpe->next, rs_start);
1034 			continue;
1035 		}
1036 		if (strcmp(cpe->word, KW_PCI) == 0)
1037 		{
1038 			do_pci(cpe->next, rs_start);
1039 			continue;
1040 		}
1041 		if (strcmp(cpe->word, KW_SYSTEM) == 0)
1042 		{
1043 			do_system(cpe->next, rs_start);
1044 			continue;
1045 		}
1046 		if (strcmp(cpe->word, KW_IPC) == 0)
1047 		{
1048 			do_ipc(cpe->next, rs_start);
1049 			continue;
1050 		}
1051 		if (strcmp(cpe->word, KW_VM) == 0)
1052 		{
1053 			do_vm(cpe->next, rs_start);
1054 			continue;
1055 		}
1056 		if (strcmp(cpe->word, KW_CONTROL) == 0)
1057 		{
1058 			do_control(cpe->next, rs_start);
1059 			continue;
1060 		}
1061 	}
1062 }
1063 
1064 static const char *do_config(const char *label, char *filename, struct rs_config *rs_config)
1065 {
1066 	config_t *config, *cp, *cpe;
1067 	struct passwd *pw;
1068 	struct rs_start *rs_start = &rs_config->rs_start;
1069 
1070 	if(!(config= config_read(filename, 0, NULL)))
1071 		return NULL; /* config file read failed. */
1072 
1073 	/* Set clean rs_start defaults. */
1074 	memset(rs_config, 0, sizeof(*rs_config));
1075 	if(!(pw= getpwnam(SERVICE_LOGIN)))
1076 		fatal("no passwd file entry for '%s'", SERVICE_LOGIN);
1077 	rs_start->rss_uid= pw->pw_uid;
1078 	rs_start->rss_sigmgr= DSRV_SM;
1079 	rs_start->rss_scheduler= DSRV_SCH;
1080 	rs_start->rss_priority= DSRV_Q;
1081 	rs_start->rss_quantum= DSRV_QT;
1082 	rs_start->rss_cpu = DSRV_CPU;
1083 	rs_start->rss_flags = RSS_VM_BASIC_CALLS | RSS_SYS_BASIC_CALLS;
1084 
1085 	/* Find an entry for our service */
1086 	for (cp= config; cp; cp= cp->next)
1087 	{
1088 		if (!(cp->flags & CFG_SUBLIST))
1089 		{
1090 			fatal("do_config: expected list at %s:%d",
1091 				cp->file, cp->line);
1092 		}
1093 		cpe= cp->list;
1094 		if ((cpe->flags & CFG_STRING) || (cpe->flags & CFG_SUBLIST))
1095 		{
1096 			fatal("do_config: expected word at %s:%d",
1097 				cpe->file, cpe->line);
1098 		}
1099 
1100 		/* At this place we expect the word KW_SERVICE */
1101 		if (strcmp(cpe->word, KW_SERVICE) != 0)
1102 			fatal("do_config: exected word '%S' at %s:%d",
1103 				KW_SERVICE, cpe->file, cpe->line);
1104 
1105 		cpe= cpe->next;
1106 		if ((cpe->flags & CFG_STRING) || (cpe->flags & CFG_SUBLIST))
1107 		{
1108 			fatal("do_config: expected word at %s:%d",
1109 				cpe->file, cpe->line);
1110 		}
1111 
1112 		/* At this place we expect the name of the service. */
1113 		if (!label || strcmp(cpe->word, label) == 0) {
1114 			label = cpe->word;
1115 			break;
1116 		}
1117 	}
1118 	if (cp == NULL)
1119 	{
1120 		fprintf(stderr, "minix-service: service '%s' not found in "
1121 		    "'%s'\n", label, filename);
1122 		exit(1);
1123 	}
1124 
1125 	cpe= cpe->next;
1126 
1127 	do_service(cpe, config, rs_config);
1128 
1129 	{
1130 		char *default_ipc = RSS_IPC_ALL_SYS;
1131 		if(!rs_start->rss_ipc) {
1132 		      rs_start->rss_ipc= default_ipc;
1133 		      rs_start->rss_ipclen= strlen(default_ipc);
1134 		}
1135 	}
1136 
1137 	/* config file read ok. */
1138 	return label;
1139 }
1140 
1141 /* returns failure */
1142 const char *parse_config(char *progname, int custom_config, char *req_config,
1143 	struct rs_config *rs_config)
1144 {
1145         char *specificconfig, *specific_pkg_config;
1146 	const char *l;
1147 
1148 	/* Config file specified? */
1149         if(custom_config)
1150           return do_config(progname, req_config, rs_config);
1151 
1152 	/* No specific config file. */
1153         if(asprintf(&specificconfig, "%s/%s", _PATH_SYSTEM_CONF_DIR,
1154               progname) < 0) {
1155               errx(1, "no memory");
1156         }
1157 
1158         if(asprintf(&specific_pkg_config, "%s/%s", _PATH_SYSTEM_CONF_PKG_DIR,
1159               progname) < 0) {
1160               errx(1, "no memory");
1161         }
1162 
1163         /* Try specific config filename first, in base system
1164 	 * and package locations, * and only if it fails, the global
1165 	 * system one.
1166          */
1167 	if((l=do_config(progname, specific_pkg_config, rs_config))) return l;
1168 	if((l=do_config(progname, specificconfig, rs_config))) return l;
1169 	if((l=do_config(progname, req_config, rs_config))) return l;
1170 
1171 	return NULL;
1172 }
1173 
1174