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
do_class(config_t * cpe,config_t * config,struct rs_config * rs_config)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
do_uid(config_t * cpe,struct rs_start * rs_start)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
do_sigmgr(config_t * cpe,struct rs_start * rs_start)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
do_type(config_t * cpe,struct rs_config * rs_config)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
do_descr(config_t * cpe,struct rs_config * rs_config)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
do_scheduler(config_t * cpe,struct rs_start * rs_start)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
do_priority(config_t * cpe,struct rs_start * rs_start)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
do_quantum(config_t * cpe,struct rs_start * rs_start)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
do_cpu(config_t * cpe,struct rs_start * rs_start)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
do_irq(config_t * cpe,struct rs_start * rs_start)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
do_io(config_t * cpe,struct rs_start * rs_start)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
do_pci_device(config_t * cpe,struct rs_start * rs_start)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
do_pci_class(config_t * cpe,struct rs_start * rs_start)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
do_pci(config_t * cpe,struct rs_start * rs_start)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
do_ipc(config_t * cpe,struct rs_start * rs_start)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
do_vm(config_t * cpe,struct rs_start * rs_start)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
do_system(config_t * cpe,struct rs_start * rs_start)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
do_control(config_t * cpe,struct rs_start * rs_start)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
do_domain(config_t * cpe,struct rs_start * rs_start)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
do_service(config_t * cpe,config_t * config,struct rs_config * rs_config)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
do_config(const char * label,char * filename,struct rs_config * rs_config)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 */
parse_config(char * progname,int custom_config,char * req_config,struct rs_config * rs_config)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