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