174462Salfred/* $NetBSD: getnetconfig.c,v 1.3 2000/07/06 03:10:34 christos Exp $ */ 274462Salfred 3261057Smav/*- 4261057Smav * Copyright (c) 2009, Sun Microsystems, Inc. 5261057Smav * All rights reserved. 674462Salfred * 7261057Smav * Redistribution and use in source and binary forms, with or without 8261057Smav * modification, are permitted provided that the following conditions are met: 9261057Smav * - Redistributions of source code must retain the above copyright notice, 10261057Smav * this list of conditions and the following disclaimer. 11261057Smav * - Redistributions in binary form must reproduce the above copyright notice, 12261057Smav * this list of conditions and the following disclaimer in the documentation 13261057Smav * and/or other materials provided with the distribution. 14261057Smav * - Neither the name of Sun Microsystems, Inc. nor the names of its 15261057Smav * contributors may be used to endorse or promote products derived 16261057Smav * from this software without specific prior written permission. 17261057Smav * 18261057Smav * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19261057Smav * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20261057Smav * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21261057Smav * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 22261057Smav * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23261057Smav * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24261057Smav * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25261057Smav * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26261057Smav * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27261057Smav * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28261057Smav * POSSIBILITY OF SUCH DAMAGE. 2974462Salfred */ 30136581Sobrien 31136581Sobrien#if defined(LIBC_SCCS) && !defined(lint) 32136581Sobrienstatic char sccsid[] = "@(#)getnetconfig.c 1.12 91/12/19 SMI"; 3374462Salfred#endif 3492990Sobrien#include <sys/cdefs.h> 3592990Sobrien__FBSDID("$FreeBSD$"); 3674462Salfred 3774462Salfred/* 3874462Salfred * Copyright (c) 1989 by Sun Microsystems, Inc. 3974462Salfred */ 4074462Salfred 4175094Siedowse#include "namespace.h" 4274462Salfred#include "reentrant.h" 4374462Salfred#include <stdio.h> 4474462Salfred#include <errno.h> 4574462Salfred#include <netconfig.h> 46109956Smbr#include <stddef.h> 4774462Salfred#include <stdlib.h> 4874462Salfred#include <string.h> 4974462Salfred#include <rpc/rpc.h> 50111010Snectar#include <unistd.h> 5174462Salfred#include "un-namespace.h" 5274462Salfred#include "rpc_com.h" 5374462Salfred 5474462Salfred/* 5574462Salfred * The five library routines in this file provide application access to the 5674462Salfred * system network configuration database, /etc/netconfig. In addition to the 5774462Salfred * netconfig database and the routines for accessing it, the environment 5874462Salfred * variable NETPATH and its corresponding routines in getnetpath.c may also be 5974462Salfred * used to specify the network transport to be used. 6074462Salfred */ 6174462Salfred 6274462Salfred 6374462Salfred/* 6474462Salfred * netconfig errors 6574462Salfred */ 6674462Salfred 6774462Salfred#define NC_NONETCONFIG ENOENT 6874462Salfred#define NC_NOMEM ENOMEM 6974462Salfred#define NC_NOTINIT EINVAL /* setnetconfig was not called first */ 7074462Salfred#define NC_BADFILE EBADF /* format for netconfig file is bad */ 7175146Siedowse#define NC_NOTFOUND ENOPROTOOPT /* specified netid was not found */ 7274462Salfred 7374462Salfred/* 7474462Salfred * semantics as strings (should be in netconfig.h) 7574462Salfred */ 7674462Salfred#define NC_TPI_CLTS_S "tpi_clts" 7774462Salfred#define NC_TPI_COTS_S "tpi_cots" 7874462Salfred#define NC_TPI_COTS_ORD_S "tpi_cots_ord" 7974462Salfred#define NC_TPI_RAW_S "tpi_raw" 8074462Salfred 8174462Salfred/* 8274462Salfred * flags as characters (also should be in netconfig.h) 8374462Salfred */ 8474462Salfred#define NC_NOFLAG_C '-' 8574462Salfred#define NC_VISIBLE_C 'v' 8674462Salfred#define NC_BROADCAST_C 'b' 8774462Salfred 8874462Salfred/* 8974462Salfred * Character used to indicate there is no name-to-address lookup library 9074462Salfred */ 9174462Salfred#define NC_NOLOOKUP "-" 9274462Salfred 9374462Salfredstatic const char * const _nc_errors[] = { 9474462Salfred "Netconfig database not found", 9574462Salfred "Not enough memory", 9674462Salfred "Not initialized", 9775146Siedowse "Netconfig database has invalid format", 9875146Siedowse "Netid not found in netconfig database" 9974462Salfred}; 10074462Salfred 10174462Salfredstruct netconfig_info { 10274462Salfred int eof; /* all entries has been read */ 10374462Salfred int ref; /* # of times setnetconfig() has been called */ 10474462Salfred struct netconfig_list *head; /* head of the list */ 10574462Salfred struct netconfig_list *tail; /* last of the list */ 10674462Salfred}; 10774462Salfred 10874462Salfredstruct netconfig_list { 10974462Salfred char *linep; /* hold line read from netconfig */ 11074462Salfred struct netconfig *ncp; 11174462Salfred struct netconfig_list *next; 11274462Salfred}; 11374462Salfred 11474462Salfredstruct netconfig_vars { 11574462Salfred int valid; /* token that indicates a valid netconfig_vars */ 11674462Salfred int flag; /* first time flag */ 11774462Salfred struct netconfig_list *nc_configs; /* pointer to the current netconfig entry */ 11874462Salfred}; 11974462Salfred 12074462Salfred#define NC_VALID 0xfeed 12174462Salfred#define NC_STORAGE 0xf00d 12274462Salfred#define NC_INVALID 0 12374462Salfred 12474462Salfred 12592905Sobrienstatic int *__nc_error(void); 12692905Sobrienstatic int parse_ncp(char *, struct netconfig *); 12792905Sobrienstatic struct netconfig *dup_ncp(struct netconfig *); 12874462Salfred 12974462Salfred 13074462Salfredstatic FILE *nc_file; /* for netconfig db */ 131204950Sjhbstatic mutex_t nc_file_lock = MUTEX_INITIALIZER; 132194932Sdelphij 13374462Salfredstatic struct netconfig_info ni = { 0, 0, NULL, NULL}; 134204950Sjhbstatic mutex_t ni_lock = MUTEX_INITIALIZER; 13574462Salfred 136204950Sjhbstatic thread_key_t nc_key; 137204950Sjhbstatic once_t nc_once = ONCE_INITIALIZER; 138204950Sjhbstatic int nc_key_error; 139194932Sdelphij 140204950Sjhbstatic void 141204950Sjhbnc_key_init(void) 142204950Sjhb{ 143204950Sjhb 144204950Sjhb nc_key_error = thr_keycreate(&nc_key, free); 145204950Sjhb} 146204950Sjhb 14774462Salfred#define MAXNETCONFIGLINE 1000 14874462Salfred 14974462Salfredstatic int * 15074462Salfred__nc_error() 15174462Salfred{ 15274462Salfred static int nc_error = 0; 153204950Sjhb int *nc_addr; 15474462Salfred 15575146Siedowse /* 15675146Siedowse * Use the static `nc_error' if we are the main thread 15775146Siedowse * (including non-threaded programs), or if an allocation 15875146Siedowse * fails. 15975146Siedowse */ 16075146Siedowse if (thr_main()) 16175146Siedowse return (&nc_error); 162204950Sjhb if (thr_once(&nc_once, nc_key_init) != 0 || nc_key_error != 0) 163204950Sjhb return (&nc_error); 16475146Siedowse if ((nc_addr = (int *)thr_getspecific(nc_key)) == NULL) { 16574462Salfred nc_addr = (int *)malloc(sizeof (int)); 16674462Salfred if (thr_setspecific(nc_key, (void *) nc_addr) != 0) { 16774462Salfred if (nc_addr) 16874462Salfred free(nc_addr); 16975146Siedowse return (&nc_error); 17074462Salfred } 17174462Salfred *nc_addr = 0; 17274462Salfred } 17375146Siedowse return (nc_addr); 17474462Salfred} 17574462Salfred 17674462Salfred#define nc_error (*(__nc_error())) 17774462Salfred/* 17874462Salfred * A call to setnetconfig() establishes a /etc/netconfig "session". A session 17974462Salfred * "handle" is returned on a successful call. At the start of a session (after 18074462Salfred * a call to setnetconfig()) searches through the /etc/netconfig database will 18174462Salfred * proceed from the start of the file. The session handle must be passed to 18274462Salfred * getnetconfig() to parse the file. Each call to getnetconfig() using the 18374462Salfred * current handle will process one subsequent entry in /etc/netconfig. 18474462Salfred * setnetconfig() must be called before the first call to getnetconfig(). 18574462Salfred * (Handles are used to allow for nested calls to setnetpath()). 18674462Salfred * 18774462Salfred * A new session is established with each call to setnetconfig(), with a new 18874462Salfred * handle being returned on each call. Previously established sessions remain 18974462Salfred * active until endnetconfig() is called with that session's handle as an 19074462Salfred * argument. 19174462Salfred * 19274462Salfred * setnetconfig() need *not* be called before a call to getnetconfigent(). 19374462Salfred * setnetconfig() returns a NULL pointer on failure (for example, if 19474462Salfred * the netconfig database is not present). 19574462Salfred */ 19674462Salfredvoid * 19774462Salfredsetnetconfig() 19874462Salfred{ 19974462Salfred struct netconfig_vars *nc_vars; 20074462Salfred 20174462Salfred if ((nc_vars = (struct netconfig_vars *)malloc(sizeof 20274462Salfred (struct netconfig_vars))) == NULL) { 20374462Salfred return(NULL); 20474462Salfred } 20574462Salfred 20674462Salfred /* 20774462Salfred * For multiple calls, i.e. nc_file is not NULL, we just return the 20874462Salfred * handle without reopening the netconfig db. 20974462Salfred */ 210194932Sdelphij mutex_lock(&ni_lock); 21174462Salfred ni.ref++; 212194932Sdelphij mutex_unlock(&ni_lock); 213194932Sdelphij 214194932Sdelphij mutex_lock(&nc_file_lock); 21574462Salfred if ((nc_file != NULL) || (nc_file = fopen(NETCONFIG, "r")) != NULL) { 21674462Salfred nc_vars->valid = NC_VALID; 21774462Salfred nc_vars->flag = 0; 21874462Salfred nc_vars->nc_configs = ni.head; 219194932Sdelphij mutex_unlock(&nc_file_lock); 22074462Salfred return ((void *)nc_vars); 22174462Salfred } 222194932Sdelphij mutex_unlock(&nc_file_lock); 223194932Sdelphij 224194932Sdelphij mutex_lock(&ni_lock); 22574462Salfred ni.ref--; 226194932Sdelphij mutex_unlock(&ni_lock); 227194932Sdelphij 22874462Salfred nc_error = NC_NONETCONFIG; 22974462Salfred free(nc_vars); 23074462Salfred return (NULL); 23174462Salfred} 23274462Salfred 23374462Salfred 23474462Salfred/* 23574462Salfred * When first called, getnetconfig() returns a pointer to the first entry in 23674462Salfred * the netconfig database, formatted as a struct netconfig. On each subsequent 23774462Salfred * call, getnetconfig() returns a pointer to the next entry in the database. 23874462Salfred * getnetconfig() can thus be used to search the entire netconfig file. 23974462Salfred * getnetconfig() returns NULL at end of file. 24074462Salfred */ 24174462Salfred 24274462Salfredstruct netconfig * 24374462Salfredgetnetconfig(handlep) 24474462Salfredvoid *handlep; 24574462Salfred{ 24674462Salfred struct netconfig_vars *ncp = (struct netconfig_vars *)handlep; 24774462Salfred char *stringp; /* tmp string pointer */ 24874462Salfred struct netconfig_list *list; 24974462Salfred struct netconfig *np; 250194932Sdelphij struct netconfig *result; 25174462Salfred 25274462Salfred /* 25374462Salfred * Verify that handle is valid 25474462Salfred */ 255194932Sdelphij mutex_lock(&nc_file_lock); 25674462Salfred if (ncp == NULL || nc_file == NULL) { 25774462Salfred nc_error = NC_NOTINIT; 258194932Sdelphij mutex_unlock(&nc_file_lock); 25974462Salfred return (NULL); 26074462Salfred } 261194932Sdelphij mutex_unlock(&nc_file_lock); 26274462Salfred 26374462Salfred switch (ncp->valid) { 26474462Salfred case NC_VALID: 26574462Salfred /* 26674462Salfred * If entry has already been read into the list, 26774462Salfred * we return the entry in the linked list. 26874462Salfred * If this is the first time call, check if there are any entries in 26974462Salfred * linked list. If no entries, we need to read the netconfig db. 27074462Salfred * If we have been here and the next entry is there, we just return 27174462Salfred * it. 27274462Salfred */ 27374462Salfred if (ncp->flag == 0) { /* first time */ 27474462Salfred ncp->flag = 1; 275194932Sdelphij mutex_lock(&ni_lock); 27674462Salfred ncp->nc_configs = ni.head; 277194932Sdelphij mutex_unlock(&ni_lock); 27874462Salfred if (ncp->nc_configs != NULL) /* entry already exist */ 27974462Salfred return(ncp->nc_configs->ncp); 28074462Salfred } 28174462Salfred else if (ncp->nc_configs != NULL && ncp->nc_configs->next != NULL) { 28274462Salfred ncp->nc_configs = ncp->nc_configs->next; 28374462Salfred return(ncp->nc_configs->ncp); 28474462Salfred } 28574462Salfred 28674462Salfred /* 28774462Salfred * If we cannot find the entry in the list and is end of file, 28874462Salfred * we give up. 28974462Salfred */ 290194932Sdelphij mutex_lock(&ni_lock); 291194932Sdelphij if (ni.eof == 1) { 292194932Sdelphij mutex_unlock(&ni_lock); 293194932Sdelphij return(NULL); 294194932Sdelphij } 295194932Sdelphij mutex_unlock(&ni_lock); 296194932Sdelphij 29774462Salfred break; 29874462Salfred default: 29974462Salfred nc_error = NC_NOTINIT; 30074462Salfred return (NULL); 30174462Salfred } 30274462Salfred 30374462Salfred stringp = (char *) malloc(MAXNETCONFIGLINE); 30474462Salfred if (stringp == NULL) 30574462Salfred return (NULL); 30674462Salfred 30774462Salfred#ifdef MEM_CHK 30874462Salfred if (malloc_verify() == 0) { 30974462Salfred fprintf(stderr, "memory heap corrupted in getnetconfig\n"); 31074462Salfred exit(1); 31174462Salfred } 31274462Salfred#endif 31374462Salfred 31474462Salfred /* 31574462Salfred * Read a line from netconfig file. 31674462Salfred */ 317194932Sdelphij mutex_lock(&nc_file_lock); 31874462Salfred do { 31974462Salfred if (fgets(stringp, MAXNETCONFIGLINE, nc_file) == NULL) { 32074462Salfred free(stringp); 321194932Sdelphij mutex_lock(&ni_lock); 32274462Salfred ni.eof = 1; 323194932Sdelphij mutex_unlock(&ni_lock); 324194932Sdelphij mutex_unlock(&nc_file_lock); 32574462Salfred return (NULL); 32674462Salfred } 32774462Salfred } while (*stringp == '#'); 328194932Sdelphij mutex_unlock(&nc_file_lock); 32974462Salfred 33074462Salfred list = (struct netconfig_list *) malloc(sizeof (struct netconfig_list)); 33174462Salfred if (list == NULL) { 33274462Salfred free(stringp); 33374462Salfred return(NULL); 33474462Salfred } 33574462Salfred np = (struct netconfig *) malloc(sizeof (struct netconfig)); 33674462Salfred if (np == NULL) { 33774462Salfred free(stringp); 33874462Salfred free(list); 33974462Salfred return(NULL); 34074462Salfred } 34174462Salfred list->ncp = np; 34274462Salfred list->next = NULL; 34374462Salfred list->ncp->nc_lookups = NULL; 34474462Salfred list->linep = stringp; 34574462Salfred if (parse_ncp(stringp, list->ncp) == -1) { 34674462Salfred free(stringp); 34774462Salfred free(np); 34874462Salfred free(list); 34974462Salfred return (NULL); 35074462Salfred } 35174462Salfred else { 35274462Salfred /* 35374462Salfred * If this is the first entry that's been read, it is the head of 35474462Salfred * the list. If not, put the entry at the end of the list. 35574462Salfred * Reposition the current pointer of the handle to the last entry 35674462Salfred * in the list. 35774462Salfred */ 358194932Sdelphij mutex_lock(&ni_lock); 35974462Salfred if (ni.head == NULL) { /* first entry */ 36074462Salfred ni.head = ni.tail = list; 36174462Salfred } 36274462Salfred else { 36374462Salfred ni.tail->next = list; 36474462Salfred ni.tail = ni.tail->next; 36574462Salfred } 36674462Salfred ncp->nc_configs = ni.tail; 367194932Sdelphij result = ni.tail->ncp; 368194932Sdelphij mutex_unlock(&ni_lock); 369194932Sdelphij return(result); 37074462Salfred } 37174462Salfred} 37274462Salfred 37374462Salfred/* 37474462Salfred * endnetconfig() may be called to "unbind" or "close" the netconfig database 37574462Salfred * when processing is complete, releasing resources for reuse. endnetconfig() 37674462Salfred * may not be called before setnetconfig(). endnetconfig() returns 0 on 37774462Salfred * success and -1 on failure (for example, if setnetconfig() was not called 37874462Salfred * previously). 37974462Salfred */ 38074462Salfredint 38174462Salfredendnetconfig(handlep) 38274462Salfredvoid *handlep; 38374462Salfred{ 38474462Salfred struct netconfig_vars *nc_handlep = (struct netconfig_vars *)handlep; 38574462Salfred 38674462Salfred struct netconfig_list *q, *p; 38774462Salfred 38874462Salfred /* 38974462Salfred * Verify that handle is valid 39074462Salfred */ 39174462Salfred if (nc_handlep == NULL || (nc_handlep->valid != NC_VALID && 39274462Salfred nc_handlep->valid != NC_STORAGE)) { 39374462Salfred nc_error = NC_NOTINIT; 39474462Salfred return (-1); 39574462Salfred } 39674462Salfred 39774462Salfred /* 39874462Salfred * Return 0 if anyone still needs it. 39974462Salfred */ 40074462Salfred nc_handlep->valid = NC_INVALID; 40174462Salfred nc_handlep->flag = 0; 40274462Salfred nc_handlep->nc_configs = NULL; 403194932Sdelphij mutex_lock(&ni_lock); 40474462Salfred if (--ni.ref > 0) { 405194932Sdelphij mutex_unlock(&ni_lock); 40674462Salfred free(nc_handlep); 40774462Salfred return(0); 40874462Salfred } 40974462Salfred 41074462Salfred /* 41174462Salfred * Noone needs these entries anymore, then frees them. 41274462Salfred * Make sure all info in netconfig_info structure has been reinitialized. 41374462Salfred */ 414199784Swollman q = ni.head; 41574462Salfred ni.eof = ni.ref = 0; 41674462Salfred ni.head = NULL; 41774462Salfred ni.tail = NULL; 418194932Sdelphij mutex_unlock(&ni_lock); 419194932Sdelphij 420199784Swollman while (q != NULL) { 42174462Salfred p = q->next; 42274462Salfred if (q->ncp->nc_lookups != NULL) free(q->ncp->nc_lookups); 42374462Salfred free(q->ncp); 42474462Salfred free(q->linep); 42574462Salfred free(q); 42674462Salfred q = p; 42774462Salfred } 42874462Salfred free(nc_handlep); 42974462Salfred 430194932Sdelphij mutex_lock(&nc_file_lock); 43174462Salfred fclose(nc_file); 43274462Salfred nc_file = NULL; 433194932Sdelphij mutex_unlock(&nc_file_lock); 434194932Sdelphij 43574462Salfred return (0); 43674462Salfred} 43774462Salfred 43874462Salfred/* 43974462Salfred * getnetconfigent(netid) returns a pointer to the struct netconfig structure 44074462Salfred * corresponding to netid. It returns NULL if netid is invalid (that is, does 44174462Salfred * not name an entry in the netconfig database). It returns NULL and sets 44274462Salfred * errno in case of failure (for example, if the netconfig database cannot be 44374462Salfred * opened). 44474462Salfred */ 44574462Salfred 44674462Salfredstruct netconfig * 44774462Salfredgetnetconfigent(netid) 44874843Salfred const char *netid; 44974462Salfred{ 45074462Salfred FILE *file; /* NETCONFIG db's file pointer */ 45174462Salfred char *linep; /* holds current netconfig line */ 45274462Salfred char *stringp; /* temporary string pointer */ 45374462Salfred struct netconfig *ncp = NULL; /* returned value */ 45474462Salfred struct netconfig_list *list; /* pointer to cache list */ 45574462Salfred 45675146Siedowse nc_error = NC_NOTFOUND; /* default error. */ 45774462Salfred if (netid == NULL || strlen(netid) == 0) { 45874462Salfred return (NULL); 45974462Salfred } 46074462Salfred 46174462Salfred /* 46274462Salfred * Look up table if the entries have already been read and parsed in 46374462Salfred * getnetconfig(), then copy this entry into a buffer and return it. 46474462Salfred * If we cannot find the entry in the current list and there are more 46574462Salfred * entries in the netconfig db that has not been read, we then read the 46674462Salfred * db and try find the match netid. 46774462Salfred * If all the netconfig db has been read and placed into the list and 46874462Salfred * there is no match for the netid, return NULL. 46974462Salfred */ 470194932Sdelphij mutex_lock(&ni_lock); 47174462Salfred if (ni.head != NULL) { 47274462Salfred for (list = ni.head; list; list = list->next) { 47374462Salfred if (strcmp(list->ncp->nc_netid, netid) == 0) { 474194932Sdelphij mutex_unlock(&ni_lock); 47574462Salfred return(dup_ncp(list->ncp)); 47674462Salfred } 47774462Salfred } 478194932Sdelphij if (ni.eof == 1) { /* that's all the entries */ 479194932Sdelphij mutex_unlock(&ni_lock); 48074462Salfred return(NULL); 481194932Sdelphij } 48274462Salfred } 483194932Sdelphij mutex_unlock(&ni_lock); 48474462Salfred 48574462Salfred 48674462Salfred if ((file = fopen(NETCONFIG, "r")) == NULL) { 48775146Siedowse nc_error = NC_NONETCONFIG; 48874462Salfred return (NULL); 48974462Salfred } 49074462Salfred 49174462Salfred if ((linep = malloc(MAXNETCONFIGLINE)) == NULL) { 49274462Salfred fclose(file); 49375146Siedowse nc_error = NC_NOMEM; 49474462Salfred return (NULL); 49574462Salfred } 49674462Salfred do { 497109956Smbr ptrdiff_t len; 49874462Salfred char *tmpp; /* tmp string pointer */ 49974462Salfred 50074462Salfred do { 50174462Salfred if ((stringp = fgets(linep, MAXNETCONFIGLINE, file)) == NULL) { 50274462Salfred break; 50374462Salfred } 50474462Salfred } while (*stringp == '#'); 50574462Salfred if (stringp == NULL) { /* eof */ 50674462Salfred break; 50774462Salfred } 50874462Salfred if ((tmpp = strpbrk(stringp, "\t ")) == NULL) { /* can't parse file */ 50974462Salfred nc_error = NC_BADFILE; 51074462Salfred break; 51174462Salfred } 512109956Smbr if (strlen(netid) == (size_t) (len = tmpp - stringp) && /* a match */ 51374462Salfred strncmp(stringp, netid, (size_t)len) == 0) { 51474462Salfred if ((ncp = (struct netconfig *) 51574462Salfred malloc(sizeof (struct netconfig))) == NULL) { 51674462Salfred break; 51774462Salfred } 51874462Salfred ncp->nc_lookups = NULL; 51974462Salfred if (parse_ncp(linep, ncp) == -1) { 52074462Salfred free(ncp); 52174462Salfred ncp = NULL; 52274462Salfred } 52374462Salfred break; 52474462Salfred } 52574462Salfred } while (stringp != NULL); 52674462Salfred if (ncp == NULL) { 52774462Salfred free(linep); 52874462Salfred } 52974462Salfred fclose(file); 53074462Salfred return(ncp); 53174462Salfred} 53274462Salfred 53374462Salfred/* 53474462Salfred * freenetconfigent(netconfigp) frees the netconfig structure pointed to by 53574462Salfred * netconfigp (previously returned by getnetconfigent()). 53674462Salfred */ 53774462Salfred 53874462Salfredvoid 53974462Salfredfreenetconfigent(netconfigp) 54074462Salfred struct netconfig *netconfigp; 54174462Salfred{ 54274462Salfred if (netconfigp != NULL) { 54374462Salfred free(netconfigp->nc_netid); /* holds all netconfigp's strings */ 54474462Salfred if (netconfigp->nc_lookups != NULL) 54574462Salfred free(netconfigp->nc_lookups); 54674462Salfred free(netconfigp); 54774462Salfred } 54874462Salfred return; 54974462Salfred} 55074462Salfred 55174462Salfred/* 55274462Salfred * Parse line and stuff it in a struct netconfig 55374462Salfred * Typical line might look like: 55474462Salfred * udp tpi_cots vb inet udp /dev/udp /usr/lib/ip.so,/usr/local/ip.so 55574462Salfred * 55674462Salfred * We return -1 if any of the tokens don't parse, or malloc fails. 55774462Salfred * 55874462Salfred * Note that we modify stringp (putting NULLs after tokens) and 55974462Salfred * we set the ncp's string field pointers to point to these tokens within 56074462Salfred * stringp. 56174462Salfred */ 56274462Salfred 56374462Salfredstatic int 56474462Salfredparse_ncp(stringp, ncp) 56574462Salfredchar *stringp; /* string to parse */ 56674462Salfredstruct netconfig *ncp; /* where to put results */ 56774462Salfred{ 56874462Salfred char *tokenp; /* for processing tokens */ 56974462Salfred char *lasts; 570172259Smatteo char **nc_lookups; 57174462Salfred 57274462Salfred nc_error = NC_BADFILE; /* nearly anything that breaks is for this reason */ 57374462Salfred stringp[strlen(stringp)-1] = '\0'; /* get rid of newline */ 57474462Salfred /* netid */ 57574462Salfred if ((ncp->nc_netid = strtok_r(stringp, "\t ", &lasts)) == NULL) { 57674462Salfred return (-1); 57774462Salfred } 57874462Salfred 57974462Salfred /* semantics */ 58074462Salfred if ((tokenp = strtok_r(NULL, "\t ", &lasts)) == NULL) { 58174462Salfred return (-1); 58274462Salfred } 58374462Salfred if (strcmp(tokenp, NC_TPI_COTS_ORD_S) == 0) 58474462Salfred ncp->nc_semantics = NC_TPI_COTS_ORD; 58574462Salfred else if (strcmp(tokenp, NC_TPI_COTS_S) == 0) 58674462Salfred ncp->nc_semantics = NC_TPI_COTS; 58774462Salfred else if (strcmp(tokenp, NC_TPI_CLTS_S) == 0) 58874462Salfred ncp->nc_semantics = NC_TPI_CLTS; 58974462Salfred else if (strcmp(tokenp, NC_TPI_RAW_S) == 0) 59074462Salfred ncp->nc_semantics = NC_TPI_RAW; 59174462Salfred else 59274462Salfred return (-1); 59374462Salfred 59474462Salfred /* flags */ 59574462Salfred if ((tokenp = strtok_r(NULL, "\t ", &lasts)) == NULL) { 59674462Salfred return (-1); 59774462Salfred } 59874462Salfred for (ncp->nc_flag = NC_NOFLAG; *tokenp != '\0'; 59974462Salfred tokenp++) { 60074462Salfred switch (*tokenp) { 60174462Salfred case NC_NOFLAG_C: 60274462Salfred break; 60374462Salfred case NC_VISIBLE_C: 60474462Salfred ncp->nc_flag |= NC_VISIBLE; 60574462Salfred break; 60674462Salfred case NC_BROADCAST_C: 60774462Salfred ncp->nc_flag |= NC_BROADCAST; 60874462Salfred break; 60974462Salfred default: 61074462Salfred return (-1); 61174462Salfred } 61274462Salfred } 61374462Salfred /* protocol family */ 61474462Salfred if ((ncp->nc_protofmly = strtok_r(NULL, "\t ", &lasts)) == NULL) { 61574462Salfred return (-1); 61674462Salfred } 61774462Salfred /* protocol name */ 61874462Salfred if ((ncp->nc_proto = strtok_r(NULL, "\t ", &lasts)) == NULL) { 61974462Salfred return (-1); 62074462Salfred } 62174462Salfred /* network device */ 62274462Salfred if ((ncp->nc_device = strtok_r(NULL, "\t ", &lasts)) == NULL) { 62374462Salfred return (-1); 62474462Salfred } 62574462Salfred if ((tokenp = strtok_r(NULL, "\t ", &lasts)) == NULL) { 62674462Salfred return (-1); 62774462Salfred } 62874462Salfred if (strcmp(tokenp, NC_NOLOOKUP) == 0) { 62974462Salfred ncp->nc_nlookups = 0; 63074462Salfred ncp->nc_lookups = NULL; 63174462Salfred } else { 63274462Salfred char *cp; /* tmp string */ 63374462Salfred 63474462Salfred if (ncp->nc_lookups != NULL) /* from last visit */ 63574462Salfred free(ncp->nc_lookups); 636172259Smatteo ncp->nc_lookups = NULL; 63774462Salfred ncp->nc_nlookups = 0; 63874462Salfred while ((cp = tokenp) != NULL) { 639172259Smatteo if ((nc_lookups = realloc(ncp->nc_lookups, 640172259Smatteo (ncp->nc_nlookups + 1) * sizeof *ncp->nc_lookups)) == NULL) { 641172259Smatteo free(ncp->nc_lookups); 642172259Smatteo ncp->nc_lookups = NULL; 643172259Smatteo return (-1); 644172259Smatteo } 64574462Salfred tokenp = _get_next_token(cp, ','); 646172259Smatteo ncp->nc_lookups = nc_lookups; 647172259Smatteo ncp->nc_lookups[ncp->nc_nlookups++] = cp; 64874462Salfred } 64974462Salfred } 65074462Salfred return (0); 65174462Salfred} 65274462Salfred 65374462Salfred 65474462Salfred/* 65574462Salfred * Returns a string describing the reason for failure. 65674462Salfred */ 65774462Salfredchar * 65874462Salfrednc_sperror() 65974462Salfred{ 66074462Salfred const char *message; 66174462Salfred 66274462Salfred switch(nc_error) { 66374462Salfred case NC_NONETCONFIG: 66474462Salfred message = _nc_errors[0]; 66574462Salfred break; 66674462Salfred case NC_NOMEM: 66774462Salfred message = _nc_errors[1]; 66874462Salfred break; 66974462Salfred case NC_NOTINIT: 67074462Salfred message = _nc_errors[2]; 67174462Salfred break; 67274462Salfred case NC_BADFILE: 67374462Salfred message = _nc_errors[3]; 67474462Salfred break; 67575146Siedowse case NC_NOTFOUND: 67675146Siedowse message = _nc_errors[4]; 67775146Siedowse break; 67874462Salfred default: 67974462Salfred message = "Unknown network selection error"; 68074462Salfred } 68174462Salfred /* LINTED const castaway */ 68274462Salfred return ((char *)message); 68374462Salfred} 68474462Salfred 68574462Salfred/* 68674462Salfred * Prints a message onto standard error describing the reason for failure. 68774462Salfred */ 68874462Salfredvoid 68974462Salfrednc_perror(s) 69074462Salfred const char *s; 69174462Salfred{ 69275146Siedowse fprintf(stderr, "%s: %s\n", s, nc_sperror()); 69374462Salfred} 69474462Salfred 69574462Salfred/* 69674462Salfred * Duplicates the matched netconfig buffer. 69774462Salfred */ 69874462Salfredstatic struct netconfig * 69974462Salfreddup_ncp(ncp) 70074462Salfredstruct netconfig *ncp; 70174462Salfred{ 70274462Salfred struct netconfig *p; 70374462Salfred char *tmp; 704109956Smbr u_int i; 70574462Salfred 70674462Salfred if ((tmp=malloc(MAXNETCONFIGLINE)) == NULL) 70774462Salfred return(NULL); 70874462Salfred if ((p=(struct netconfig *)malloc(sizeof(struct netconfig))) == NULL) { 70974462Salfred free(tmp); 71074462Salfred return(NULL); 71174462Salfred } 71274462Salfred /* 71374462Salfred * First we dup all the data from matched netconfig buffer. Then we 71474462Salfred * adjust some of the member pointer to a pre-allocated buffer where 71574462Salfred * contains part of the data. 71674462Salfred * To follow the convention used in parse_ncp(), we store all the 717109956Smbr * necessary information in the pre-allocated buffer and let each 71874462Salfred * of the netconfig char pointer member point to the right address 71974462Salfred * in the buffer. 72074462Salfred */ 72174462Salfred *p = *ncp; 72274462Salfred p->nc_netid = (char *)strcpy(tmp,ncp->nc_netid); 723126643Smarkm tmp = strchr(tmp, '\0') + 1; 72474462Salfred p->nc_protofmly = (char *)strcpy(tmp,ncp->nc_protofmly); 725126643Smarkm tmp = strchr(tmp, '\0') + 1; 72674462Salfred p->nc_proto = (char *)strcpy(tmp,ncp->nc_proto); 727126643Smarkm tmp = strchr(tmp, '\0') + 1; 72874462Salfred p->nc_device = (char *)strcpy(tmp,ncp->nc_device); 72974462Salfred p->nc_lookups = (char **)malloc((size_t)(p->nc_nlookups+1) * sizeof(char *)); 73074462Salfred if (p->nc_lookups == NULL) { 73174462Salfred free(p->nc_netid); 732162191Smbr free(p); 73374462Salfred return(NULL); 73474462Salfred } 73574462Salfred for (i=0; i < p->nc_nlookups; i++) { 736126643Smarkm tmp = strchr(tmp, '\0') + 1; 73774462Salfred p->nc_lookups[i] = (char *)strcpy(tmp,ncp->nc_lookups[i]); 73874462Salfred } 73974462Salfred return(p); 74074462Salfred} 741