 4593804bf0
			
		
	
	
		4593804bf0
		
	
	
	
	
		
			
			On the AM335X, writes to the padconf registers must be done in privileged mode. To allow userspace drivers to dynamically change the padconf at runtime, a kernel call has been added. Change-Id: I4b25d2879399b1785a360912faa0e90b5c258533
		
			
				
	
	
		
			1158 lines
		
	
	
		
			25 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1158 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 },
 | |
| 	{ "VFS_MMAP",		VM_VFS_MMAP },
 | |
| 	{ "VFS_REPLY",		VM_VFS_REPLY },
 | |
| 	{ 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 },
 | |
| 	{ "PADCONF",		SYS_PADCONF },
 | |
| 	{ 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;
 | |
| }
 | |
| 
 |