minix/commands/service/parse.c
Ben Gras 49eb1f4806 vm: new secondary cache code
Primary purpose of change: to support the mmap implementation, VM must
know both (a) about some block metadata for FS cache blocks, i.e.
inode numbers and inode offsets where applicable; and (b) know about
*all* cache blocks, i.e.  also of the FS primary caches and not just
the blocks that spill into the secondary one. This changes the
interface and VM data structures.

This change is only for the interface (libminixfs) and VM data
structures; the filesystem code is unmodified, so although the
secondary cache will be used as normal, blocks will not be annotated
with inode information until the FS is modified to provide this
information. Until it is modified, mmap of files will fail gracefully
on such filesystems.

This is indicated to VFS/VM by returning ENOSYS for REQ_PEEK.

Change-Id: I1d2df6c485e6c5e89eb28d9055076cc02629594e
2013-04-24 10:18:16 +00:00

1154 lines
25 KiB
C

#include <stdarg.h>
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <pwd.h>
#include <err.h>
#include <unistd.h>
#include <limits.h>
#include <lib.h>
#include <minix/config.h>
#include <minix/com.h>
#include <minix/const.h>
#include <minix/type.h>
#include <minix/ipc.h>
#include <minix/rs.h>
#include <minix/syslib.h>
#include <minix/bitmap.h>
#include <paths.h>
#include <minix/sef.h>
#include <minix/dmap.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <configfile.h>
#include <machine/archtypes.h>
#include <timers.h>
#include "kernel/proc.h"
#include "config.h"
#include "proto.h"
static int class_recurs; /* Nesting level of class statements */
#define MAX_CLASS_RECURS 100 /* Max nesting level for classes */
#include "parse.h"
static void do_service(config_t *cpe, config_t *config, struct rs_config *);
static void do_class(config_t *cpe, config_t *config, struct rs_config *rs_config)
{
config_t *cp, *cp1;
if (class_recurs > MAX_CLASS_RECURS)
{
fatal(
"do_class: nesting level too high for class '%s' at %s:%d",
cpe->word, cpe->file, cpe->line);
}
class_recurs++;
/* Process classes */
for (; cpe; cpe= cpe->next)
{
if (cpe->flags & CFG_SUBLIST)
{
fatal("do_class: unexpected sublist at %s:%d",
cpe->file, cpe->line);
}
if (cpe->flags & CFG_STRING)
{
fatal("do_uid: unexpected string at %s:%d",
cpe->file, cpe->line);
}
/* Find entry for the class */
for (cp= config; cp; cp= cp->next)
{
if (!(cp->flags & CFG_SUBLIST))
{
fatal("do_class: expected list at %s:%d",
cp->file, cp->line);
}
cp1= cp->list;
if ((cp1->flags & CFG_STRING) ||
(cp1->flags & CFG_SUBLIST))
{
fatal("do_class: expected word at %s:%d",
cp1->file, cp1->line);
}
/* At this place we expect the word KW_SERVICE */
if (strcmp(cp1->word, KW_SERVICE) != 0)
fatal("do_class: exected word '%S' at %s:%d",
KW_SERVICE, cp1->file, cp1->line);
cp1= cp1->next;
if ((cp1->flags & CFG_STRING) ||
(cp1->flags & CFG_SUBLIST))
{
fatal("do_class: expected word at %s:%d",
cp1->file, cp1->line);
}
/* At this place we expect the name of the service */
if (strcmp(cp1->word, cpe->word) == 0)
break;
}
if (cp == NULL)
{
fatal(
"do_class: no entry found for class '%s' at %s:%d",
cpe->word, cpe->file, cpe->line);
}
do_service(cp1->next, config, rs_config);
}
class_recurs--;
}
static void do_uid(config_t *cpe, struct rs_start *rs_start)
{
uid_t uid;
struct passwd *pw;
char *check;
/* Process a uid */
if (cpe->next != NULL)
{
fatal("do_uid: just one uid/login expected at %s:%d",
cpe->file, cpe->line);
}
if (cpe->flags & CFG_SUBLIST)
{
fatal("do_uid: unexpected sublist at %s:%d",
cpe->file, cpe->line);
}
if (cpe->flags & CFG_STRING)
{
fatal("do_uid: unexpected string at %s:%d",
cpe->file, cpe->line);
}
pw= getpwnam(cpe->word);
if (pw != NULL)
uid= pw->pw_uid;
else
{
if (!strncmp(cpe->word, KW_SELF, strlen(KW_SELF)+1))
{
uid= getuid(); /* Real uid */
}
else {
uid= strtol(cpe->word, &check, 0);
if (check[0] != '\0')
{
fatal("do_uid: bad uid/login '%s' at %s:%d",
cpe->word, cpe->file, cpe->line);
}
}
}
rs_start->rss_uid= uid;
}
static void do_sigmgr(config_t *cpe, struct rs_start *rs_start)
{
endpoint_t sigmgr_ep;
int r;
/* Process a signal manager value */
if (cpe->next != NULL)
{
fatal("do_sigmgr: just one sigmgr value expected at %s:%d",
cpe->file, cpe->line);
}
if (cpe->flags & CFG_SUBLIST)
{
fatal("do_sigmgr: unexpected sublist at %s:%d",
cpe->file, cpe->line);
}
if (cpe->flags & CFG_STRING)
{
fatal("do_sigmgr: unexpected string at %s:%d",
cpe->file, cpe->line);
}
if(!strcmp(cpe->word, "SELF")) {
sigmgr_ep = SELF;
}
else {
if((r = minix_rs_lookup(cpe->word, &sigmgr_ep))) {
fatal("do_sigmgr: unknown sigmgr %s at %s:%d",
cpe->word, cpe->file, cpe->line);
}
}
rs_start->rss_sigmgr= sigmgr_ep;
}
static void do_type(config_t *cpe, struct rs_config *rs_config)
{
if (cpe->next != NULL)
{
fatal("do_type: just one type value expected at %s:%d",
cpe->file, cpe->line);
}
if (cpe->flags & CFG_SUBLIST)
{
fatal("do_type: unexpected sublist at %s:%d",
cpe->file, cpe->line);
}
if ((cpe->flags & CFG_STRING))
{
fatal("do_type: unexpected string at %s:%d",
cpe->file, cpe->line);
}
if(rs_config->type)
fatal("do_type: another type at %s:%d",
cpe->file, cpe->line);
if(!strcmp(cpe->word, KW_NET))
rs_config->type = KW_NET;
else
fatal("do_type: odd type at %s:%d",
cpe->file, cpe->line);
}
static void do_descr(config_t *cpe, struct rs_config *rs_config)
{
if (cpe->next != NULL)
{
fatal("do_descr: just one description expected at %s:%d",
cpe->file, cpe->line);
}
if (cpe->flags & CFG_SUBLIST)
{
fatal("do_descr: unexpected sublist at %s:%d",
cpe->file, cpe->line);
}
if (!(cpe->flags & CFG_STRING))
{
fatal("do_descr: expected string at %s:%d",
cpe->file, cpe->line);
}
if(rs_config->descr)
fatal("do_descr: another descr at %s:%d",
cpe->file, cpe->line);
rs_config->descr = cpe->word;
}
static void do_scheduler(config_t *cpe, struct rs_start *rs_start)
{
endpoint_t scheduler_ep;
int r;
/* Process a scheduler value */
if (cpe->next != NULL)
{
fatal("do_scheduler: just one scheduler value expected at %s:%d",
cpe->file, cpe->line);
}
if (cpe->flags & CFG_SUBLIST)
{
fatal("do_scheduler: unexpected sublist at %s:%d",
cpe->file, cpe->line);
}
if (cpe->flags & CFG_STRING)
{
fatal("do_scheduler: unexpected string at %s:%d",
cpe->file, cpe->line);
}
if(!strcmp(cpe->word, "KERNEL")) {
scheduler_ep = KERNEL;
}
else {
if((r = minix_rs_lookup(cpe->word, &scheduler_ep))) {
fatal("do_scheduler: unknown scheduler %s at %s:%d",
cpe->word, cpe->file, cpe->line);
}
}
rs_start->rss_scheduler= scheduler_ep;
}
static void do_priority(config_t *cpe, struct rs_start *rs_start)
{
int priority_val;
char *check;
/* Process a priority value */
if (cpe->next != NULL)
{
fatal("do_priority: just one priority value expected at %s:%d",
cpe->file, cpe->line);
}
if (cpe->flags & CFG_SUBLIST)
{
fatal("do_priority: unexpected sublist at %s:%d",
cpe->file, cpe->line);
}
if (cpe->flags & CFG_STRING)
{
fatal("do_priority: unexpected string at %s:%d",
cpe->file, cpe->line);
}
priority_val= strtol(cpe->word, &check, 0);
if (check[0] != '\0')
{
fatal("do_priority: bad priority value '%s' at %s:%d",
cpe->word, cpe->file, cpe->line);
}
if (priority_val < 0 || priority_val >= NR_SCHED_QUEUES)
{
fatal("do_priority: priority %d out of range at %s:%d",
priority_val, cpe->file, cpe->line);
}
rs_start->rss_priority= priority_val;
}
static void do_quantum(config_t *cpe, struct rs_start *rs_start)
{
int quantum_val;
char *check;
/* Process a quantum value */
if (cpe->next != NULL)
{
fatal("do_quantum: just one quantum value expected at %s:%d",
cpe->file, cpe->line);
}
if (cpe->flags & CFG_SUBLIST)
{
fatal("do_quantum: unexpected sublist at %s:%d",
cpe->file, cpe->line);
}
if (cpe->flags & CFG_STRING)
{
fatal("do_quantum: unexpected string at %s:%d",
cpe->file, cpe->line);
}
quantum_val= strtol(cpe->word, &check, 0);
if (check[0] != '\0')
{
fatal("do_quantum: bad quantum value '%s' at %s:%d",
cpe->word, cpe->file, cpe->line);
}
if (quantum_val <= 0)
{
fatal("do_quantum: quantum %d out of range at %s:%d",
quantum_val, cpe->file, cpe->line);
}
rs_start->rss_quantum= quantum_val;
}
static void do_cpu(config_t *cpe, struct rs_start *rs_start)
{
int cpu;
char *check;
/* Process a quantum value */
if (cpe->next != NULL)
{
fatal("do_cpu: just one value expected at %s:%d",
cpe->file, cpe->line);
}
if (cpe->flags & CFG_SUBLIST)
{
fatal("do_cpu: unexpected sublist at %s:%d",
cpe->file, cpe->line);
}
if (cpe->flags & CFG_STRING)
{
fatal("do_cpu: unexpected string at %s:%d",
cpe->file, cpe->line);
}
cpu= strtol(cpe->word, &check, 0);
if (check[0] != '\0')
{
fatal("do_cpu: bad value '%s' at %s:%d",
cpe->word, cpe->file, cpe->line);
}
if (cpu < 0)
{
fatal("do_cpu: %d out of range at %s:%d",
cpu, cpe->file, cpe->line);
}
rs_start->rss_cpu= cpu;
}
static void do_irq(config_t *cpe, struct rs_start *rs_start)
{
int irq;
int first;
char *check;
/* Process a list of IRQs */
first = TRUE;
for (; cpe; cpe= cpe->next)
{
if (cpe->flags & CFG_SUBLIST)
{
fatal("do_irq: unexpected sublist at %s:%d",
cpe->file, cpe->line);
}
if (cpe->flags & CFG_STRING)
{
fatal("do_irq: unexpected string at %s:%d",
cpe->file, cpe->line);
}
/* No IRQ allowed? (default) */
if(!strcmp(cpe->word, KW_NONE)) {
if(!first || cpe->next) {
fatal("do_irq: %s keyword not allowed in list",
KW_NONE);
}
break;
}
/* All IRQs are allowed? */
if(!strcmp(cpe->word, KW_ALL)) {
if(!first || cpe->next) {
fatal("do_irq: %s keyword not allowed in list",
KW_ALL);
}
rs_start->rss_nr_irq = RSS_IO_ALL;
break;
}
/* Set single IRQs as specified in the configuration. */
irq= strtoul(cpe->word, &check, 0);
if (check[0] != '\0')
{
fatal("do_irq: bad irq '%s' at %s:%d",
cpe->word, cpe->file, cpe->line);
}
if (rs_start->rss_nr_irq >= RSS_NR_IRQ)
fatal("do_irq: too many IRQs (max %d)", RSS_NR_IRQ);
rs_start->rss_irq[rs_start->rss_nr_irq]= irq;
rs_start->rss_nr_irq++;
first = FALSE;
}
}
static void do_io(config_t *cpe, struct rs_start *rs_start)
{
unsigned base, len;
int first;
char *check;
/* Process a list of I/O ranges */
first = TRUE;
for (; cpe; cpe= cpe->next)
{
if (cpe->flags & CFG_SUBLIST)
{
fatal("do_io: unexpected sublist at %s:%d",
cpe->file, cpe->line);
}
if (cpe->flags & CFG_STRING)
{
fatal("do_io: unexpected string at %s:%d",
cpe->file, cpe->line);
}
/* No range allowed? (default) */
if(!strcmp(cpe->word, KW_NONE)) {
if(!first || cpe->next) {
fatal("do_io: %s keyword not allowed in list",
KW_NONE);
}
break;
}
/* All ranges are allowed? */
if(!strcmp(cpe->word, KW_ALL)) {
if(!first || cpe->next) {
fatal("do_io: %s keyword not allowed in list",
KW_ALL);
}
rs_start->rss_nr_io = RSS_IO_ALL;
break;
}
/* Set single ranges as specified in the configuration. */
base= strtoul(cpe->word, &check, 0x10);
len= 1;
if (check[0] == ':')
{
len= strtoul(check+1, &check, 0x10);
}
if (check[0] != '\0')
{
fatal("do_io: bad I/O range '%s' at %s:%d",
cpe->word, cpe->file, cpe->line);
}
if (rs_start->rss_nr_io >= RSS_NR_IO)
fatal("do_io: too many I/O ranges (max %d)", RSS_NR_IO);
rs_start->rss_io[rs_start->rss_nr_io].base= base;
rs_start->rss_io[rs_start->rss_nr_io].len= len;
rs_start->rss_nr_io++;
first = FALSE;
}
}
static void do_pci_device(config_t *cpe, struct rs_start *rs_start)
{
u16_t vid, did;
char *check, *check2;
/* Process a list of PCI device IDs */
for (; cpe; cpe= cpe->next)
{
if (cpe->flags & CFG_SUBLIST)
{
fatal("do_pci_device: unexpected sublist at %s:%d",
cpe->file, cpe->line);
}
if (cpe->flags & CFG_STRING)
{
fatal("do_pci_device: unexpected string at %s:%d",
cpe->file, cpe->line);
}
vid= strtoul(cpe->word, &check, 0x10);
if (check[0] == '/')
did= strtoul(check+1, &check2, 0x10);
if (check[0] != '/' || check2[0] != '\0')
{
fatal("do_pci_device: bad ID '%s' at %s:%d",
cpe->word, cpe->file, cpe->line);
}
if (rs_start->rss_nr_pci_id >= RS_NR_PCI_DEVICE)
{
fatal("do_pci_device: too many device IDs (max %d)",
RS_NR_PCI_DEVICE);
}
rs_start->rss_pci_id[rs_start->rss_nr_pci_id].vid= vid;
rs_start->rss_pci_id[rs_start->rss_nr_pci_id].did= did;
rs_start->rss_nr_pci_id++;
}
}
static void do_pci_class(config_t *cpe, struct rs_start *rs_start)
{
u8_t baseclass, subclass, interface;
u32_t class_id, mask;
char *check;
/* Process a list of PCI device class IDs */
for (; cpe; cpe= cpe->next)
{
if (cpe->flags & CFG_SUBLIST)
{
fatal("do_pci_device: unexpected sublist at %s:%d",
cpe->file, cpe->line);
}
if (cpe->flags & CFG_STRING)
{
fatal("do_pci_device: unexpected string at %s:%d",
cpe->file, cpe->line);
}
baseclass= strtoul(cpe->word, &check, 0x10);
subclass= 0;
interface= 0;
mask= 0xff0000;
if (check[0] == '/')
{
subclass= strtoul(check+1, &check, 0x10);
mask= 0xffff00;
if (check[0] == '/')
{
interface= strtoul(check+1, &check, 0x10);
mask= 0xffffff;
}
}
if (check[0] != '\0')
{
fatal("do_pci_class: bad class ID '%s' at %s:%d",
cpe->word, cpe->file, cpe->line);
}
class_id= (baseclass << 16) | (subclass << 8) | interface;
if (rs_start->rss_nr_pci_class >= RS_NR_PCI_CLASS)
{
fatal("do_pci_class: too many class IDs (max %d)",
RS_NR_PCI_CLASS);
}
rs_start->rss_pci_class[rs_start->rss_nr_pci_class].pciclass=
class_id;
rs_start->rss_pci_class[rs_start->rss_nr_pci_class].mask= mask;
rs_start->rss_nr_pci_class++;
}
}
static void do_pci(config_t *cpe, struct rs_start *rs_start)
{
if (cpe == NULL)
return; /* Empty PCI statement */
if (cpe->flags & CFG_SUBLIST)
{
fatal("do_pci: unexpected sublist at %s:%d",
cpe->file, cpe->line);
}
if (cpe->flags & CFG_STRING)
{
fatal("do_pci: unexpected string at %s:%d",
cpe->file, cpe->line);
}
if (strcmp(cpe->word, KW_DEVICE) == 0)
{
do_pci_device(cpe->next, rs_start);
return;
}
if (strcmp(cpe->word, KW_CLASS) == 0)
{
do_pci_class(cpe->next, rs_start);
return;
}
fatal("do_pci: unexpected word '%s' at %s:%d",
cpe->word, cpe->file, cpe->line);
}
static void do_ipc(config_t *cpe, struct rs_start *rs_start)
{
char *list;
const char *word;
char *word_all = RSS_IPC_ALL;
char *word_all_sys = RSS_IPC_ALL_SYS;
size_t listsize, wordlen;
int first;
list= NULL;
listsize= 1;
list= malloc(listsize);
if (list == NULL)
fatal("do_ipc: unable to malloc %d bytes", listsize);
list[0]= '\0';
/* Process a list of process names that are allowed to be
* contacted
*/
first = TRUE;
for (; cpe; cpe= cpe->next)
{
if (cpe->flags & CFG_SUBLIST)
{
fatal("do_ipc: unexpected sublist at %s:%d",
cpe->file, cpe->line);
}
if (cpe->flags & CFG_STRING)
{
fatal("do_ipc: unexpected string at %s:%d",
cpe->file, cpe->line);
}
word = cpe->word;
/* All (system) ipc targets are allowed? */
if(!strcmp(word, KW_ALL) || !strcmp(word, KW_ALL_SYS)) {
if(!first || cpe->next) {
fatal("do_ipc: %s keyword not allowed in list",
word);
}
word = !strcmp(word, KW_ALL) ? word_all : word_all_sys;
}
wordlen= strlen(word);
listsize += 1 + wordlen;
list= realloc(list, listsize);
if (list == NULL)
{
fatal("do_ipc: unable to realloc %d bytes",
listsize);
}
strcat(list, " ");
strcat(list, word);
first = FALSE;
}
#if 0
printf("do_ipc: got list '%s'\n", list);
#endif
if (rs_start->rss_ipc)
fatal("do_ipc: req_ipc is set");
rs_start->rss_ipc = list+1;
rs_start->rss_ipclen= strlen(rs_start->rss_ipc);
}
struct
{
char *label;
int call_nr;
} vm_table[] =
{
{ "EXIT", VM_EXIT },
{ "FORK", VM_FORK },
{ "BRK", VM_BRK },
{ "EXEC_NEWMEM", VM_EXEC_NEWMEM },
{ "PUSH_SIG", 0 },
{ "WILLEXIT", VM_WILLEXIT },
{ "ADDDMA", VM_ADDDMA },
{ "DELDMA", VM_DELDMA },
{ "GETDMA", VM_GETDMA },
{ "REMAP", VM_REMAP },
{ "REMAP_RO", VM_REMAP_RO },
{ "SHM_UNMAP", VM_SHM_UNMAP },
{ "GETPHYS", VM_GETPHYS },
{ "GETREF", VM_GETREF },
{ "RS_SET_PRIV", VM_RS_SET_PRIV },
{ "QUERY_EXIT", VM_QUERY_EXIT },
{ "WATCH_EXIT", VM_WATCH_EXIT },
{ "NOTIFY_SIG", VM_NOTIFY_SIG },
{ "INFO", VM_INFO },
{ "RS_UPDATE", VM_RS_UPDATE },
{ "RS_MEMCTL", VM_RS_MEMCTL },
{ "PROCCTL", VM_PROCCTL },
{ "MAPCACHEPAGE", VM_MAPCACHEPAGE },
{ "SETCACHEPAGE", VM_SETCACHEPAGE },
{ NULL, 0 },
};
static void do_vm(config_t *cpe, struct rs_start *rs_start)
{
int i, first;
first = TRUE;
for (; cpe; cpe = cpe->next)
{
if (cpe->flags & CFG_SUBLIST)
{
fatal("do_vm: unexpected sublist at %s:%d",
cpe->file, cpe->line);
}
if (cpe->flags & CFG_STRING)
{
fatal("do_vm: unexpected string at %s:%d",
cpe->file, cpe->line);
}
/* Only basic calls allowed? (default). */
if(!strcmp(cpe->word, KW_BASIC)) {
if(!first || cpe->next) {
fatal("do_vm: %s keyword not allowed in list",
KW_NONE);
}
break;
}
/* No calls allowed? */
if(!strcmp(cpe->word, KW_NONE)) {
if(!first || cpe->next) {
fatal("do_vm: %s keyword not allowed in list",
KW_NONE);
}
rs_start->rss_flags &= ~RSS_VM_BASIC_CALLS;
break;
}
/* All calls are allowed? */
if(!strcmp(cpe->word, KW_ALL)) {
if(!first || cpe->next) {
fatal("do_vm: %s keyword not allowed in list",
KW_ALL);
}
for (i = 0; i < NR_VM_CALLS; i++)
SET_BIT(rs_start->rss_vm, i);
break;
}
/* Set single calls as specified in the configuration. */
for (i = 0; vm_table[i].label != NULL; i++)
if (!strcmp(cpe->word, vm_table[i].label))
break;
if (vm_table[i].label == NULL) {
warning("do_vm: ignoring unknown call '%s' at %s:%d",
cpe->word, cpe->file, cpe->line);
} else if(vm_table[i].call_nr) {
SET_BIT(rs_start->rss_vm,
vm_table[i].call_nr - VM_RQ_BASE);
}
first = FALSE;
}
}
struct
{
char *label;
int call_nr;
} system_tab[]=
{
{ "PRIVCTL", SYS_PRIVCTL },
{ "TRACE", SYS_TRACE },
{ "KILL", SYS_KILL },
{ "UMAP", SYS_UMAP },
{ "VIRCOPY", SYS_VIRCOPY },
{ "PHYSCOPY", SYS_PHYSCOPY },
{ "UMAP_REMOTE", SYS_UMAP_REMOTE },
{ "VUMAP", SYS_VUMAP },
{ "IRQCTL", SYS_IRQCTL },
{ "INT86", SYS_INT86 },
{ "DEVIO", SYS_DEVIO },
{ "SDEVIO", SYS_SDEVIO },
{ "VDEVIO", SYS_VDEVIO },
{ "ABORT", SYS_ABORT },
{ "IOPENABLE", SYS_IOPENABLE },
{ "READBIOS", SYS_READBIOS },
{ "STIME", SYS_STIME },
{ "VMCTL", SYS_VMCTL },
{ "MEMSET", SYS_MEMSET },
{ NULL, 0 }
};
static void do_system(config_t *cpe, struct rs_start *rs_start)
{
int i, first;
/* Process a list of 'system' calls that are allowed */
first = TRUE;
for (; cpe; cpe= cpe->next)
{
if (cpe->flags & CFG_SUBLIST)
{
fatal("do_system: unexpected sublist at %s:%d",
cpe->file, cpe->line);
}
if (cpe->flags & CFG_STRING)
{
fatal("do_system: unexpected string at %s:%d",
cpe->file, cpe->line);
}
/* Only basic calls allowed? (default). */
if(!strcmp(cpe->word, KW_BASIC)) {
if(!first || cpe->next) {
fatal("do_system: %s keyword not allowed in list",
KW_NONE);
}
break;
}
/* No calls allowed? */
if(!strcmp(cpe->word, KW_NONE)) {
if(!first || cpe->next) {
fatal("do_system: %s keyword not allowed in list",
KW_NONE);
}
rs_start->rss_flags &= ~RSS_SYS_BASIC_CALLS;
break;
}
/* All calls are allowed? */
if(!strcmp(cpe->word, KW_ALL)) {
if(!first || cpe->next) {
fatal("do_system: %s keyword not allowed in list",
KW_ALL);
}
for (i = 0; i < NR_SYS_CALLS; i++)
SET_BIT(rs_start->rss_system, i);
break;
}
/* Set single calls as specified in the configuration. */
for (i = 0; system_tab[i].label != NULL; i++)
if (!strcmp(cpe->word, system_tab[i].label))
break;
if (system_tab[i].label == NULL) {
warning("do_system: ignoring unknown call '%s' at %s:%d",
cpe->word, cpe->file, cpe->line);
} else {
SET_BIT(rs_start->rss_system,
system_tab[i].call_nr - KERNEL_CALL);
}
first = FALSE;
}
}
static void do_control(config_t *cpe, struct rs_start *rs_start)
{
int nr_control = 0;
/* Process a list of 'control' labels. */
for (; cpe; cpe= cpe->next)
{
if (cpe->flags & CFG_SUBLIST)
{
fatal("do_control: unexpected sublist at %s:%d",
cpe->file, cpe->line);
}
if (cpe->flags & CFG_STRING)
{
fatal("do_control: unexpected string at %s:%d",
cpe->file, cpe->line);
}
if (nr_control >= RS_NR_CONTROL)
{
fatal(
"do_control: RS_NR_CONTROL is too small (%d needed)",
nr_control+1);
}
rs_start->rss_control[nr_control].l_addr = (char*) cpe->word;
rs_start->rss_control[nr_control].l_len = strlen(cpe->word);
rs_start->rss_nr_control = ++nr_control;
}
}
static void do_service(config_t *cpe, config_t *config, struct rs_config *rs_config)
{
struct rs_start *rs_start = &rs_config->rs_start;
config_t *cp;
/* At this point we expect one sublist that contains the varios
* resource allocations
*/
if (!(cpe->flags & CFG_SUBLIST))
{
fatal("do_service: expected list at %s:%d",
cpe->file, cpe->line);
}
if (cpe->next != NULL)
{
cpe= cpe->next;
fatal("do_service: expected end of list at %s:%d",
cpe->file, cpe->line);
}
cpe= cpe->list;
/* Process the list */
for (cp= cpe; cp; cp= cp->next)
{
if (!(cp->flags & CFG_SUBLIST))
{
fatal("do_service: expected list at %s:%d",
cp->file, cp->line);
}
cpe= cp->list;
if ((cpe->flags & CFG_STRING) || (cpe->flags & CFG_SUBLIST))
{
fatal("do_service: expected word at %s:%d",
cpe->file, cpe->line);
}
if (strcmp(cpe->word, KW_CLASS) == 0)
{
do_class(cpe->next, config, rs_config);
continue;
}
if (strcmp(cpe->word, KW_UID) == 0)
{
do_uid(cpe->next, rs_start);
continue;
}
if (strcmp(cpe->word, KW_SIGMGR) == 0)
{
do_sigmgr(cpe->next, rs_start);
continue;
}
if (strcmp(cpe->word, KW_TYPE) == 0)
{
do_type(cpe->next, rs_config);
continue;
}
if (strcmp(cpe->word, KW_DESCR) == 0)
{
do_descr(cpe->next, rs_config);
continue;
}
if (strcmp(cpe->word, KW_SCHEDULER) == 0)
{
do_scheduler(cpe->next, rs_start);
continue;
}
if (strcmp(cpe->word, KW_PRIORITY) == 0)
{
do_priority(cpe->next, rs_start);
continue;
}
if (strcmp(cpe->word, KW_QUANTUM) == 0)
{
do_quantum(cpe->next, rs_start);
continue;
}
if (strcmp(cpe->word, KW_CPU) == 0)
{
do_cpu(cpe->next, rs_start);
continue;
}
if (strcmp(cpe->word, KW_IRQ) == 0)
{
do_irq(cpe->next, rs_start);
continue;
}
if (strcmp(cpe->word, KW_IO) == 0)
{
do_io(cpe->next, rs_start);
continue;
}
if (strcmp(cpe->word, KW_PCI) == 0)
{
do_pci(cpe->next, rs_start);
continue;
}
if (strcmp(cpe->word, KW_SYSTEM) == 0)
{
do_system(cpe->next, rs_start);
continue;
}
if (strcmp(cpe->word, KW_IPC) == 0)
{
do_ipc(cpe->next, rs_start);
continue;
}
if (strcmp(cpe->word, KW_VM) == 0)
{
do_vm(cpe->next, rs_start);
continue;
}
if (strcmp(cpe->word, KW_CONTROL) == 0)
{
do_control(cpe->next, rs_start);
continue;
}
}
}
static const char *do_config(const char *label, char *filename, struct rs_config *rs_config)
{
config_t *config, *cp, *cpe;
struct passwd *pw;
struct rs_start *rs_start = &rs_config->rs_start;
if(!(config= config_read(filename, 0, NULL)))
return NULL; /* config file read failed. */
/* Set clean rs_start defaults. */
memset(rs_config, 0, sizeof(*rs_config));
if(!(pw= getpwnam(SERVICE_LOGIN)))
fatal("no passwd file entry for '%s'", SERVICE_LOGIN);
rs_start->rss_uid= pw->pw_uid;
rs_start->rss_sigmgr= DSRV_SM;
rs_start->rss_scheduler= DSRV_SCH;
rs_start->rss_priority= DSRV_Q;
rs_start->rss_quantum= DSRV_QT;
rs_start->rss_cpu = DSRV_CPU;
rs_start->rss_flags = RSS_VM_BASIC_CALLS | RSS_SYS_BASIC_CALLS;
/* Find an entry for our service */
for (cp= config; cp; cp= cp->next)
{
if (!(cp->flags & CFG_SUBLIST))
{
fatal("do_config: expected list at %s:%d",
cp->file, cp->line);
}
cpe= cp->list;
if ((cpe->flags & CFG_STRING) || (cpe->flags & CFG_SUBLIST))
{
fatal("do_config: expected word at %s:%d",
cpe->file, cpe->line);
}
/* At this place we expect the word KW_SERVICE */
if (strcmp(cpe->word, KW_SERVICE) != 0)
fatal("do_config: exected word '%S' at %s:%d",
KW_SERVICE, cpe->file, cpe->line);
cpe= cpe->next;
if ((cpe->flags & CFG_STRING) || (cpe->flags & CFG_SUBLIST))
{
fatal("do_config: expected word at %s:%d",
cpe->file, cpe->line);
}
/* At this place we expect the name of the service. */
if (!label || strcmp(cpe->word, label) == 0) {
label = cpe->word;
break;
}
}
if (cp == NULL)
{
fprintf(stderr, "service: service '%s' not found in '%s'\n",
label, filename);
exit(1);
}
cpe= cpe->next;
do_service(cpe, config, rs_config);
{
char *default_ipc = RSS_IPC_ALL_SYS;
if(!rs_start->rss_ipc) {
rs_start->rss_ipc= default_ipc;
rs_start->rss_ipclen= strlen(default_ipc);
}
}
/* config file read ok. */
return label;
}
/* returns failure */
const char *parse_config(char *progname, int custom_config, char *req_config,
struct rs_config *rs_config)
{
char *specificconfig, *specific_pkg_config;
const char *l;
/* Config file specified? */
if(custom_config)
return do_config(progname, req_config, rs_config);
/* No specific config file. */
if(asprintf(&specificconfig, "%s/%s", _PATH_SYSTEM_CONF_DIR,
progname) < 0) {
errx(1, "no memory");
}
if(asprintf(&specific_pkg_config, "%s/%s", _PATH_SYSTEM_CONF_PKG_DIR,
progname) < 0) {
errx(1, "no memory");
}
/* Try specific config filename first, in base system
* and package locations, * and only if it fails, the global
* system one.
*/
if((l=do_config(progname, specific_pkg_config, rs_config))) return l;
if((l=do_config(progname, specificconfig, rs_config))) return l;
if((l=do_config(progname, req_config, rs_config))) return l;
return NULL;
}