/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (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 (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved. */ /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ /* All Rights Reserved */ #include "uucp.h" #include #include "sysfiles.h" #include /* * 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(), getaline(); /* 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 (getaline(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 (getaline(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 getaline(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 (getaline(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 (getaline(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); } } } } }