diff usr/src/cmd/bnu/sysfiles.c @ 0:c9caec207d52 b86

Initial porting based on b86
author Koji Uno <koji.uno@sun.com>
date Tue, 02 Jun 2009 18:56:50 +0900
parents
children 1a15d5aaf794
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/bnu/sysfiles.c	Tue Jun 02 18:56:50 2009 +0900
@@ -0,0 +1,779 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 1998 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
+/*	  All Rights Reserved  	*/
+
+
+#pragma ident	"@(#)sysfiles.c	1.12	05/06/08 SMI"
+
+#include "uucp.h"
+
+#include <unistd.h>
+#include "sysfiles.h"
+#include <sys/stropts.h>
+
+/*
+ * manage systems files (Systems, Devices, and Dialcodes families).
+ *
+ * also manage new file Devconfig, allows per-device setup.
+ * present use is to specify what streams modules to push/pop for
+ * AT&T TLI/streams network.
+ *
+ * TODO:
+ *    call bsfix()?
+ *    combine the 3 versions of everything (sys, dev, and dial) into one.
+ *    allow arbitrary classes of service.
+ *    need verifysys() for uucheck.
+ *    nameserver interface?
+ *    pass sysname (or 0) to getsysline().  (might want reg. exp. or NS processing 
+ */
+
+/* private variables */
+static void tokenize(), nameparse(), setfile(), setioctl(),
+	scansys(), scancfg(), setconfig();
+static int namematch(), nextdialers(), nextdevices(), nextsystems(), getline();
+
+/* pointer arrays might be dynamically allocated */
+static char *Systems[64] = {0};	/* list of Systems files */
+static char *Devices[64] = {0};	/* list of Devices files */
+static char *Dialers[64] = {0};	/* list of Dialers files */
+static char *Pops[64] = {0};	/* list of STREAMS modules to be popped */
+static char *Pushes[64] = {0};	/* list of STREAMS modules to be pushed */
+
+static int nsystems;		/* index into list of Systems files */
+static int ndevices;		/* index into list of Devices files */
+static int ndialers;		/* index into list of Dialers files */
+static int npops;		/* index into list of STREAMS modules */
+							/*to be popped */
+static int npushes;		/* index into list of STREAMS modules */
+							/*to be pushed */
+
+GLOBAL unsigned connecttime = CONNECTTIME;
+GLOBAL unsigned expecttime = EXPECTTIME;
+GLOBAL unsigned msgtime = MSGTIME;
+
+static FILE *fsystems;
+static FILE *fdevices;
+static FILE *fdialers;
+
+static char errformat[BUFSIZ];
+
+/* this might be dynamically allocated */
+#define NTOKENS 16
+static char *tokens[NTOKENS], **tokptr;
+
+/* export these */
+EXTERN void sysreset(), devreset(), dialreset(), setdevcfg(), setservice();
+EXTERN char *strsave();
+
+/* import these */
+extern char *strcpy(), *strtok(), *strchr(), *strsave();
+EXTERN int eaccess();
+
+/*
+ * setservice init's Systems, Devices, Dialers lists from Sysfiles
+ */
+GLOBAL void
+setservice(service)
+char *service;
+{
+	char	*prev = _uu_setlocale(LC_ALL, "C");
+
+	setconfig();
+	scansys(service);
+	(void) _uu_resetlocale(LC_ALL, prev);
+	return;
+}
+
+/*
+ * setdevcfg init's Pops, Pushes lists from Devconfig
+ */
+
+GLOBAL void
+setdevcfg(service, device)
+char *service, *device;
+{
+	char	*prev = _uu_setlocale(LC_ALL, "C");
+
+	scancfg(service, device);
+	(void) _uu_resetlocale(LC_ALL, prev);
+	return;
+}
+
+/*	administrative files access */
+GLOBAL int
+sysaccess(type)
+int type;
+{
+	switch (type) {
+
+	case ACCESS_SYSTEMS:
+		return(access(Systems[nsystems], R_OK));
+	case ACCESS_DEVICES:
+		return(access(Devices[ndevices], R_OK));
+	case ACCESS_DIALERS:
+		return(access(Dialers[ndialers], R_OK));
+	case EACCESS_SYSTEMS:
+		return(eaccess(Systems[nsystems], R_OK));
+	case EACCESS_DEVICES:
+		return(eaccess(Devices[ndevices], R_OK));
+	case EACCESS_DIALERS:
+		return(eaccess(Dialers[ndialers], R_OK));
+	default:
+		(void)sprintf(errformat, "bad access type %d", type);
+		logent(errformat, "sysaccess");
+		return(FAIL);
+	}
+}
+
+
+/*
+ * read Sysfiles, set up lists of Systems/Devices/Dialers file names.
+ * allow multiple entries for a given service, allow a service
+ * type to describe resources more than once, e.g., systems=foo:baz systems=bar.
+ */
+static void
+scansys(service)
+char *service;
+{	FILE *f;
+	char *tok, buf[BUFSIZ];
+
+	Systems[0] = Devices[0] = Dialers[0] = NULL;
+	if ((f = fopen(SYSFILES, "r")) != 0) {
+		while (getline(f, buf) > 0) { 
+			/* got a (logical) line from Sysfiles */
+			/* strtok's of this buf continue in tokenize() */
+			tok = strtok(buf, " \t");
+			if (namematch("service=", tok, service)) {
+				tokenize();
+				nameparse();
+			}
+		}
+		(void) fclose(f);
+	}
+
+	/* if didn't find entries in Sysfiles, use defaults */
+	if (Systems[0] == NULL) {
+		Systems[0] = strsave(SYSTEMS);
+		ASSERT(Systems[0] != NULL, Ct_ALLOCATE, "scansys: Systems", 0);
+		Systems[1] = NULL;
+	}
+	if (Devices[0] == NULL) {
+		Devices[0] = strsave(DEVICES);
+		ASSERT(Devices[0] != NULL, Ct_ALLOCATE, "scansys: Devices", 0);
+		Devices[1] = NULL;
+	}
+	if (Dialers[0] == NULL) {
+		Dialers[0] = strsave(DIALERS);
+		ASSERT(Dialers[0] != NULL, Ct_ALLOCATE, "scansys: Dialers", 0);
+		Dialers[1] = NULL;
+	}
+	return;
+}
+
+
+/*
+ * read Devconfig.  allow multiple entries for a given service, allow a service
+ * type to describe resources more than once, e.g., push=foo:baz push=bar.
+ */
+static void
+scancfg(service, device)
+char *service, *device;
+{	FILE *f;
+	char *tok, buf[BUFSIZ];
+
+	/* (re)initialize device-specific information */
+
+	npops = npushes = 0;
+	Pops[0] = Pushes[0] = NULL;
+	connecttime = CONNECTTIME;
+	expecttime = EXPECTTIME;
+	msgtime = MSGTIME;
+
+	if ((f = fopen(DEVCONFIG, "r")) != 0) {
+		while (getline(f, buf) > 0) {
+			/* got a (logical) line from Devconfig */
+			/* strtok's of this buf continue in tokenize() */
+			tok = strtok(buf, " \t");
+			if (namematch("service=", tok, service)) {
+				tok = strtok((char *)0, " \t");
+				if ( namematch("device=", tok, device)) {
+					tokenize();
+					nameparse();
+				}
+			}
+		}
+		(void) fclose(f);
+	}
+
+	return;
+
+}
+
+/*
+ *  given a file pointer and buffer, construct logical line in buffer
+ *  (i.e., concatenate lines ending in '\').  return length of line
+ *  ASSUMES that buffer is BUFSIZ long!
+ */
+
+static int
+getline(f, line)
+FILE *f;
+char *line;
+{	char *lptr, *lend;
+
+	lptr = line;
+	while (fgets(lptr, (line + BUFSIZ) - lptr, f) != NULL) {
+		lend = lptr + strlen(lptr);
+		if (lend == lptr || lend[-1] != '\n')	
+			/* empty buf or line too long! */
+			break;
+		*--lend = '\0'; /* lop off ending '\n' */
+		if ( lend == line ) /* empty line - ignore */
+			continue;
+		lptr = lend;
+		if (lend[-1] != '\\')
+			break;
+		/* continuation */
+		lend[-1] = ' ';
+	}
+	return(lptr - line);
+}
+
+/*
+ * given a label (e.g., "service=", "device="), a name ("cu", "uucico"),
+ *  and a line:  if line begins with the label and if the name appears
+ * in a colon-separated list of names following the label, return true;
+ * else return false
+ */
+static int
+namematch(label, line, name)
+char *label, *line, *name;
+{	char *lend;
+
+	if (strncmp(label, line, strlen(label)) != SAME) {
+		return(FALSE);	/* probably a comment line */
+	}
+	line += strlen(label);
+	if (*line == '\0')
+		return(FALSE);
+	/*
+	 * can't use strtok() in the following because scansys(),
+	 * scancfg() do an initializing call to strtok() before
+	 * coming here and then CONTINUE calling strtok() in tokenize(),
+	 * after returning from namematch().
+	 */
+	while ((lend = strchr(line, ':')) != NULL) {
+		*lend = '\0';
+		if (strcmp(line, name) == SAME)
+			return(TRUE);
+		line = lend+1;
+	}
+	return(strcmp(line, name) == SAME);
+}
+
+/*
+ * tokenize() continues pulling tokens out of a buffer -- the
+ * initializing call to strtok must have been made before calling
+ * tokenize() -- and starts stuffing 'em into tokptr.
+ */
+static void
+tokenize()
+{	char *tok;
+
+	tokptr = tokens;
+	while ((tok = strtok((char *) NULL, " \t")) != NULL) {
+		*tokptr++ = tok;
+		if (tokptr - tokens >= NTOKENS)
+			break;
+	}
+	*tokptr = NULL;
+	return;
+}
+
+/*
+ * look at top token in array: should be line of the form
+ *	name=item1:item2:item3...
+ * if name is one we recognize, then call set[file|ioctl] to set up 
+ * corresponding list.  otherwise, log bad name.
+ */
+static void
+nameparse()
+{	char **line, *equals;
+	int temp;
+
+#define setuint(a,b,c) a = ( ((temp = atoi(b)) <= 0) ? (c) : temp )
+
+	for (line = tokens; (line - tokens) < NTOKENS && *line; line++) {
+		equals = strchr(*line, '=');
+		if (equals == NULL)
+			continue;	/* may be meaningful someday? */
+		*equals = '\0';
+		/* ignore entry with empty rhs */
+		if (*++equals == '\0')
+			continue;
+		if (strcmp(*line, "systems") == SAME)
+			setfile(Systems, equals);
+		else if (strcmp(*line, "devices") == SAME)
+			setfile(Devices, equals);
+		else if (strcmp(*line, "dialers") == SAME)
+			setfile(Dialers, equals);
+		else if (strcmp(*line, "pop") == SAME)
+			setioctl(Pops, equals);
+		else if (strcmp(*line, "push") == SAME)
+			setioctl(Pushes, equals);
+		else if (strcmp(*line, "connecttime") == SAME)
+			setuint(connecttime, equals, CONNECTTIME);
+		else if (strcmp(*line, "expecttime") == SAME)
+			setuint(expecttime, equals, EXPECTTIME);
+		else if (strcmp(*line, "msgtime") == SAME)
+			setuint(msgtime, equals, MSGTIME);
+		else {
+			(void)sprintf(errformat,"unrecognized label %s",*line);
+			logent(errformat, "Sysfiles|Devconfig");
+		}
+	}
+	return;
+}
+
+/*
+ * given the list for a particular type (systems, devices,...)
+ * and a line of colon-separated files, add 'em to list
+ */
+
+static void
+setfile(type, line)
+char **type, *line;
+{	char **tptr, *tok;
+	char expandpath[BUFSIZ];
+
+	if (*line == 0)
+		return;
+	tptr = type;
+	while (*tptr)		/* skip over existing entries to*/
+		tptr++;		/* concatenate multiple entries */
+
+	for (tok = strtok(line, ":"); tok != NULL;
+	tok = strtok((char *) NULL, ":")) {
+		expandpath[0] = '\0';
+		if ( *tok != '/' )
+			/* by default, file names are relative to SYSDIR */
+			sprintf(expandpath, "%s/", SYSDIR);
+		strcat(expandpath, tok);
+		if (eaccess(expandpath, R_OK) != 0)
+			/* if we can't read it, no point in adding to list */
+			continue;
+		*tptr = strsave(expandpath);
+		ASSERT(*tptr != NULL, Ct_ALLOCATE, "setfile: tptr", 0);
+		tptr++;
+	}
+	return;
+}
+
+/*
+ * given the list for a particular ioctl (push, pop)
+ * and a line of colon-separated modules, add 'em to list
+ */
+
+static void
+setioctl(type, line)
+char **type, *line;
+{	char **tptr, *tok;
+
+	if (*line == 0)
+		return;
+	tptr = type;
+	while (*tptr)		/* skip over existing entries to*/
+		tptr++;		/* concatenate multiple entries */
+	for (tok = strtok(line, ":"); tok != NULL;
+	tok = strtok((char *) NULL, ":")) {
+		*tptr = strsave(tok);
+		ASSERT(*tptr != NULL, Ct_ALLOCATE, "setioctl: tptr", 0);
+		tptr++;
+	}
+	return;
+}
+
+/*
+ * reset Systems files
+ */
+GLOBAL void
+sysreset()
+{
+	if (fsystems)
+		fclose(fsystems);
+	fsystems = NULL;
+	nsystems = 0;
+	devreset();
+	return;
+}
+
+/*
+ * reset Devices files
+ */
+GLOBAL void		
+devreset()
+{
+	if (fdevices)
+		fclose(fdevices);
+	fdevices = NULL;
+	ndevices = 0;
+	dialreset();
+	return;
+}
+
+/*
+ * reset Dialers files
+ */
+GLOBAL void		
+dialreset()
+{
+	if (fdialers)
+		fclose(fdialers);
+	fdialers = NULL;
+	ndialers = 0;
+	return;
+}
+
+/*
+ * get next line from Systems file
+ * return TRUE if successful, FALSE if not
+ */
+GLOBAL int
+getsysline(buf, len)
+char *buf;
+{
+	char	*prev = _uu_setlocale(LC_ALL, "C");
+
+	if (Systems[0] == NULL)
+		/* not initialized via setservice() - use default */
+		setservice("uucico");
+
+	/* initialize devices and dialers whenever a new line is read */
+	/* from systems */
+	devreset();
+	if (fsystems == NULL)
+		if (nextsystems() == FALSE) {
+			(void) _uu_resetlocale(LC_ALL, prev);
+			return(FALSE);
+		}
+
+	ASSERT(len >= BUFSIZ, "BUFFER TOO SMALL", "getsysline", 0);
+	for(;;) {
+		while (getline(fsystems, buf) != NULL)
+		    if ((*buf != '#') && (*buf != ' ') &&
+			(*buf != '\t') && (*buf != '\n')) {
+			(void) _uu_resetlocale(LC_ALL, prev);
+			return(TRUE);
+		}
+		if (nextsystems() == FALSE) {
+			(void) _uu_resetlocale(LC_ALL, prev);
+			return(FALSE);
+		}
+	}
+}
+
+/*
+ * move to next systems file.  return TRUE if successful, FALSE if not
+ */
+static int
+nextsystems()
+{
+	devreset();
+
+	if (fsystems != NULL) {
+		(void) fclose(fsystems);
+		nsystems++;
+	} else {
+		nsystems = 0;
+	}
+	for ( ; Systems[nsystems] != NULL; nsystems++)
+		if ((fsystems = fopen(Systems[nsystems], "r")) != NULL)
+			return(TRUE);
+	return(FALSE);
+}
+		
+/*
+ * get next line from Devices file
+ * return TRUE if successful, FALSE if not
+ */
+GLOBAL int
+getdevline(buf, len)
+char *buf;
+{
+	char	*prev = _uu_setlocale(LC_ALL, "C");
+
+	if (Devices[0] == NULL)
+		/* not initialized via setservice() - use default */
+		setservice("uucico");
+
+	if (fdevices == NULL)
+		if (nextdevices() == FALSE) {
+			(void) _uu_resetlocale(LC_ALL, prev);
+			return(FALSE);
+		}
+	for(;;) {
+		if (fgets(buf, len, fdevices) != NULL) {
+			(void) _uu_resetlocale(LC_ALL, prev);
+			return(TRUE);
+		}
+		if (nextdevices() == FALSE) {
+			(void) _uu_resetlocale(LC_ALL, prev);
+			return(FALSE);
+		}
+	}
+}
+
+/*
+ * move to next devices file.  return TRUE if successful, FALSE if not
+ */
+static int
+nextdevices()
+{
+	if (fdevices != NULL) {
+		(void) fclose(fdevices);
+		ndevices++;
+	} else {
+		ndevices = 0;
+	}
+	for ( ; Devices[ndevices] != NULL; ndevices++)
+		if ((fdevices = fopen(Devices[ndevices], "r")) != NULL)
+			return(TRUE);
+	return(FALSE);
+}
+
+		
+/*
+ * get next line from Dialers file
+ * return TRUE if successful, FALSE if not
+ */
+
+GLOBAL int
+getdialline(buf, len)
+char *buf;
+{
+	char	*prev = _uu_setlocale(LC_ALL, "C");
+
+	if (Dialers[0] == NULL)
+		/* not initialized via setservice() - use default */
+		setservice("uucico");
+
+	if (fdialers == NULL)
+		if (nextdialers() == FALSE) {
+			(void) _uu_resetlocale(LC_ALL, prev);
+			return(FALSE);
+		}
+	for(;;) {
+		if (fgets(buf, len, fdialers) != NULL) {
+			(void) _uu_resetlocale(LC_ALL, prev);
+			return(TRUE);
+		}
+		if (nextdialers() == FALSE) {
+			(void) _uu_resetlocale(LC_ALL, prev);
+			return(FALSE);
+		}
+	}
+}
+
+/*
+ * move to next dialers file.  return TRUE if successful, FALSE if not
+ */
+static int
+nextdialers()
+{
+	if (fdialers) {
+		(void) fclose(fdialers);
+		ndialers++;
+	} else {
+		ndialers = 0;
+	}
+	
+	for ( ; Dialers[ndialers] != NULL; ndialers++)
+		if ((fdialers = fopen(Dialers[ndialers], "r")) != NULL)
+			return(TRUE);
+	return(FALSE);
+}
+
+/*
+ * get next module to be popped
+ * return TRUE if successful, FALSE if not
+ */
+static int
+getpop(buf, len, optional)
+char *buf;
+int len, *optional;
+{
+	int slen;
+
+	if ( Pops[0] == NULL || Pops[npops] == NULL )
+		return(FALSE);
+
+	/*	if the module name is enclosed in parentheses,	*/
+	/*	is optional. set flag & strip parens		*/
+	slen = strlen(Pops[npops]) - 1;
+	if ( Pops[npops][0] == '('  && Pops[npops][slen] == ')' ) {
+		*optional = 1;
+		len = ( slen < len ? slen : len );
+		strncpy(buf, &(Pops[npops++][1]), len);
+	} else {
+		*optional = 0;
+		strncpy(buf, Pops[npops++], len);
+	}
+	buf[len-1] = '\0';
+	return(TRUE);
+}
+
+/*
+ * get next module to be pushed
+ * return TRUE if successful, FALSE if not
+ */
+static int
+getpush(buf, len)
+char *buf;
+int len;
+{
+	if ( Pushes[0] == NULL || Pushes[npushes] == NULL )
+		return(FALSE);
+	strncpy(buf, Pushes[npushes++], len);
+	return(TRUE);
+}
+
+/*
+ * pop/push requested modules
+ * return TRUE if successful, FALSE if not
+ */
+GLOBAL int
+pop_push(fd)
+int fd;
+{
+    char	strmod[FMNAMESZ], onstream[FMNAMESZ];
+    int		optional;
+    char	*prev = _uu_setlocale(LC_ALL, "C");
+
+    /*	check for streams modules to pop	*/
+    while ( getpop(strmod, sizeof(strmod), &optional) ) {
+	DEBUG(5, (optional ? "pop_push: optionally POPing %s\n"
+			   : "pop_push: POPing %s\n" ), strmod);
+	if ( ioctl(fd, I_LOOK, onstream) == -1 ) {
+	    DEBUG(5, "pop_push: I_LOOK on fd %d failed ", fd);
+	    DEBUG(5, "errno %d\n", errno);
+	    (void) _uu_resetlocale(LC_ALL, prev);
+	    return(FALSE);
+	}
+	if ( strcmp(strmod, onstream) != SAME ) {
+	    if ( optional )
+		continue;
+	    DEBUG(5, "pop_push: I_POP: %s not there\n", strmod);
+	    (void) _uu_resetlocale(LC_ALL, prev);
+	    return(FALSE);
+	}
+	if ( ioctl(fd, I_POP, 0) == -1 ) {
+	    DEBUG(5, "pop_push: I_POP on fd %d failed ", fd);
+	    DEBUG(5, "errno %d\n", errno);
+	    (void) _uu_resetlocale(LC_ALL, prev);
+	    return(FALSE);
+	}
+    }
+
+    /*	check for streams modules to push	*/
+    while ( getpush(strmod, sizeof(strmod)) ) {
+	DEBUG(5, "pop_push: PUSHing %s\n", strmod);
+	if ( ioctl(fd, I_PUSH, strmod) == -1 ) {
+	    DEBUG(5, "pop_push: I_PUSH on fd %d failed ", fd);
+	    DEBUG(5, "errno %d\n", errno);
+	    (void) _uu_resetlocale(LC_ALL, prev);
+	    return(FALSE);
+	}
+    }
+    (void) _uu_resetlocale(LC_ALL, prev);
+    return(TRUE);
+}
+
+/*
+ * 	return name of currently open Systems file
+ */
+GLOBAL char *
+currsys()
+{
+	return(Systems[nsystems]);
+}
+
+/*
+ * 	return name of currently open Devices file
+ */
+GLOBAL char *
+currdev()
+{
+	return(Devices[ndevices]);
+}
+
+/*
+ * 	return name of currently open Dialers file
+ */
+GLOBAL char *
+currdial()
+{
+	return(Dialers[ndialers]);
+}
+
+/*
+ * set configuration parameters provided in Config file
+ */
+static void
+setconfig()
+{
+    FILE *f;
+    char buf[BUFSIZ];
+    char *tok;
+    extern char _ProtoCfg[];
+
+    if ((f = fopen(CONFIG, "r")) != 0) {
+	while (getline(f, buf) > 0) { 
+	    /* got a (logical) line from Config file */
+	    tok = strtok(buf, " \t");
+	    if ( (tok != NULL) && (*tok != '#') ) {
+		/* got a token */
+
+		/* this probably should be table driven when
+		 * the list of configurable parameters grows.
+		 */
+		if (strncmp("Protocol=", tok, strlen("Protocol=")) == SAME) {
+		    tok += strlen("Protocol=");
+		    if ( *tok != '\0' ) {
+			if ( _ProtoCfg[0] != '\0' ) {
+			    DEBUG(7, "Protocol string %s ", tok);
+			    DEBUG(7, "overrides %s\n", _ProtoCfg);
+		        }
+		        strcpy(_ProtoCfg, tok);
+		    }
+	        } else {
+		    DEBUG(7, "Unknown configuration parameter %s\n", tok);
+	        }
+	    }
+	}
+    }
+}