174462Salfred/* $NetBSD: getnetconfig.c,v 1.3 2000/07/06 03:10:34 christos Exp $ */ 274462Salfred 374462Salfred/* 474462Salfred * Sun RPC is a product of Sun Microsystems, Inc. and is provided for 574462Salfred * unrestricted use provided that this legend is included on all tape 674462Salfred * media and as a part of the software program in whole or part. Users 774462Salfred * may copy or modify Sun RPC without charge, but are not authorized 874462Salfred * to license or distribute it to anyone else except as part of a product or 974462Salfred * program developed by the user or with the express written consent of 1074462Salfred * Sun Microsystems, Inc. 1174462Salfred * 1274462Salfred * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE 1374462Salfred * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR 1474462Salfred * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. 1574462Salfred * 1674462Salfred * Sun RPC is provided with no support and without any obligation on the 1774462Salfred * part of Sun Microsystems, Inc. to assist in its use, correction, 1874462Salfred * modification or enhancement. 1974462Salfred * 2074462Salfred * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE 2174462Salfred * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC 2274462Salfred * OR ANY PART THEREOF. 2374462Salfred * 2474462Salfred * In no event will Sun Microsystems, Inc. be liable for any lost revenue 2574462Salfred * or profits or other special, indirect and consequential damages, even if 2674462Salfred * Sun has been advised of the possibility of such damages. 2774462Salfred * 2874462Salfred * Sun Microsystems, Inc. 2974462Salfred * 2550 Garcia Avenue 3074462Salfred * Mountain View, California 94043 3174462Salfred */ 32136581Sobrien 33136581Sobrien#if defined(LIBC_SCCS) && !defined(lint) 34136581Sobrienstatic char sccsid[] = "@(#)getnetconfig.c 1.12 91/12/19 SMI"; 3574462Salfred#endif 3692990Sobrien#include <sys/cdefs.h> 3792990Sobrien__FBSDID("$FreeBSD$"); 3874462Salfred 3974462Salfred/* 4074462Salfred * Copyright (c) 1989 by Sun Microsystems, Inc. 4174462Salfred */ 4274462Salfred 4375094Siedowse#include "namespace.h" 4474462Salfred#include "reentrant.h" 4574462Salfred#include <stdio.h> 4674462Salfred#include <errno.h> 4774462Salfred#include <netconfig.h> 48109956Smbr#include <stddef.h> 4974462Salfred#include <stdlib.h> 5074462Salfred#include <string.h> 5174462Salfred#include <rpc/rpc.h> 52111010Snectar#include <unistd.h> 5374462Salfred#include "un-namespace.h" 5474462Salfred#include "rpc_com.h" 5574462Salfred 5674462Salfred/* 5774462Salfred * The five library routines in this file provide application access to the 5874462Salfred * system network configuration database, /etc/netconfig. In addition to the 5974462Salfred * netconfig database and the routines for accessing it, the environment 6074462Salfred * variable NETPATH and its corresponding routines in getnetpath.c may also be 6174462Salfred * used to specify the network transport to be used. 6274462Salfred */ 6374462Salfred 6474462Salfred 6574462Salfred/* 6674462Salfred * netconfig errors 6774462Salfred */ 6874462Salfred 6974462Salfred#define NC_NONETCONFIG ENOENT 7074462Salfred#define NC_NOMEM ENOMEM 7174462Salfred#define NC_NOTINIT EINVAL /* setnetconfig was not called first */ 7274462Salfred#define NC_BADFILE EBADF /* format for netconfig file is bad */ 7375146Siedowse#define NC_NOTFOUND ENOPROTOOPT /* specified netid was not found */ 7474462Salfred 7574462Salfred/* 7674462Salfred * semantics as strings (should be in netconfig.h) 7774462Salfred */ 7874462Salfred#define NC_TPI_CLTS_S "tpi_clts" 7974462Salfred#define NC_TPI_COTS_S "tpi_cots" 8074462Salfred#define NC_TPI_COTS_ORD_S "tpi_cots_ord" 8174462Salfred#define NC_TPI_RAW_S "tpi_raw" 8274462Salfred 8374462Salfred/* 8474462Salfred * flags as characters (also should be in netconfig.h) 8574462Salfred */ 8674462Salfred#define NC_NOFLAG_C '-' 8774462Salfred#define NC_VISIBLE_C 'v' 8874462Salfred#define NC_BROADCAST_C 'b' 8974462Salfred 9074462Salfred/* 9174462Salfred * Character used to indicate there is no name-to-address lookup library 9274462Salfred */ 9374462Salfred#define NC_NOLOOKUP "-" 9474462Salfred 9574462Salfredstatic const char * const _nc_errors[] = { 9674462Salfred "Netconfig database not found", 9774462Salfred "Not enough memory", 9874462Salfred "Not initialized", 9975146Siedowse "Netconfig database has invalid format", 10075146Siedowse "Netid not found in netconfig database" 10174462Salfred}; 10274462Salfred 10374462Salfredstruct netconfig_info { 10474462Salfred int eof; /* all entries has been read */ 10574462Salfred int ref; /* # of times setnetconfig() has been called */ 10674462Salfred struct netconfig_list *head; /* head of the list */ 10774462Salfred struct netconfig_list *tail; /* last of the list */ 10874462Salfred}; 10974462Salfred 11074462Salfredstruct netconfig_list { 11174462Salfred char *linep; /* hold line read from netconfig */ 11274462Salfred struct netconfig *ncp; 11374462Salfred struct netconfig_list *next; 11474462Salfred}; 11574462Salfred 11674462Salfredstruct netconfig_vars { 11774462Salfred int valid; /* token that indicates a valid netconfig_vars */ 11874462Salfred int flag; /* first time flag */ 11974462Salfred struct netconfig_list *nc_configs; /* pointer to the current netconfig entry */ 12074462Salfred}; 12174462Salfred 12274462Salfred#define NC_VALID 0xfeed 12374462Salfred#define NC_STORAGE 0xf00d 12474462Salfred#define NC_INVALID 0 12574462Salfred 12674462Salfred 12792905Sobrienstatic int *__nc_error(void); 12892905Sobrienstatic int parse_ncp(char *, struct netconfig *); 12992905Sobrienstatic struct netconfig *dup_ncp(struct netconfig *); 13074462Salfred 13174462Salfred 13274462Salfredstatic FILE *nc_file; /* for netconfig db */ 133204950Sjhbstatic mutex_t nc_file_lock = MUTEX_INITIALIZER; 134194932Sdelphij 13574462Salfredstatic struct netconfig_info ni = { 0, 0, NULL, NULL}; 136204950Sjhbstatic mutex_t ni_lock = MUTEX_INITIALIZER; 13774462Salfred 138204950Sjhbstatic thread_key_t nc_key; 139204950Sjhbstatic once_t nc_once = ONCE_INITIALIZER; 140204950Sjhbstatic int nc_key_error; 141194932Sdelphij 142204950Sjhbstatic void 143204950Sjhbnc_key_init(void) 144204950Sjhb{ 145204950Sjhb 146204950Sjhb nc_key_error = thr_keycreate(&nc_key, free); 147204950Sjhb} 148204950Sjhb 14974462Salfred#define MAXNETCONFIGLINE 1000 15074462Salfred 15174462Salfredstatic int * 15274462Salfred__nc_error() 15374462Salfred{ 15474462Salfred static int nc_error = 0; 155204950Sjhb int *nc_addr; 15674462Salfred 15775146Siedowse /* 15875146Siedowse * Use the static `nc_error' if we are the main thread 15975146Siedowse * (including non-threaded programs), or if an allocation 16075146Siedowse * fails. 16175146Siedowse */ 16275146Siedowse if (thr_main()) 16375146Siedowse return (&nc_error); 164204950Sjhb if (thr_once(&nc_once, nc_key_init) != 0 || nc_key_error != 0) 165204950Sjhb return (&nc_error); 16675146Siedowse if ((nc_addr = (int *)thr_getspecific(nc_key)) == NULL) { 16774462Salfred nc_addr = (int *)malloc(sizeof (int)); 16874462Salfred if (thr_setspecific(nc_key, (void *) nc_addr) != 0) { 16974462Salfred if (nc_addr) 17074462Salfred free(nc_addr); 17175146Siedowse return (&nc_error); 17274462Salfred } 17374462Salfred *nc_addr = 0; 17474462Salfred } 17575146Siedowse return (nc_addr); 17674462Salfred} 17774462Salfred 17874462Salfred#define nc_error (*(__nc_error())) 17974462Salfred/* 18074462Salfred * A call to setnetconfig() establishes a /etc/netconfig "session". A session 18174462Salfred * "handle" is returned on a successful call. At the start of a session (after 18274462Salfred * a call to setnetconfig()) searches through the /etc/netconfig database will 18374462Salfred * proceed from the start of the file. The session handle must be passed to 18474462Salfred * getnetconfig() to parse the file. Each call to getnetconfig() using the 18574462Salfred * current handle will process one subsequent entry in /etc/netconfig. 18674462Salfred * setnetconfig() must be called before the first call to getnetconfig(). 18774462Salfred * (Handles are used to allow for nested calls to setnetpath()). 18874462Salfred * 18974462Salfred * A new session is established with each call to setnetconfig(), with a new 19074462Salfred * handle being returned on each call. Previously established sessions remain 19174462Salfred * active until endnetconfig() is called with that session's handle as an 19274462Salfred * argument. 19374462Salfred * 19474462Salfred * setnetconfig() need *not* be called before a call to getnetconfigent(). 19574462Salfred * setnetconfig() returns a NULL pointer on failure (for example, if 19674462Salfred * the netconfig database is not present). 19774462Salfred */ 19874462Salfredvoid * 19974462Salfredsetnetconfig() 20074462Salfred{ 20174462Salfred struct netconfig_vars *nc_vars; 20274462Salfred 20374462Salfred if ((nc_vars = (struct netconfig_vars *)malloc(sizeof 20474462Salfred (struct netconfig_vars))) == NULL) { 20574462Salfred return(NULL); 20674462Salfred } 20774462Salfred 20874462Salfred /* 20974462Salfred * For multiple calls, i.e. nc_file is not NULL, we just return the 21074462Salfred * handle without reopening the netconfig db. 21174462Salfred */ 212194932Sdelphij mutex_lock(&ni_lock); 21374462Salfred ni.ref++; 214194932Sdelphij mutex_unlock(&ni_lock); 215194932Sdelphij 216194932Sdelphij mutex_lock(&nc_file_lock); 21774462Salfred if ((nc_file != NULL) || (nc_file = fopen(NETCONFIG, "r")) != NULL) { 21874462Salfred nc_vars->valid = NC_VALID; 21974462Salfred nc_vars->flag = 0; 22074462Salfred nc_vars->nc_configs = ni.head; 221194932Sdelphij mutex_unlock(&nc_file_lock); 22274462Salfred return ((void *)nc_vars); 22374462Salfred } 224194932Sdelphij mutex_unlock(&nc_file_lock); 225194932Sdelphij 226194932Sdelphij mutex_lock(&ni_lock); 22774462Salfred ni.ref--; 228194932Sdelphij mutex_unlock(&ni_lock); 229194932Sdelphij 23074462Salfred nc_error = NC_NONETCONFIG; 23174462Salfred free(nc_vars); 23274462Salfred return (NULL); 23374462Salfred} 23474462Salfred 23574462Salfred 23674462Salfred/* 23774462Salfred * When first called, getnetconfig() returns a pointer to the first entry in 23874462Salfred * the netconfig database, formatted as a struct netconfig. On each subsequent 23974462Salfred * call, getnetconfig() returns a pointer to the next entry in the database. 24074462Salfred * getnetconfig() can thus be used to search the entire netconfig file. 24174462Salfred * getnetconfig() returns NULL at end of file. 24274462Salfred */ 24374462Salfred 24474462Salfredstruct netconfig * 24574462Salfredgetnetconfig(handlep) 24674462Salfredvoid *handlep; 24774462Salfred{ 24874462Salfred struct netconfig_vars *ncp = (struct netconfig_vars *)handlep; 24974462Salfred char *stringp; /* tmp string pointer */ 25074462Salfred struct netconfig_list *list; 25174462Salfred struct netconfig *np; 252194932Sdelphij struct netconfig *result; 25374462Salfred 25474462Salfred /* 25574462Salfred * Verify that handle is valid 25674462Salfred */ 257194932Sdelphij mutex_lock(&nc_file_lock); 25874462Salfred if (ncp == NULL || nc_file == NULL) { 25974462Salfred nc_error = NC_NOTINIT; 260194932Sdelphij mutex_unlock(&nc_file_lock); 26174462Salfred return (NULL); 26274462Salfred } 263194932Sdelphij mutex_unlock(&nc_file_lock); 26474462Salfred 26574462Salfred switch (ncp->valid) { 26674462Salfred case NC_VALID: 26774462Salfred /* 26874462Salfred * If entry has already been read into the list, 26974462Salfred * we return the entry in the linked list. 27074462Salfred * If this is the first time call, check if there are any entries in 27174462Salfred * linked list. If no entries, we need to read the netconfig db. 27274462Salfred * If we have been here and the next entry is there, we just return 27374462Salfred * it. 27474462Salfred */ 27574462Salfred if (ncp->flag == 0) { /* first time */ 27674462Salfred ncp->flag = 1; 277194932Sdelphij mutex_lock(&ni_lock); 27874462Salfred ncp->nc_configs = ni.head; 279194932Sdelphij mutex_unlock(&ni_lock); 28074462Salfred if (ncp->nc_configs != NULL) /* entry already exist */ 28174462Salfred return(ncp->nc_configs->ncp); 28274462Salfred } 28374462Salfred else if (ncp->nc_configs != NULL && ncp->nc_configs->next != NULL) { 28474462Salfred ncp->nc_configs = ncp->nc_configs->next; 28574462Salfred return(ncp->nc_configs->ncp); 28674462Salfred } 28774462Salfred 28874462Salfred /* 28974462Salfred * If we cannot find the entry in the list and is end of file, 29074462Salfred * we give up. 29174462Salfred */ 292194932Sdelphij mutex_lock(&ni_lock); 293194932Sdelphij if (ni.eof == 1) { 294194932Sdelphij mutex_unlock(&ni_lock); 295194932Sdelphij return(NULL); 296194932Sdelphij } 297194932Sdelphij mutex_unlock(&ni_lock); 298194932Sdelphij 29974462Salfred break; 30074462Salfred default: 30174462Salfred nc_error = NC_NOTINIT; 30274462Salfred return (NULL); 30374462Salfred } 30474462Salfred 30574462Salfred stringp = (char *) malloc(MAXNETCONFIGLINE); 30674462Salfred if (stringp == NULL) 30774462Salfred return (NULL); 30874462Salfred 30974462Salfred#ifdef MEM_CHK 31074462Salfred if (malloc_verify() == 0) { 31174462Salfred fprintf(stderr, "memory heap corrupted in getnetconfig\n"); 31274462Salfred exit(1); 31374462Salfred } 31474462Salfred#endif 31574462Salfred 31674462Salfred /* 31774462Salfred * Read a line from netconfig file. 31874462Salfred */ 319194932Sdelphij mutex_lock(&nc_file_lock); 32074462Salfred do { 32174462Salfred if (fgets(stringp, MAXNETCONFIGLINE, nc_file) == NULL) { 32274462Salfred free(stringp); 323194932Sdelphij mutex_lock(&ni_lock); 32474462Salfred ni.eof = 1; 325194932Sdelphij mutex_unlock(&ni_lock); 326194932Sdelphij mutex_unlock(&nc_file_lock); 32774462Salfred return (NULL); 32874462Salfred } 32974462Salfred } while (*stringp == '#'); 330194932Sdelphij mutex_unlock(&nc_file_lock); 33174462Salfred 33274462Salfred list = (struct netconfig_list *) malloc(sizeof (struct netconfig_list)); 33374462Salfred if (list == NULL) { 33474462Salfred free(stringp); 33574462Salfred return(NULL); 33674462Salfred } 33774462Salfred np = (struct netconfig *) malloc(sizeof (struct netconfig)); 33874462Salfred if (np == NULL) { 33974462Salfred free(stringp); 34074462Salfred free(list); 34174462Salfred return(NULL); 34274462Salfred } 34374462Salfred list->ncp = np; 34474462Salfred list->next = NULL; 34574462Salfred list->ncp->nc_lookups = NULL; 34674462Salfred list->linep = stringp; 34774462Salfred if (parse_ncp(stringp, list->ncp) == -1) { 34874462Salfred free(stringp); 34974462Salfred free(np); 35074462Salfred free(list); 35174462Salfred return (NULL); 35274462Salfred } 35374462Salfred else { 35474462Salfred /* 35574462Salfred * If this is the first entry that's been read, it is the head of 35674462Salfred * the list. If not, put the entry at the end of the list. 35774462Salfred * Reposition the current pointer of the handle to the last entry 35874462Salfred * in the list. 35974462Salfred */ 360194932Sdelphij mutex_lock(&ni_lock); 36174462Salfred if (ni.head == NULL) { /* first entry */ 36274462Salfred ni.head = ni.tail = list; 36374462Salfred } 36474462Salfred else { 36574462Salfred ni.tail->next = list; 36674462Salfred ni.tail = ni.tail->next; 36774462Salfred } 36874462Salfred ncp->nc_configs = ni.tail; 369194932Sdelphij result = ni.tail->ncp; 370194932Sdelphij mutex_unlock(&ni_lock); 371194932Sdelphij return(result); 37274462Salfred } 37374462Salfred} 37474462Salfred 37574462Salfred/* 37674462Salfred * endnetconfig() may be called to "unbind" or "close" the netconfig database 37774462Salfred * when processing is complete, releasing resources for reuse. endnetconfig() 37874462Salfred * may not be called before setnetconfig(). endnetconfig() returns 0 on 37974462Salfred * success and -1 on failure (for example, if setnetconfig() was not called 38074462Salfred * previously). 38174462Salfred */ 38274462Salfredint 38374462Salfredendnetconfig(handlep) 38474462Salfredvoid *handlep; 38574462Salfred{ 38674462Salfred struct netconfig_vars *nc_handlep = (struct netconfig_vars *)handlep; 38774462Salfred 38874462Salfred struct netconfig_list *q, *p; 38974462Salfred 39074462Salfred /* 39174462Salfred * Verify that handle is valid 39274462Salfred */ 39374462Salfred if (nc_handlep == NULL || (nc_handlep->valid != NC_VALID && 39474462Salfred nc_handlep->valid != NC_STORAGE)) { 39574462Salfred nc_error = NC_NOTINIT; 39674462Salfred return (-1); 39774462Salfred } 39874462Salfred 39974462Salfred /* 40074462Salfred * Return 0 if anyone still needs it. 40174462Salfred */ 40274462Salfred nc_handlep->valid = NC_INVALID; 40374462Salfred nc_handlep->flag = 0; 40474462Salfred nc_handlep->nc_configs = NULL; 405194932Sdelphij mutex_lock(&ni_lock); 40674462Salfred if (--ni.ref > 0) { 407194932Sdelphij mutex_unlock(&ni_lock); 40874462Salfred free(nc_handlep); 40974462Salfred return(0); 41074462Salfred } 41174462Salfred 41274462Salfred /* 41374462Salfred * Noone needs these entries anymore, then frees them. 41474462Salfred * Make sure all info in netconfig_info structure has been reinitialized. 41574462Salfred */ 416199784Swollman q = ni.head; 41774462Salfred ni.eof = ni.ref = 0; 41874462Salfred ni.head = NULL; 41974462Salfred ni.tail = NULL; 420194932Sdelphij mutex_unlock(&ni_lock); 421194932Sdelphij 422199784Swollman while (q != NULL) { 42374462Salfred p = q->next; 42474462Salfred if (q->ncp->nc_lookups != NULL) free(q->ncp->nc_lookups); 42574462Salfred free(q->ncp); 42674462Salfred free(q->linep); 42774462Salfred free(q); 42874462Salfred q = p; 42974462Salfred } 43074462Salfred free(nc_handlep); 43174462Salfred 432194932Sdelphij mutex_lock(&nc_file_lock); 43374462Salfred fclose(nc_file); 43474462Salfred nc_file = NULL; 435194932Sdelphij mutex_unlock(&nc_file_lock); 436194932Sdelphij 43774462Salfred return (0); 43874462Salfred} 43974462Salfred 44074462Salfred/* 44174462Salfred * getnetconfigent(netid) returns a pointer to the struct netconfig structure 44274462Salfred * corresponding to netid. It returns NULL if netid is invalid (that is, does 44374462Salfred * not name an entry in the netconfig database). It returns NULL and sets 44474462Salfred * errno in case of failure (for example, if the netconfig database cannot be 44574462Salfred * opened). 44674462Salfred */ 44774462Salfred 44874462Salfredstruct netconfig * 44974462Salfredgetnetconfigent(netid) 45074843Salfred const char *netid; 45174462Salfred{ 45274462Salfred FILE *file; /* NETCONFIG db's file pointer */ 45374462Salfred char *linep; /* holds current netconfig line */ 45474462Salfred char *stringp; /* temporary string pointer */ 45574462Salfred struct netconfig *ncp = NULL; /* returned value */ 45674462Salfred struct netconfig_list *list; /* pointer to cache list */ 45774462Salfred 45875146Siedowse nc_error = NC_NOTFOUND; /* default error. */ 45974462Salfred if (netid == NULL || strlen(netid) == 0) { 46074462Salfred return (NULL); 46174462Salfred } 46274462Salfred 46374462Salfred /* 46474462Salfred * Look up table if the entries have already been read and parsed in 46574462Salfred * getnetconfig(), then copy this entry into a buffer and return it. 46674462Salfred * If we cannot find the entry in the current list and there are more 46774462Salfred * entries in the netconfig db that has not been read, we then read the 46874462Salfred * db and try find the match netid. 46974462Salfred * If all the netconfig db has been read and placed into the list and 47074462Salfred * there is no match for the netid, return NULL. 47174462Salfred */ 472194932Sdelphij mutex_lock(&ni_lock); 47374462Salfred if (ni.head != NULL) { 47474462Salfred for (list = ni.head; list; list = list->next) { 47574462Salfred if (strcmp(list->ncp->nc_netid, netid) == 0) { 476194932Sdelphij mutex_unlock(&ni_lock); 47774462Salfred return(dup_ncp(list->ncp)); 47874462Salfred } 47974462Salfred } 480194932Sdelphij if (ni.eof == 1) { /* that's all the entries */ 481194932Sdelphij mutex_unlock(&ni_lock); 48274462Salfred return(NULL); 483194932Sdelphij } 48474462Salfred } 485194932Sdelphij mutex_unlock(&ni_lock); 48674462Salfred 48774462Salfred 48874462Salfred if ((file = fopen(NETCONFIG, "r")) == NULL) { 48975146Siedowse nc_error = NC_NONETCONFIG; 49074462Salfred return (NULL); 49174462Salfred } 49274462Salfred 49374462Salfred if ((linep = malloc(MAXNETCONFIGLINE)) == NULL) { 49474462Salfred fclose(file); 49575146Siedowse nc_error = NC_NOMEM; 49674462Salfred return (NULL); 49774462Salfred } 49874462Salfred do { 499109956Smbr ptrdiff_t len; 50074462Salfred char *tmpp; /* tmp string pointer */ 50174462Salfred 50274462Salfred do { 50374462Salfred if ((stringp = fgets(linep, MAXNETCONFIGLINE, file)) == NULL) { 50474462Salfred break; 50574462Salfred } 50674462Salfred } while (*stringp == '#'); 50774462Salfred if (stringp == NULL) { /* eof */ 50874462Salfred break; 50974462Salfred } 51074462Salfred if ((tmpp = strpbrk(stringp, "\t ")) == NULL) { /* can't parse file */ 51174462Salfred nc_error = NC_BADFILE; 51274462Salfred break; 51374462Salfred } 514109956Smbr if (strlen(netid) == (size_t) (len = tmpp - stringp) && /* a match */ 51574462Salfred strncmp(stringp, netid, (size_t)len) == 0) { 51674462Salfred if ((ncp = (struct netconfig *) 51774462Salfred malloc(sizeof (struct netconfig))) == NULL) { 51874462Salfred break; 51974462Salfred } 52074462Salfred ncp->nc_lookups = NULL; 52174462Salfred if (parse_ncp(linep, ncp) == -1) { 52274462Salfred free(ncp); 52374462Salfred ncp = NULL; 52474462Salfred } 52574462Salfred break; 52674462Salfred } 52774462Salfred } while (stringp != NULL); 52874462Salfred if (ncp == NULL) { 52974462Salfred free(linep); 53074462Salfred } 53174462Salfred fclose(file); 53274462Salfred return(ncp); 53374462Salfred} 53474462Salfred 53574462Salfred/* 53674462Salfred * freenetconfigent(netconfigp) frees the netconfig structure pointed to by 53774462Salfred * netconfigp (previously returned by getnetconfigent()). 53874462Salfred */ 53974462Salfred 54074462Salfredvoid 54174462Salfredfreenetconfigent(netconfigp) 54274462Salfred struct netconfig *netconfigp; 54374462Salfred{ 54474462Salfred if (netconfigp != NULL) { 54574462Salfred free(netconfigp->nc_netid); /* holds all netconfigp's strings */ 54674462Salfred if (netconfigp->nc_lookups != NULL) 54774462Salfred free(netconfigp->nc_lookups); 54874462Salfred free(netconfigp); 54974462Salfred } 55074462Salfred return; 55174462Salfred} 55274462Salfred 55374462Salfred/* 55474462Salfred * Parse line and stuff it in a struct netconfig 55574462Salfred * Typical line might look like: 55674462Salfred * udp tpi_cots vb inet udp /dev/udp /usr/lib/ip.so,/usr/local/ip.so 55774462Salfred * 55874462Salfred * We return -1 if any of the tokens don't parse, or malloc fails. 55974462Salfred * 56074462Salfred * Note that we modify stringp (putting NULLs after tokens) and 56174462Salfred * we set the ncp's string field pointers to point to these tokens within 56274462Salfred * stringp. 56374462Salfred */ 56474462Salfred 56574462Salfredstatic int 56674462Salfredparse_ncp(stringp, ncp) 56774462Salfredchar *stringp; /* string to parse */ 56874462Salfredstruct netconfig *ncp; /* where to put results */ 56974462Salfred{ 57074462Salfred char *tokenp; /* for processing tokens */ 57174462Salfred char *lasts; 572172259Smatteo char **nc_lookups; 57374462Salfred 57474462Salfred nc_error = NC_BADFILE; /* nearly anything that breaks is for this reason */ 57574462Salfred stringp[strlen(stringp)-1] = '\0'; /* get rid of newline */ 57674462Salfred /* netid */ 57774462Salfred if ((ncp->nc_netid = strtok_r(stringp, "\t ", &lasts)) == NULL) { 57874462Salfred return (-1); 57974462Salfred } 58074462Salfred 58174462Salfred /* semantics */ 58274462Salfred if ((tokenp = strtok_r(NULL, "\t ", &lasts)) == NULL) { 58374462Salfred return (-1); 58474462Salfred } 58574462Salfred if (strcmp(tokenp, NC_TPI_COTS_ORD_S) == 0) 58674462Salfred ncp->nc_semantics = NC_TPI_COTS_ORD; 58774462Salfred else if (strcmp(tokenp, NC_TPI_COTS_S) == 0) 58874462Salfred ncp->nc_semantics = NC_TPI_COTS; 58974462Salfred else if (strcmp(tokenp, NC_TPI_CLTS_S) == 0) 59074462Salfred ncp->nc_semantics = NC_TPI_CLTS; 59174462Salfred else if (strcmp(tokenp, NC_TPI_RAW_S) == 0) 59274462Salfred ncp->nc_semantics = NC_TPI_RAW; 59374462Salfred else 59474462Salfred return (-1); 59574462Salfred 59674462Salfred /* flags */ 59774462Salfred if ((tokenp = strtok_r(NULL, "\t ", &lasts)) == NULL) { 59874462Salfred return (-1); 59974462Salfred } 60074462Salfred for (ncp->nc_flag = NC_NOFLAG; *tokenp != '\0'; 60174462Salfred tokenp++) { 60274462Salfred switch (*tokenp) { 60374462Salfred case NC_NOFLAG_C: 60474462Salfred break; 60574462Salfred case NC_VISIBLE_C: 60674462Salfred ncp->nc_flag |= NC_VISIBLE; 60774462Salfred break; 60874462Salfred case NC_BROADCAST_C: 60974462Salfred ncp->nc_flag |= NC_BROADCAST; 61074462Salfred break; 61174462Salfred default: 61274462Salfred return (-1); 61374462Salfred } 61474462Salfred } 61574462Salfred /* protocol family */ 61674462Salfred if ((ncp->nc_protofmly = strtok_r(NULL, "\t ", &lasts)) == NULL) { 61774462Salfred return (-1); 61874462Salfred } 61974462Salfred /* protocol name */ 62074462Salfred if ((ncp->nc_proto = strtok_r(NULL, "\t ", &lasts)) == NULL) { 62174462Salfred return (-1); 62274462Salfred } 62374462Salfred /* network device */ 62474462Salfred if ((ncp->nc_device = strtok_r(NULL, "\t ", &lasts)) == NULL) { 62574462Salfred return (-1); 62674462Salfred } 62774462Salfred if ((tokenp = strtok_r(NULL, "\t ", &lasts)) == NULL) { 62874462Salfred return (-1); 62974462Salfred } 63074462Salfred if (strcmp(tokenp, NC_NOLOOKUP) == 0) { 63174462Salfred ncp->nc_nlookups = 0; 63274462Salfred ncp->nc_lookups = NULL; 63374462Salfred } else { 63474462Salfred char *cp; /* tmp string */ 63574462Salfred 63674462Salfred if (ncp->nc_lookups != NULL) /* from last visit */ 63774462Salfred free(ncp->nc_lookups); 638172259Smatteo ncp->nc_lookups = NULL; 63974462Salfred ncp->nc_nlookups = 0; 64074462Salfred while ((cp = tokenp) != NULL) { 641172259Smatteo if ((nc_lookups = realloc(ncp->nc_lookups, 642172259Smatteo (ncp->nc_nlookups + 1) * sizeof *ncp->nc_lookups)) == NULL) { 643172259Smatteo free(ncp->nc_lookups); 644172259Smatteo ncp->nc_lookups = NULL; 645172259Smatteo return (-1); 646172259Smatteo } 64774462Salfred tokenp = _get_next_token(cp, ','); 648172259Smatteo ncp->nc_lookups = nc_lookups; 649172259Smatteo ncp->nc_lookups[ncp->nc_nlookups++] = cp; 65074462Salfred } 65174462Salfred } 65274462Salfred return (0); 65374462Salfred} 65474462Salfred 65574462Salfred 65674462Salfred/* 65774462Salfred * Returns a string describing the reason for failure. 65874462Salfred */ 65974462Salfredchar * 66074462Salfrednc_sperror() 66174462Salfred{ 66274462Salfred const char *message; 66374462Salfred 66474462Salfred switch(nc_error) { 66574462Salfred case NC_NONETCONFIG: 66674462Salfred message = _nc_errors[0]; 66774462Salfred break; 66874462Salfred case NC_NOMEM: 66974462Salfred message = _nc_errors[1]; 67074462Salfred break; 67174462Salfred case NC_NOTINIT: 67274462Salfred message = _nc_errors[2]; 67374462Salfred break; 67474462Salfred case NC_BADFILE: 67574462Salfred message = _nc_errors[3]; 67674462Salfred break; 67775146Siedowse case NC_NOTFOUND: 67875146Siedowse message = _nc_errors[4]; 67975146Siedowse break; 68074462Salfred default: 68174462Salfred message = "Unknown network selection error"; 68274462Salfred } 68374462Salfred /* LINTED const castaway */ 68474462Salfred return ((char *)message); 68574462Salfred} 68674462Salfred 68774462Salfred/* 68874462Salfred * Prints a message onto standard error describing the reason for failure. 68974462Salfred */ 69074462Salfredvoid 69174462Salfrednc_perror(s) 69274462Salfred const char *s; 69374462Salfred{ 69475146Siedowse fprintf(stderr, "%s: %s\n", s, nc_sperror()); 69574462Salfred} 69674462Salfred 69774462Salfred/* 69874462Salfred * Duplicates the matched netconfig buffer. 69974462Salfred */ 70074462Salfredstatic struct netconfig * 70174462Salfreddup_ncp(ncp) 70274462Salfredstruct netconfig *ncp; 70374462Salfred{ 70474462Salfred struct netconfig *p; 70574462Salfred char *tmp; 706109956Smbr u_int i; 70774462Salfred 70874462Salfred if ((tmp=malloc(MAXNETCONFIGLINE)) == NULL) 70974462Salfred return(NULL); 71074462Salfred if ((p=(struct netconfig *)malloc(sizeof(struct netconfig))) == NULL) { 71174462Salfred free(tmp); 71274462Salfred return(NULL); 71374462Salfred } 71474462Salfred /* 71574462Salfred * First we dup all the data from matched netconfig buffer. Then we 71674462Salfred * adjust some of the member pointer to a pre-allocated buffer where 71774462Salfred * contains part of the data. 71874462Salfred * To follow the convention used in parse_ncp(), we store all the 719109956Smbr * necessary information in the pre-allocated buffer and let each 72074462Salfred * of the netconfig char pointer member point to the right address 72174462Salfred * in the buffer. 72274462Salfred */ 72374462Salfred *p = *ncp; 72474462Salfred p->nc_netid = (char *)strcpy(tmp,ncp->nc_netid); 725126643Smarkm tmp = strchr(tmp, '\0') + 1; 72674462Salfred p->nc_protofmly = (char *)strcpy(tmp,ncp->nc_protofmly); 727126643Smarkm tmp = strchr(tmp, '\0') + 1; 72874462Salfred p->nc_proto = (char *)strcpy(tmp,ncp->nc_proto); 729126643Smarkm tmp = strchr(tmp, '\0') + 1; 73074462Salfred p->nc_device = (char *)strcpy(tmp,ncp->nc_device); 73174462Salfred p->nc_lookups = (char **)malloc((size_t)(p->nc_nlookups+1) * sizeof(char *)); 73274462Salfred if (p->nc_lookups == NULL) { 73374462Salfred free(p->nc_netid); 734162191Smbr free(p); 73574462Salfred return(NULL); 73674462Salfred } 73774462Salfred for (i=0; i < p->nc_nlookups; i++) { 738126643Smarkm tmp = strchr(tmp, '\0') + 1; 73974462Salfred p->nc_lookups[i] = (char *)strcpy(tmp,ncp->nc_lookups[i]); 74074462Salfred } 74174462Salfred return(p); 74274462Salfred} 743