Home | History | Annotate | Line # | Download | only in rpc
      1  1.25  christos /*	$NetBSD: getnetconfig.c,v 1.25 2017/06/30 10:03:34 christos Exp $	*/
      2   1.1      fvdl 
      3   1.1      fvdl /*
      4  1.21      tron  * Copyright (c) 2010, Oracle America, Inc.
      5   1.1      fvdl  *
      6  1.21      tron  * Redistribution and use in source and binary forms, with or without
      7  1.21      tron  * modification, are permitted provided that the following conditions are
      8  1.21      tron  * met:
      9   1.1      fvdl  *
     10  1.21      tron  *     * Redistributions of source code must retain the above copyright
     11  1.21      tron  *       notice, this list of conditions and the following disclaimer.
     12  1.21      tron  *     * Redistributions in binary form must reproduce the above
     13  1.21      tron  *       copyright notice, this list of conditions and the following
     14  1.21      tron  *       disclaimer in the documentation and/or other materials
     15  1.21      tron  *       provided with the distribution.
     16  1.21      tron  *     * Neither the name of the "Oracle America, Inc." nor the names of its
     17  1.21      tron  *       contributors may be used to endorse or promote products derived
     18  1.21      tron  *       from this software without specific prior written permission.
     19   1.1      fvdl  *
     20  1.21      tron  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     21  1.21      tron  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     22  1.21      tron  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
     23  1.21      tron  *   FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
     24  1.21      tron  *   COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
     25  1.21      tron  *   INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     26  1.21      tron  *   DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
     27  1.21      tron  *   GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     28  1.21      tron  *   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     29  1.21      tron  *   WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
     30  1.21      tron  *   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     31  1.21      tron  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     32   1.1      fvdl  */
     33  1.12    itojun 
     34  1.12    itojun #include <sys/cdefs.h>
     35  1.12    itojun #if defined(LIBC_SCCS) && !defined(lint)
     36  1.12    itojun #if 0
     37   1.1      fvdl static        char sccsid[] = "@(#)getnetconfig.c	1.12 91/12/19 SMI";
     38  1.12    itojun #else
     39  1.25  christos __RCSID("$NetBSD: getnetconfig.c,v 1.25 2017/06/30 10:03:34 christos Exp $");
     40  1.12    itojun #endif
     41   1.1      fvdl #endif
     42   1.1      fvdl 
     43   1.1      fvdl /*
     44   1.1      fvdl  * Copyright (c) 1989 by Sun Microsystems, Inc.
     45   1.1      fvdl  */
     46   1.1      fvdl 
     47   1.1      fvdl #include "namespace.h"
     48  1.10   thorpej #include "reentrant.h"
     49   1.1      fvdl #include <stdio.h>
     50   1.4     lukem #include <assert.h>
     51   1.1      fvdl #include <errno.h>
     52   1.1      fvdl #include <netconfig.h>
     53   1.9   thorpej #include <stddef.h>
     54   1.1      fvdl #include <stdlib.h>
     55   1.1      fvdl #include <string.h>
     56   1.3  christos #include <rpc/rpc.h>
     57   1.8      fvdl #include "rpc_internal.h"
     58   1.1      fvdl 
     59   1.1      fvdl #ifdef __weak_alias
     60   1.1      fvdl __weak_alias(getnetconfig,_getnetconfig)
     61   1.1      fvdl __weak_alias(setnetconfig,_setnetconfig)
     62   1.1      fvdl __weak_alias(endnetconfig,_endnetconfig)
     63   1.1      fvdl __weak_alias(getnetconfigent,_getnetconfigent)
     64   1.1      fvdl __weak_alias(freenetconfigent,_freenetconfigent)
     65   1.1      fvdl __weak_alias(nc_perror,_nc_perror)
     66   1.1      fvdl __weak_alias(nc_sperror,_nc_sperror)
     67   1.1      fvdl #endif
     68   1.1      fvdl 
     69   1.1      fvdl /*
     70   1.1      fvdl  * The five library routines in this file provide application access to the
     71   1.1      fvdl  * system network configuration database, /etc/netconfig.  In addition to the
     72   1.1      fvdl  * netconfig database and the routines for accessing it, the environment
     73   1.1      fvdl  * variable NETPATH and its corresponding routines in getnetpath.c may also be
     74   1.1      fvdl  * used to specify the network transport to be used.
     75   1.1      fvdl  */
     76   1.1      fvdl 
     77   1.1      fvdl 
     78   1.1      fvdl /*
     79   1.1      fvdl  * netconfig errors
     80   1.1      fvdl  */
     81   1.1      fvdl 
     82   1.1      fvdl #define NC_NONETCONFIG	ENOENT
     83   1.1      fvdl #define NC_NOMEM	ENOMEM
     84   1.1      fvdl #define NC_NOTINIT	EINVAL	    /* setnetconfig was not called first */
     85   1.1      fvdl #define NC_BADFILE	EBADF	    /* format for netconfig file is bad */
     86   1.1      fvdl 
     87   1.1      fvdl /*
     88   1.1      fvdl  * semantics as strings (should be in netconfig.h)
     89   1.1      fvdl  */
     90   1.1      fvdl #define NC_TPI_CLTS_S	    "tpi_clts"
     91   1.1      fvdl #define	NC_TPI_COTS_S	    "tpi_cots"
     92   1.1      fvdl #define	NC_TPI_COTS_ORD_S   "tpi_cots_ord"
     93   1.1      fvdl #define	NC_TPI_RAW_S        "tpi_raw"
     94   1.1      fvdl 
     95   1.1      fvdl /*
     96   1.1      fvdl  * flags as characters (also should be in netconfig.h)
     97   1.1      fvdl  */
     98   1.1      fvdl #define	NC_NOFLAG_C	'-'
     99   1.1      fvdl #define	NC_VISIBLE_C	'v'
    100   1.1      fvdl #define	NC_BROADCAST_C	'b'
    101   1.1      fvdl 
    102   1.1      fvdl /*
    103   1.1      fvdl  * Character used to indicate there is no name-to-address lookup library
    104   1.1      fvdl  */
    105   1.1      fvdl #define NC_NOLOOKUP	"-"
    106   1.1      fvdl 
    107   1.6  jdolecek static const char * const _nc_errors[] = {
    108   1.5     lukem 	"Netconfig database not found",
    109   1.5     lukem 	"Not enough memory",
    110   1.5     lukem 	"Not initialized",
    111   1.5     lukem 	"Netconfig database has invalid format"
    112   1.1      fvdl };
    113   1.1      fvdl 
    114   1.1      fvdl struct netconfig_info {
    115   1.5     lukem 	int		eof;	/* all entries has been read */
    116   1.5     lukem 	int		ref;	/* # of times setnetconfig() has been called */
    117   1.5     lukem 	struct netconfig_list	*head;	/* head of the list */
    118   1.5     lukem 	struct netconfig_list	*tail;	/* last of the list */
    119   1.1      fvdl };
    120   1.1      fvdl 
    121   1.1      fvdl struct netconfig_list {
    122   1.5     lukem 	char			*linep;	/* hold line read from netconfig */
    123   1.5     lukem 	struct netconfig	*ncp;
    124   1.5     lukem 	struct netconfig_list	*next;
    125   1.1      fvdl };
    126   1.1      fvdl 
    127   1.1      fvdl struct netconfig_vars {
    128   1.5     lukem 	    int   valid;	/* token that indicates valid netconfig_vars */
    129   1.5     lukem 	    int   flag;		/* first time flag */
    130   1.5     lukem 	    struct netconfig_list *nc_configs;
    131   1.5     lukem 	   			 /* pointer to the current netconfig entry */
    132   1.1      fvdl };
    133   1.1      fvdl 
    134   1.1      fvdl #define NC_VALID	0xfeed
    135   1.1      fvdl #define NC_STORAGE	0xf00d
    136   1.1      fvdl #define NC_INVALID	0
    137   1.1      fvdl 
    138   1.1      fvdl 
    139  1.20      matt static int *__nc_error(void);
    140  1.20      matt static int parse_ncp(char *, struct netconfig *);
    141  1.20      matt static struct netconfig *dup_ncp(struct netconfig *);
    142   1.1      fvdl 
    143   1.1      fvdl 
    144   1.1      fvdl static FILE *nc_file;		/* for netconfig db */
    145   1.1      fvdl static struct netconfig_info	ni = { 0, 0, NULL, NULL};
    146   1.1      fvdl 
    147   1.1      fvdl #define MAXNETCONFIGLINE    1000
    148   1.1      fvdl 
    149  1.10   thorpej #ifdef _REENTRANT
    150  1.10   thorpej static thread_key_t nc_key;
    151  1.10   thorpej static once_t nc_once = ONCE_INITIALIZER;
    152  1.10   thorpej 
    153  1.10   thorpej static void
    154  1.10   thorpej __nc_error_setup(void)
    155  1.10   thorpej {
    156  1.10   thorpej 	thr_keycreate(&nc_key, free);
    157  1.10   thorpej }
    158  1.10   thorpej #endif
    159  1.10   thorpej 
    160   1.1      fvdl static int *
    161  1.20      matt __nc_error(void)
    162   1.1      fvdl {
    163  1.10   thorpej #ifdef _REENTRANT
    164   1.1      fvdl 	int *nc_addr = NULL;
    165   1.1      fvdl #endif
    166   1.1      fvdl 	static int nc_error = 0;
    167   1.1      fvdl 
    168  1.10   thorpej #ifdef _REENTRANT
    169  1.10   thorpej 	if (__isthreaded == 0)
    170  1.10   thorpej 		return &nc_error;
    171  1.10   thorpej 	thr_once(&nc_once, __nc_error_setup);
    172  1.10   thorpej 	nc_addr = thr_getspecific(nc_key) ;
    173   1.1      fvdl 	if (nc_addr == NULL) {
    174  1.17  christos 		nc_addr = malloc(sizeof (int));
    175  1.17  christos 		if (nc_addr == NULL)
    176  1.17  christos 			return &nc_error;
    177  1.23  christos 		if (thr_setspecific(nc_key, nc_addr) != 0) {
    178   1.1      fvdl 			if (nc_addr)
    179   1.1      fvdl 				free(nc_addr);
    180   1.1      fvdl 			return &nc_error;
    181   1.1      fvdl 		}
    182   1.1      fvdl 		*nc_addr = 0;
    183   1.1      fvdl 	}
    184   1.1      fvdl 	return nc_addr;
    185   1.1      fvdl #else
    186   1.1      fvdl 	return &nc_error;
    187   1.1      fvdl #endif
    188   1.1      fvdl }
    189   1.1      fvdl 
    190   1.1      fvdl #define nc_error        (*(__nc_error()))
    191   1.1      fvdl /*
    192   1.1      fvdl  * A call to setnetconfig() establishes a /etc/netconfig "session".  A session
    193   1.1      fvdl  * "handle" is returned on a successful call.  At the start of a session (after
    194   1.1      fvdl  * a call to setnetconfig()) searches through the /etc/netconfig database will
    195   1.1      fvdl  * proceed from the start of the file.  The session handle must be passed to
    196   1.1      fvdl  * getnetconfig() to parse the file.  Each call to getnetconfig() using the
    197   1.1      fvdl  * current handle will process one subsequent entry in /etc/netconfig.
    198   1.1      fvdl  * setnetconfig() must be called before the first call to getnetconfig().
    199   1.1      fvdl  * (Handles are used to allow for nested calls to setnetpath()).
    200   1.1      fvdl  *
    201   1.1      fvdl  * A new session is established with each call to setnetconfig(), with a new
    202   1.1      fvdl  * handle being returned on each call.  Previously established sessions remain
    203   1.1      fvdl  * active until endnetconfig() is called with that session's handle as an
    204   1.1      fvdl  * argument.
    205   1.1      fvdl  *
    206   1.1      fvdl  * setnetconfig() need *not* be called before a call to getnetconfigent().
    207   1.1      fvdl  * setnetconfig() returns a NULL pointer on failure (for example, if
    208   1.1      fvdl  * the netconfig database is not present).
    209   1.1      fvdl  */
    210   1.1      fvdl void *
    211  1.20      matt setnetconfig(void)
    212   1.1      fvdl {
    213   1.5     lukem 	struct netconfig_vars *nc_vars;
    214   1.1      fvdl 
    215  1.17  christos 	if ((nc_vars = malloc(sizeof(*nc_vars))) == NULL) {
    216  1.23  christos 		return NULL;
    217   1.5     lukem 	}
    218   1.5     lukem 
    219   1.5     lukem 	/*
    220   1.5     lukem 	 * For multiple calls, i.e. nc_file is not NULL, we just return the
    221   1.5     lukem 	 * handle without reopening the netconfig db.
    222   1.5     lukem 	 */
    223   1.5     lukem 	ni.ref++;
    224  1.19  christos 	if ((nc_file != NULL) || (nc_file = fopen(NETCONFIG, "re")) != NULL) {
    225   1.5     lukem 		nc_vars->valid = NC_VALID;
    226   1.5     lukem 		nc_vars->flag = 0;
    227   1.5     lukem 		nc_vars->nc_configs = ni.head;
    228  1.23  christos 		return nc_vars;
    229   1.5     lukem 	}
    230   1.5     lukem 	ni.ref--;
    231   1.5     lukem 	nc_error = NC_NONETCONFIG;
    232   1.5     lukem 	free(nc_vars);
    233  1.23  christos 	return NULL;
    234   1.1      fvdl }
    235   1.1      fvdl 
    236   1.1      fvdl 
    237   1.1      fvdl /*
    238   1.1      fvdl  * When first called, getnetconfig() returns a pointer to the first entry in
    239   1.1      fvdl  * the netconfig database, formatted as a struct netconfig.  On each subsequent
    240   1.1      fvdl  * call, getnetconfig() returns a pointer to the next entry in the database.
    241   1.1      fvdl  * getnetconfig() can thus be used to search the entire netconfig file.
    242   1.1      fvdl  * getnetconfig() returns NULL at end of file.
    243   1.1      fvdl  */
    244   1.1      fvdl 
    245   1.1      fvdl struct netconfig *
    246  1.20      matt getnetconfig(void *handlep)
    247   1.1      fvdl {
    248  1.23  christos 	struct netconfig_vars *ncp = handlep;
    249   1.5     lukem 	char *stringp;		/* tmp string pointer */
    250   1.5     lukem 	struct netconfig_list	*list;
    251   1.5     lukem 	struct netconfig *np;
    252   1.1      fvdl 
    253   1.1      fvdl 	/*
    254   1.5     lukem 	 * Verify that handle is valid
    255   1.1      fvdl 	 */
    256   1.5     lukem 	if (ncp == NULL || nc_file == NULL) {
    257   1.5     lukem 		nc_error = NC_NOTINIT;
    258  1.23  christos 		return NULL;
    259   1.5     lukem 	}
    260   1.5     lukem 
    261   1.5     lukem 	switch (ncp->valid) {
    262   1.5     lukem 	case NC_VALID:
    263   1.5     lukem 		/*
    264   1.5     lukem 		 * If entry has already been read into the list,
    265   1.5     lukem 		 * we return the entry in the linked list.
    266   1.5     lukem 		 * If this is the first time call, check if there are any
    267   1.5     lukem 		 * entries in linked list.  If no entries, we need to read the
    268   1.5     lukem 		 * netconfig db.
    269   1.5     lukem 		 * If we have been here and the next entry is there, we just
    270   1.5     lukem 		 * return it.
    271   1.5     lukem 		 */
    272   1.5     lukem 		if (ncp->flag == 0) {	/* first time */
    273   1.5     lukem 			ncp->flag = 1;
    274   1.5     lukem 			ncp->nc_configs = ni.head;
    275   1.5     lukem 			if (ncp->nc_configs != NULL) /* entry already exist */
    276  1.23  christos 				return ncp->nc_configs->ncp;
    277   1.5     lukem 		}
    278   1.5     lukem 		else if (ncp->nc_configs != NULL &&
    279   1.5     lukem 		    ncp->nc_configs->next != NULL) {
    280   1.5     lukem 			ncp->nc_configs = ncp->nc_configs->next;
    281  1.23  christos 			return ncp->nc_configs->ncp;
    282   1.5     lukem 		}
    283   1.5     lukem 
    284   1.5     lukem 		/*
    285   1.5     lukem 		 * If we cannot find the entry in the list and is end of file,
    286   1.5     lukem 		 * we give up.
    287   1.5     lukem 		 */
    288   1.5     lukem 		if (ni.eof == 1)
    289  1.23  christos 			return NULL;
    290   1.5     lukem 		break;
    291   1.5     lukem 	default:
    292   1.5     lukem 		nc_error = NC_NOTINIT;
    293  1.23  christos 		return NULL;
    294   1.1      fvdl 	}
    295   1.1      fvdl 
    296  1.17  christos 	stringp = malloc(MAXNETCONFIGLINE);
    297   1.5     lukem 	if (stringp == NULL)
    298  1.23  christos 		return NULL;
    299   1.1      fvdl 
    300   1.1      fvdl #ifdef MEM_CHK
    301   1.5     lukem 	if (malloc_verify() == 0) {
    302   1.5     lukem 		fprintf(stderr, "memory heap corrupted in getnetconfig\n");
    303   1.5     lukem 		exit(1);
    304   1.5     lukem 	}
    305   1.1      fvdl #endif
    306   1.1      fvdl 
    307   1.1      fvdl 	/*
    308   1.5     lukem 	 * Read a line from netconfig file.
    309   1.1      fvdl 	 */
    310   1.5     lukem 	do {
    311   1.5     lukem 		if (fgets(stringp, MAXNETCONFIGLINE, nc_file) == NULL) {
    312   1.5     lukem 			free(stringp);
    313   1.5     lukem 			ni.eof = 1;
    314  1.23  christos 			return NULL;
    315   1.5     lukem 		}
    316   1.5     lukem 	} while (*stringp == '#');
    317   1.5     lukem 
    318  1.17  christos 	list = malloc(sizeof(*list));
    319   1.5     lukem 	if (list == NULL) {
    320   1.5     lukem 		free(stringp);
    321  1.23  christos 		return NULL;
    322   1.5     lukem 	}
    323  1.17  christos 	np = malloc(sizeof(*np));
    324   1.5     lukem 	if (np == NULL) {
    325   1.5     lukem 		free(stringp);
    326   1.5     lukem 		free(list);
    327  1.23  christos 		return NULL;
    328   1.5     lukem 	}
    329   1.5     lukem 	list->ncp = np;
    330   1.5     lukem 	list->next = NULL;
    331   1.5     lukem 	list->ncp->nc_lookups = NULL;
    332   1.5     lukem 	list->linep = stringp;
    333   1.5     lukem 	if (parse_ncp(stringp, list->ncp) == -1) {
    334   1.5     lukem 		free(stringp);
    335   1.5     lukem 		free(np);
    336   1.5     lukem 		free(list);
    337  1.23  christos 		return NULL;
    338   1.5     lukem 	} else {
    339   1.5     lukem 		/*
    340   1.5     lukem 		 * If this is the first entry that's been read, it is the
    341   1.5     lukem 		 * head of the list.  If not, put the entry at the end of
    342   1.5     lukem 		 * the list.  Reposition the current pointer of the handle to
    343   1.5     lukem 		 * the last entry in the list.
    344   1.5     lukem 		 */
    345   1.5     lukem 		if (ni.head == NULL)		/* first entry */
    346   1.5     lukem 			ni.head = ni.tail = list;
    347   1.5     lukem 		else {
    348   1.5     lukem 			ni.tail->next = list;
    349   1.5     lukem 			ni.tail = ni.tail->next;
    350   1.5     lukem 		}
    351   1.5     lukem 		ncp->nc_configs = ni.tail;
    352  1.23  christos 		return ni.tail->ncp;
    353   1.1      fvdl 	}
    354   1.1      fvdl }
    355   1.1      fvdl 
    356   1.1      fvdl /*
    357   1.1      fvdl  * endnetconfig() may be called to "unbind" or "close" the netconfig database
    358   1.1      fvdl  * when processing is complete, releasing resources for reuse.  endnetconfig()
    359   1.1      fvdl  * may not be called before setnetconfig().  endnetconfig() returns 0 on
    360   1.1      fvdl  * success and -1 on failure (for example, if setnetconfig() was not called
    361   1.1      fvdl  * previously).
    362   1.1      fvdl  */
    363   1.1      fvdl int
    364  1.20      matt endnetconfig(void *handlep)
    365   1.1      fvdl {
    366  1.23  christos 	struct netconfig_vars *nc_handlep = handlep;
    367   1.1      fvdl 
    368   1.5     lukem 	struct netconfig_list *q, *p;
    369   1.1      fvdl 
    370   1.5     lukem 	/*
    371   1.5     lukem 	 * Verify that handle is valid
    372   1.5     lukem 	 */
    373   1.5     lukem 	if (nc_handlep == NULL || (nc_handlep->valid != NC_VALID &&
    374   1.1      fvdl 	    nc_handlep->valid != NC_STORAGE)) {
    375   1.5     lukem 		nc_error = NC_NOTINIT;
    376  1.23  christos 		return -1;
    377   1.5     lukem 	}
    378   1.5     lukem 
    379   1.5     lukem 	/*
    380   1.5     lukem 	 * Return 0 if anyone still needs it.
    381   1.5     lukem 	 */
    382   1.5     lukem 	nc_handlep->valid = NC_INVALID;
    383   1.5     lukem 	nc_handlep->flag = 0;
    384   1.5     lukem 	nc_handlep->nc_configs = NULL;
    385   1.5     lukem 	if (--ni.ref > 0) {
    386   1.5     lukem 		free(nc_handlep);
    387  1.23  christos 		return 0;
    388   1.5     lukem 	}
    389   1.5     lukem 
    390   1.5     lukem 	/*
    391   1.5     lukem 	 * Noone needs these entries anymore, then frees them.
    392   1.5     lukem 	 * Make sure all info in netconfig_info structure has been
    393   1.5     lukem 	 * reinitialized.
    394   1.5     lukem 	 */
    395   1.5     lukem 	q = p = ni.head;
    396   1.5     lukem 	ni.eof = ni.ref = 0;
    397   1.5     lukem 	ni.head = NULL;
    398   1.5     lukem 	ni.tail = NULL;
    399   1.5     lukem 	while (q) {
    400   1.5     lukem 		p = q->next;
    401   1.5     lukem 		if (q->ncp->nc_lookups != NULL) free(q->ncp->nc_lookups);
    402   1.5     lukem 		free(q->ncp);
    403   1.5     lukem 		free(q->linep);
    404   1.5     lukem 		free(q);
    405   1.5     lukem 		q = p;
    406   1.5     lukem 	}
    407   1.5     lukem 	free(nc_handlep);
    408   1.5     lukem 
    409   1.5     lukem 	fclose(nc_file);
    410   1.5     lukem 	nc_file = NULL;
    411  1.23  christos 	return 0;
    412   1.1      fvdl }
    413   1.1      fvdl 
    414   1.1      fvdl /*
    415   1.1      fvdl  * getnetconfigent(netid) returns a pointer to the struct netconfig structure
    416   1.1      fvdl  * corresponding to netid.  It returns NULL if netid is invalid (that is, does
    417   1.1      fvdl  * not name an entry in the netconfig database).  It returns NULL and sets
    418   1.1      fvdl  * errno in case of failure (for example, if the netconfig database cannot be
    419   1.1      fvdl  * opened).
    420   1.1      fvdl  */
    421   1.1      fvdl 
    422   1.1      fvdl struct netconfig *
    423  1.20      matt getnetconfigent(const char *netid)
    424   1.1      fvdl {
    425   1.5     lukem 	FILE *file;			/* NETCONFIG db's file pointer */
    426   1.5     lukem 	char *linep;			/* holds current netconfig line */
    427   1.5     lukem 	char *stringp;			/* temporary string pointer */
    428   1.5     lukem 	struct netconfig *ncp = NULL;   /* returned value */
    429   1.5     lukem 	struct netconfig_list *list;	/* pointer to cache list */
    430   1.1      fvdl 
    431   1.5     lukem 	if (netid == NULL || strlen(netid) == 0)
    432  1.23  christos 		return NULL;
    433   1.1      fvdl 
    434   1.5     lukem 	/*
    435   1.5     lukem 	 * Look up table if the entries have already been read and parsed in
    436   1.5     lukem 	 * getnetconfig(), then copy this entry into a buffer and return it.
    437   1.5     lukem 	 * If we cannot find the entry in the current list and there are more
    438   1.5     lukem 	 * entries in the netconfig db that has not been read, we then read the
    439   1.5     lukem 	 * db and try find the match netid.
    440   1.5     lukem 	 * If all the netconfig db has been read and placed into the list and
    441   1.5     lukem 	 * there is no match for the netid, return NULL.
    442   1.5     lukem 	 */
    443   1.5     lukem 	if (ni.head != NULL) {
    444   1.5     lukem 		for (list = ni.head; list; list = list->next) {
    445   1.5     lukem 			if (strcmp(list->ncp->nc_netid, netid) == 0)
    446  1.23  christos 				return dup_ncp(list->ncp);
    447   1.5     lukem 		}
    448   1.5     lukem 		if (ni.eof == 1)	/* that's all the entries */
    449  1.23  christos 			return NULL;
    450   1.1      fvdl 	}
    451   1.1      fvdl 
    452  1.22  christos 	if ((file = fopen(NETCONFIG, "re")) == NULL)
    453  1.23  christos 	    return NULL;
    454   1.1      fvdl 
    455   1.5     lukem 	if ((linep = malloc(MAXNETCONFIGLINE)) == NULL) {
    456   1.5     lukem 		fclose(file);
    457  1.23  christos 		return NULL;
    458   1.5     lukem 	}
    459   1.5     lukem 	do {
    460  1.23  christos 		size_t len;
    461   1.5     lukem 		char *tmpp;	/* tmp string pointer */
    462   1.1      fvdl 
    463   1.5     lukem 		do {
    464   1.5     lukem 			if ((stringp = fgets(linep, MAXNETCONFIGLINE, file))
    465   1.5     lukem 			    == NULL)
    466   1.5     lukem 				break;
    467   1.5     lukem 		} while (*stringp == '#');
    468   1.5     lukem 		if (stringp == NULL)	/* eof */
    469   1.5     lukem 			break;
    470   1.5     lukem 		if ((tmpp = strpbrk(stringp, "\t ")) == NULL) {
    471   1.5     lukem 					/* can't parse file */
    472   1.5     lukem 			nc_error = NC_BADFILE;
    473   1.5     lukem 			break;
    474   1.5     lukem 		}
    475  1.23  christos 		if (strlen(netid) == (len = (size_t)(tmpp - stringp)) &&
    476  1.23  christos 		    strncmp(stringp, netid, len) == 0) {
    477  1.23  christos 		    /* a match */
    478  1.17  christos 			if ((ncp = malloc(sizeof(*ncp))) == NULL)
    479   1.5     lukem 				break;
    480   1.5     lukem 			ncp->nc_lookups = NULL;
    481   1.5     lukem 			if (parse_ncp(linep, ncp) == -1) {
    482   1.5     lukem 				free(ncp);
    483   1.5     lukem 				ncp = NULL;
    484   1.5     lukem 			}
    485   1.5     lukem 			break;
    486   1.5     lukem 		}
    487   1.5     lukem 	} while (stringp != NULL);
    488   1.5     lukem 	if (ncp == NULL)
    489   1.5     lukem 		free(linep);
    490   1.1      fvdl 	fclose(file);
    491  1.23  christos 	return ncp;
    492   1.1      fvdl }
    493   1.1      fvdl 
    494   1.1      fvdl /*
    495   1.1      fvdl  * freenetconfigent(netconfigp) frees the netconfig structure pointed to by
    496   1.1      fvdl  * netconfigp (previously returned by getnetconfigent()).
    497   1.1      fvdl  */
    498   1.1      fvdl 
    499   1.1      fvdl void
    500  1.20      matt freenetconfigent(struct netconfig *netconfigp)
    501   1.1      fvdl {
    502   1.5     lukem 	if (netconfigp != NULL) {
    503   1.5     lukem 				/* holds all netconfigp's strings */
    504   1.5     lukem 		free(netconfigp->nc_netid);
    505   1.5     lukem 		if (netconfigp->nc_lookups != NULL)
    506   1.5     lukem 			free(netconfigp->nc_lookups);
    507   1.5     lukem 		free(netconfigp);
    508   1.5     lukem 	}
    509   1.1      fvdl }
    510   1.1      fvdl 
    511   1.1      fvdl /*
    512   1.1      fvdl  * Parse line and stuff it in a struct netconfig
    513   1.1      fvdl  * Typical line might look like:
    514   1.1      fvdl  *	udp tpi_cots vb inet udp /dev/udp /usr/lib/ip.so,/usr/local/ip.so
    515   1.1      fvdl  *
    516   1.1      fvdl  * We return -1 if any of the tokens don't parse, or malloc fails.
    517   1.1      fvdl  *
    518   1.1      fvdl  * Note that we modify stringp (putting NULLs after tokens) and
    519   1.1      fvdl  * we set the ncp's string field pointers to point to these tokens within
    520   1.1      fvdl  * stringp.
    521   1.1      fvdl  */
    522   1.1      fvdl 
    523   1.1      fvdl static int
    524  1.20      matt parse_ncp(
    525  1.20      matt 	char *stringp,		/* string to parse */
    526  1.20      matt 	struct netconfig *ncp)	/* where to put results */
    527   1.1      fvdl {
    528   1.5     lukem 	char    *tokenp;	/* for processing tokens */
    529   1.5     lukem 	char    *lasts;
    530   1.1      fvdl 
    531   1.5     lukem 	_DIAGASSERT(stringp != NULL);
    532   1.5     lukem 	_DIAGASSERT(ncp != NULL);
    533   1.4     lukem 
    534   1.5     lukem 	nc_error = NC_BADFILE;
    535   1.5     lukem 			/* nearly anything that breaks is for this reason */
    536   1.5     lukem 	stringp[strlen(stringp)-1] = '\0';	/* get rid of newline */
    537   1.5     lukem 	/* netid */
    538   1.5     lukem 	if ((ncp->nc_netid = strtok_r(stringp, "\t ", &lasts)) == NULL)
    539  1.23  christos 		return -1;
    540   1.5     lukem 
    541   1.5     lukem 	/* semantics */
    542   1.5     lukem 	if ((tokenp = strtok_r(NULL, "\t ", &lasts)) == NULL)
    543  1.23  christos 		return -1;
    544   1.5     lukem 	if (strcmp(tokenp, NC_TPI_COTS_ORD_S) == 0)
    545   1.5     lukem 		ncp->nc_semantics = NC_TPI_COTS_ORD;
    546   1.5     lukem 	else if (strcmp(tokenp, NC_TPI_COTS_S) == 0)
    547   1.5     lukem 		ncp->nc_semantics = NC_TPI_COTS;
    548   1.5     lukem 	else if (strcmp(tokenp, NC_TPI_CLTS_S) == 0)
    549   1.5     lukem 		ncp->nc_semantics = NC_TPI_CLTS;
    550   1.5     lukem 	else if (strcmp(tokenp, NC_TPI_RAW_S) == 0)
    551   1.5     lukem 		ncp->nc_semantics = NC_TPI_RAW;
    552   1.5     lukem 	else
    553  1.23  christos 		return -1;
    554   1.5     lukem 
    555   1.5     lukem 	/* flags */
    556   1.5     lukem 	if ((tokenp = strtok_r(NULL, "\t ", &lasts)) == NULL)
    557  1.23  christos 		return -1;
    558   1.5     lukem 	for (ncp->nc_flag = NC_NOFLAG; *tokenp != '\0'; tokenp++) {
    559   1.5     lukem 		switch (*tokenp) {
    560   1.5     lukem 		case NC_NOFLAG_C:
    561   1.5     lukem 			break;
    562   1.5     lukem 		case NC_VISIBLE_C:
    563   1.5     lukem 			ncp->nc_flag |= NC_VISIBLE;
    564   1.5     lukem 			break;
    565   1.5     lukem 		case NC_BROADCAST_C:
    566   1.5     lukem 			ncp->nc_flag |= NC_BROADCAST;
    567   1.5     lukem 			break;
    568   1.5     lukem 		default:
    569  1.23  christos 			return -1;
    570   1.5     lukem 		}
    571   1.1      fvdl 	}
    572   1.5     lukem 	/* protocol family */
    573   1.5     lukem 	if ((ncp->nc_protofmly = strtok_r(NULL, "\t ", &lasts)) == NULL)
    574  1.23  christos 		return -1;
    575   1.5     lukem 	/* protocol name */
    576   1.5     lukem 	if ((ncp->nc_proto = strtok_r(NULL, "\t ", &lasts)) == NULL)
    577  1.23  christos 		return -1;
    578   1.5     lukem 	/* network device */
    579   1.5     lukem 	if ((ncp->nc_device = strtok_r(NULL, "\t ", &lasts)) == NULL)
    580  1.23  christos 		return -1;
    581   1.5     lukem 	if ((tokenp = strtok_r(NULL, "\t ", &lasts)) == NULL)
    582  1.23  christos 		return -1;
    583   1.5     lukem 	if (strcmp(tokenp, NC_NOLOOKUP) == 0) {
    584   1.5     lukem 		ncp->nc_nlookups = 0;
    585   1.5     lukem 		ncp->nc_lookups = NULL;
    586   1.5     lukem 	} else {
    587   1.5     lukem 		char *cp;	    /* tmp string */
    588   1.5     lukem 
    589   1.5     lukem 		if (ncp->nc_lookups != NULL)	/* from last visit */
    590   1.5     lukem 			free(ncp->nc_lookups);
    591   1.5     lukem 		/* preallocate one string pointer */
    592  1.17  christos 		ncp->nc_lookups = malloc(sizeof(*ncp->nc_lookups));
    593   1.5     lukem 		ncp->nc_nlookups = 0;
    594   1.5     lukem 		while ((cp = tokenp) != NULL) {
    595   1.5     lukem 			tokenp = _get_next_token(cp, ',');
    596   1.5     lukem 			ncp->nc_lookups[(size_t)ncp->nc_nlookups++] = cp;
    597   1.5     lukem 			ncp->nc_lookups = (char **)
    598   1.5     lukem 			    realloc(ncp->nc_lookups,
    599   1.5     lukem 			    (size_t)(ncp->nc_nlookups+1) *sizeof(char *));
    600   1.5     lukem 						/* for next loop */
    601   1.5     lukem 		}
    602   1.1      fvdl 	}
    603  1.23  christos 	return 0;
    604   1.1      fvdl }
    605   1.1      fvdl 
    606   1.1      fvdl /*
    607   1.1      fvdl  * Returns a string describing the reason for failure.
    608   1.1      fvdl  */
    609   1.1      fvdl char *
    610  1.20      matt nc_sperror(void)
    611   1.1      fvdl {
    612   1.6  jdolecek 	const char *message;
    613   1.1      fvdl 
    614   1.5     lukem 	switch(nc_error) {
    615   1.5     lukem 	case NC_NONETCONFIG:
    616   1.5     lukem 		message = _nc_errors[0];
    617   1.5     lukem 		break;
    618   1.5     lukem 	case NC_NOMEM:
    619   1.5     lukem 		message = _nc_errors[1];
    620   1.5     lukem 		break;
    621   1.5     lukem 	case NC_NOTINIT:
    622   1.5     lukem 		message = _nc_errors[2];
    623   1.5     lukem 		break;
    624   1.5     lukem 	case NC_BADFILE:
    625   1.5     lukem 		message = _nc_errors[3];
    626   1.5     lukem 		break;
    627   1.5     lukem 	default:
    628   1.5     lukem 		message = "Unknown network selection error";
    629   1.5     lukem 	}
    630  1.14  christos 	return __UNCONST(message);
    631   1.1      fvdl }
    632   1.1      fvdl 
    633   1.1      fvdl /*
    634   1.1      fvdl  * Prints a message onto standard error describing the reason for failure.
    635   1.1      fvdl  */
    636   1.1      fvdl void
    637  1.20      matt nc_perror(const char *s)
    638   1.1      fvdl {
    639   1.4     lukem 
    640   1.5     lukem 	_DIAGASSERT(s != NULL);
    641   1.4     lukem 
    642   1.5     lukem 	fprintf(stderr, "%s: %s", s, nc_sperror());
    643   1.1      fvdl }
    644   1.1      fvdl 
    645   1.1      fvdl /*
    646   1.1      fvdl  * Duplicates the matched netconfig buffer.
    647   1.1      fvdl  */
    648   1.1      fvdl static struct netconfig *
    649  1.20      matt dup_ncp(struct netconfig *ncp)
    650   1.1      fvdl {
    651   1.5     lukem 	struct netconfig	*p;
    652  1.25  christos 	char	*tmp;
    653   1.9   thorpej 	u_int	i;
    654   1.5     lukem 
    655   1.5     lukem 	_DIAGASSERT(ncp != NULL);
    656   1.5     lukem 
    657  1.25  christos 	if ((tmp = malloc(MAXNETCONFIGLINE)) == NULL)
    658  1.23  christos 		return NULL;
    659  1.17  christos 	if ((p = malloc(sizeof(*p))) == NULL) {
    660   1.5     lukem 		free(tmp);
    661  1.23  christos 		return NULL;
    662   1.5     lukem 	}
    663   1.5     lukem 	/*
    664   1.5     lukem 	 * First we dup all the data from matched netconfig buffer.  Then we
    665   1.5     lukem 	 * adjust some of the member pointer to a pre-allocated buffer where
    666   1.5     lukem 	 * contains part of the data.
    667   1.5     lukem 	 * To follow the convention used in parse_ncp(), we store all the
    668   1.7       wiz 	 * necessary information in the pre-allocated buffer and let each
    669   1.5     lukem 	 * of the netconfig char pointer member point to the right address
    670   1.5     lukem 	 * in the buffer.
    671   1.5     lukem 	 */
    672   1.5     lukem 	*p = *ncp;
    673  1.23  christos 	p->nc_netid = strcpy(tmp, ncp->nc_netid);
    674  1.11       scw 	tmp = strchr(tmp, '\0') + 1;
    675  1.23  christos 	p->nc_protofmly = strcpy(tmp, ncp->nc_protofmly);
    676  1.11       scw 	tmp = strchr(tmp, '\0') + 1;
    677  1.23  christos 	p->nc_proto = strcpy(tmp, ncp->nc_proto);
    678  1.11       scw 	tmp = strchr(tmp, '\0') + 1;
    679  1.23  christos 	p->nc_device = strcpy(tmp, ncp->nc_device);
    680  1.23  christos 	p->nc_lookups = calloc((size_t)(p->nc_nlookups + 1), sizeof(char *));
    681   1.5     lukem 	if (p->nc_lookups == NULL) {
    682   1.5     lukem 		free(p->nc_netid);
    683  1.15  christos 		free(p);
    684  1.23  christos 		return NULL;
    685   1.5     lukem 	}
    686  1.23  christos 	for (i = 0; i < p->nc_nlookups; i++) {
    687  1.11       scw 		tmp = strchr(tmp, '\0') + 1;
    688  1.23  christos 		p->nc_lookups[i] = strcpy(tmp, ncp->nc_lookups[i]);
    689   1.5     lukem 	}
    690  1.23  christos 	return p;
    691   1.1      fvdl }
    692