Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 27 Sep 2012 13:20:06 GMT
From:      Andrey Simonenko <simon@comsys.ntu-kpi.kiev.ua>
To:        freebsd-bugs@FreeBSD.org
Subject:   bin/165710: RPC: getnetconfig() and other netconfig's functions correct implementation.
Message-ID:  <201209271320.q8RDK68K023792@freefall.freebsd.org>

next in thread | raw e-mail | index | archive | help
The following reply was made to PR kern/165710; it has been noted by GNATS.

From: Andrey Simonenko <simon@comsys.ntu-kpi.kiev.ua>
To: bug-followup@FreeBSD.org
Cc:  
Subject: bin/165710: RPC: getnetconfig() and other netconfig's functions
 correct implementation.
Date: Thu, 27 Sep 2012 16:11:14 +0300

 Some unnecessary macro variables were removed, check for the return code
 from fclose() was added.
 
 diff -ruNp libc.orig/include/reentrant.h libc/include/reentrant.h
 --- libc.orig/include/reentrant.h	2010-03-12 14:56:49.000000000 +0200
 +++ libc/include/reentrant.h	2012-09-27 13:39:20.000000000 +0300
 @@ -95,27 +95,19 @@
  #define ONCE_INITIALIZER	PTHREAD_ONCE_INIT
  
  #define mutex_init(m, a)	_pthread_mutex_init(m, a)
 -#define mutex_lock(m)		if (__isthreaded) \
 -				_pthread_mutex_lock(m)
 -#define mutex_unlock(m)		if (__isthreaded) \
 -				_pthread_mutex_unlock(m)
 -#define mutex_trylock(m)	(__isthreaded ? 0 : _pthread_mutex_trylock(m))
 +#define mutex_lock(m)		(__isthreaded ? _pthread_mutex_lock(m) : 0)
 +#define mutex_unlock(m)		(__isthreaded ? _pthread_mutex_unlock(m) : 0)
 +#define mutex_trylock(m)	(__isthreaded ? _pthread_mutex_trylock(m) : 0)
  
  #define cond_init(c, a, p)	_pthread_cond_init(c, a)
 -#define cond_signal(m)		if (__isthreaded) \
 -				_pthread_cond_signal(m)
 -#define cond_broadcast(m)	if (__isthreaded) \
 -				_pthread_cond_broadcast(m)
 -#define cond_wait(c, m)		if (__isthreaded) \
 -				_pthread_cond_wait(c, m)
 +#define cond_signal(m)		(__isthreaded ? _pthread_cond_signal(m) : 0)
 +#define cond_broadcast(m)	(__isthreaded ? _pthread_cond_broadcast(m) : 0)
 +#define cond_wait(c, m)		(__isthreaded ? _pthread_cond_wait(c, m) : 0)
  
  #define rwlock_init(l, a)	_pthread_rwlock_init(l, a)
 -#define rwlock_rdlock(l)	if (__isthreaded) \
 -				_pthread_rwlock_rdlock(l)
 -#define rwlock_wrlock(l)	if (__isthreaded) \
 -				_pthread_rwlock_wrlock(l)
 -#define rwlock_unlock(l)	if (__isthreaded) \
 -				_pthread_rwlock_unlock(l)
 +#define rwlock_rdlock(l)	(__isthreaded ? _pthread_rwlock_rdlock(l) : 0)
 +#define rwlock_wrlock(l)	(__isthreaded ? _pthread_rwlock_wrlock(l) : 0)
 +#define rwlock_unlock(l)	(__isthreaded ? _pthread_rwlock_unlock(l) : 0)
  
  #define thr_keycreate(k, d)	_pthread_key_create(k, d)
  #define thr_setspecific(k, p)	_pthread_setspecific(k, p)
 diff -ruNp libc.orig/rpc/Makefile.inc libc/rpc/Makefile.inc
 --- libc.orig/rpc/Makefile.inc	2012-02-08 11:58:52.000000000 +0200
 +++ libc/rpc/Makefile.inc	2012-09-27 13:39:20.000000000 +0300
 @@ -4,7 +4,7 @@
  .PATH: ${.CURDIR}/rpc ${.CURDIR}/.
  SRCS+=	auth_none.c auth_unix.c authunix_prot.c bindresvport.c clnt_bcast.c \
  	clnt_dg.c clnt_generic.c clnt_perror.c clnt_raw.c clnt_simple.c \
 -	clnt_vc.c rpc_dtablesize.c getnetconfig.c getnetpath.c getrpcent.c \
 +	clnt_vc.c rpc_dtablesize.c netconfig.c getrpcent.c \
  	getrpcport.c mt_misc.c pmap_clnt.c pmap_getmaps.c pmap_getport.c \
  	pmap_prot.c pmap_prot2.c pmap_rmt.c rpc_prot.c rpc_commondata.c \
  	rpc_callmsg.c rpc_generic.c rpc_soc.c rpcb_clnt.c rpcb_prot.c \
 diff -ruNp libc.orig/rpc/getnetconfig.3 libc/rpc/getnetconfig.3
 --- libc.orig/rpc/getnetconfig.3	2002-12-19 11:40:23.000000000 +0200
 +++ libc/rpc/getnetconfig.3	2012-09-27 13:39:20.000000000 +0300
 @@ -169,12 +169,7 @@ returns a unique handle to be used by
  In the case of an error,
  .Fn setnetconfig
  returns
 -.Dv NULL
 -and
 -.Fn nc_perror
 -or
 -.Fn nc_sperror
 -can be used to print the reason for failure.
 +.Dv NULL .
  .Pp
  The
  .Fn getnetconfig
 diff -ruNp libc.orig/rpc/getnetpath.3 libc/rpc/getnetpath.3
 --- libc.orig/rpc/getnetpath.3	2002-12-18 14:45:10.000000000 +0200
 +++ libc/rpc/getnetpath.3	2012-09-27 13:39:20.000000000 +0300
 @@ -40,7 +40,10 @@ for other routines that also access the
  network configuration database directly.
  The
  .Ev NETPATH
 -variable is a list of colon-separated network identifiers.
 +variable is a list of colon-separated network identifiers,
 +any character in a network identifier can be escaped by the
 +.Ql \e
 +character.
  .Pp
  The
  .Fn getnetpath
 @@ -103,14 +106,12 @@ variable is unset,
  .Fn getnetpath
  behaves as if
  .Ev NETPATH
 -were set to the sequence of
 +was set to the sequence of
  .Dq default
  or
  .Dq visible
  networks in the netconfig database, in the
  order in which they are listed.
 -.\"This proviso holds also for this
 -.\"whole manpage.
  .Pp
  The
  .Fn endnetpath
 @@ -143,14 +144,6 @@ returns 0 on success and \-1 on failure
  (for example, if
  .Fn setnetpath
  was not called previously).
 -The
 -.Fn nc_perror
 -or
 -.Fn nc_sperror
 -function
 -can be used to print out the reason for failure.
 -See
 -.Xr getnetconfig 3 .
  .Pp
  When first called,
  .Fn getnetpath
 @@ -164,6 +157,14 @@ has been exhausted,
  .Fn getnetpath
  returns
  .Dv NULL .
 +.Pp
 +If any of these functions failed, then the
 +.Fn nc_perror
 +and
 +.Fn nc_sperror
 +functions can be used to print out the reason for failure.
 +See
 +.Xr getnetconfig 3 .
  .Sh SEE ALSO
  .Xr getnetconfig 3 ,
  .Xr netconfig 5 ,
 diff -ruNp libc.orig/rpc/netconfig.c libc/rpc/netconfig.c
 --- libc.orig/rpc/netconfig.c	1970-01-01 03:00:00.000000000 +0300
 +++ libc/rpc/netconfig.c	2012-09-27 03:39:48.000000000 +0300
 @@ -0,0 +1,722 @@
 +/*-
 + * Copyright (c) 2012 Andrey Simonenko
 + * All rights reserved.
 + *
 + * Redistribution and use in source and binary forms, with or without
 + * modification, are permitted provided that the following conditions
 + * are met:
 + * 1. Redistributions of source code must retain the above copyright
 + *    notice, this list of conditions and the following disclaimer.
 + * 2. Redistributions in binary form must reproduce the above copyright
 + *    notice, this list of conditions and the following disclaimer in the
 + *    documentation and/or other materials provided with the distribution.
 + *
 + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 + * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 + * SUCH DAMAGE.
 + */
 +
 +#include <sys/cdefs.h>
 +__FBSDID("$FreeBSD$");
 +
 +#include <sys/queue.h>
 +#include <sys/types.h>
 +
 +#include "namespace.h"
 +#include "reentrant.h"
 +#include <netconfig.h>
 +#include <stdbool.h>
 +#include <stdio.h>
 +#include <stdlib.h>
 +#include <string.h>
 +#include "un-namespace.h"
 +
 +/*
 + * Table of semantics.
 + */
 +static const struct {
 +	const char	*name;
 +	u_long		code;
 +} nc_semantics_tbl[] = {
 +	{ .name = "tpi_cots_ord",	.code = NC_TPI_COTS_ORD	},
 +	{ .name = "tpi_clts",		.code = NC_TPI_CLTS	},
 +	{ .name = "tpi_raw",		.code = NC_TPI_RAW	},
 +	{ .name = "tpi_cots",		.code = NC_TPI_COTS	}
 +};
 +
 +#define NC_SEMANTICS_TBL_SIZE \
 +	(sizeof(nc_semantics_tbl) / sizeof(nc_semantics_tbl[0]))
 +
 +/*
 + * Errors codes.
 + */
 +#define NC_NOERROR	0
 +#define NC_EFILE	1
 +#define NC_ENOMEM	2
 +#define NC_EINIT	3
 +#define NC_EFORMAT	4
 +#define NC_ELBIG	5
 +#define NC_ENOENT	6
 +#define NC_EEOF		7
 +#define NC_EIO		8
 +
 +static const char *const nc_errlist[] = {
 +	[NC_NOERROR]		= "No error",
 +	[NC_EFILE]		= "Netconfig database cannot be opened",
 +	[NC_ENOMEM]		= "Not enough memory",
 +	[NC_EINIT]		= "Netconfig database was not initialized",
 +	[NC_EFORMAT]		= "Netconfig database has wrong format",
 +	[NC_ELBIG]		= "Line in netconfig database is too large",
 +	[NC_ENOENT]		= "Netid not found in netconfig database",
 +	[NC_EEOF]		= "Reached end of netconfig database",
 +	[NC_EIO]		= "Netconfig database input/output error"
 +};
 +
 +/*
 + * One entry from the NETCONFIG database.
 + */
 +struct nc_entry {
 +	STAILQ_ENTRY(nc_entry) link;	/* For list building.		*/
 +	struct netconfig nc;		/* One entry data.		*/
 +};
 +
 +/*
 + * Handle for the getnetconfig() and endnetconfig() functions.
 + */
 +struct nc_handle {
 +	u_int		error;		/* Current state of session.	*/
 +	struct nc_entry	*nc_entry;	/* Current entry in session.	*/
 +};
 +
 +/*
 + * Handle for the getnetpath() and endnetpath() functions.
 + */
 +struct np_handle {
 +	void		*nc_handle;	/* Open nc_handle.		*/
 +	char		*np_cur;	/* Current list in np_env.	*/
 +	char		*np_env;	/* Copy of NETPATH variable.	*/
 +};
 +
 +/*
 + * This mutex synchronizes access to all np_handles that were created
 + * when the NETPATH environment variable was defined.
 + */
 +static mutex_t np_handle_lock = MUTEX_INITIALIZER;
 +
 +/*
 + * The NETCONFIG database file.
 + */
 +static FILE *nc_file;
 +
 +/*
 + * Cache of already read entries from the NETCONFIG database.
 + */
 +static struct {
 +	STAILQ_HEAD(, nc_entry) list;	/* List of cached entries.	*/
 +	u_int		error;		/* Current state of cache data.	*/
 +	u_int		ref;		/* Number of references.	*/
 +} nc_cache = {
 +	.list	= STAILQ_HEAD_INITIALIZER(nc_cache.list),
 +	.error	= NC_EINIT,
 +	.ref	= 0
 +};
 +
 +/*
 + * This mutex synchronizes access to nc_cache, nc_file and all nc_handles.
 + */
 +static mutex_t nc_cache_lock = MUTEX_INITIALIZER;
 +
 +static thread_key_t nc_key;
 +static once_t nc_once = ONCE_INITIALIZER;
 +static int nc_key_error;
 +
 +/*
 + * Maximum allowed line length in the NETCONFIG database.
 + */
 +#define NC_LINE_MAX	1024
 +
 +/*
 + * Rules of memory allocation for (char *) fields in struct netconfig{}:
 + *   - memory for all strings is allocated in one block;
 + *   - address of allocated block is saved in the nc_netid field;
 + *   - other (char *) fields point to appropriate positions in this block;
 + *   - end of each string (data) is NUL terminated.
 + */
 +
 +static void
 +nc_key_init(void)
 +{
 +	nc_key_error = thr_keycreate(&nc_key, free);
 +}
 +
 +static u_int *
 +__nc_error(void)
 +{
 +	static u_int nc_error = NC_NOERROR;
 +
 +	u_int *value;
 +
 +	if (thr_main())
 +		goto one_value;
 +	if (thr_once(&nc_once, nc_key_init) != 0 || nc_key_error != 0)
 +		goto one_value;
 +	value = thr_getspecific(nc_key);
 +	if (value == NULL) {
 +		value = malloc(sizeof(*value));
 +		if (value == NULL)
 +			goto one_value;
 +		if (thr_setspecific(nc_key, value) != 0) {
 +			free(value);
 +			goto one_value;
 +		}
 +		*value = NC_NOERROR;
 +	}
 +	return (value);
 +
 +one_value:
 +	return (&nc_error);
 +}
 +
 +#define nc_error	(*__nc_error())
 +
 +/*
 + * Rewind NETCONFIG database session.
 + */
 +static __inline void
 +nc_session_rewind(struct nc_handle *nc_handle)
 +{
 +	nc_handle->error = NC_NOERROR;
 +	nc_handle->nc_entry = NULL;
 +}
 +
 +/*
 + * Return address of the first non white space character in the given string.
 + */
 +static char *
 +nc_skip_spaces(char *str)
 +{
 +	for (;; ++str)
 +		if (*str != ' ' && *str != '\t')
 +			break;
 +	return (str);
 +}
 +
 +/*
 + * Select next field from the line.  On enter *begp is a start for search.
 + * On exit *begp is the next after the next character after a new field
 + * if EOL is not reached, else *begp will point to the NUL character right
 + * after selected field.  The address of successfully selected field (which
 + * is finished by a NUL character) is saved in *fieldp.
 + */
 +static int
 +nc_select_field(char **begp, char **fieldp)
 +{
 +	char *beg, *ptr;
 +
 +	beg = nc_skip_spaces(*begp);
 +	for (ptr = beg;; ++ptr) {
 +		if (*ptr == ' ' || *ptr == '\t') {
 +			*ptr = '\0';
 +			if (*(ptr + 1) != '\0')
 +				++ptr;
 +			break;
 +		}
 +		if (*ptr == '\0')
 +			break;
 +	}
 +	if (ptr == beg)
 +		return (-1);
 +	*begp = ptr;
 +	*fieldp = beg;
 +	return (0);
 +}
 +
 +/*
 + * This function NUL terminates the first token from the given string,
 + * the end of the token is marked by the given delimiter.  Return value
 + * is the address of the rest of the string or NULL if there is no more
 + * tokens.  Any character can be represented by \-sequence.  On return
 + * str will point to just selected token.  Selected token can be empty
 + * string, so this case must be checked in the calling function.
 + */
 +static char *
 +nc_next_token(char *str, char delim)
 +{
 +	char *p, *q;
 +	bool esc;
 +
 +	for (p = q = str, esc = false;; ++p) {
 +		if (esc)
 +			esc = false;
 +		else if (*p == '\\') {
 +			esc = true;
 +			continue;
 +		} else if (*p == delim) {
 +			*p++ = *q = '\0';
 +			break;
 +		}
 +		*q = *p;
 +		if (*p == '\0')
 +			break;
 +		++q;
 +	}
 +	return (*p != '\0' ? p : NULL);
 +}
 +
 +/*
 + * Parse the given line with the given length according to the netconfig(5)
 + * format.  The given line is started with some non-space data, does not have
 + * new-line character at the end.
 + */
 +static int
 +nc_parse(char *line, size_t len, struct netconfig *nc)
 +{
 +	char **nc_lookups;
 +	char *s, *buf, *str, *token;
 +	u_int i;
 +
 +	buf = str = malloc(len + 1);
 +	if (buf == NULL) {
 +		nc_error = NC_ENOMEM;
 +		return (-1);
 +	}
 +	memcpy(buf, line, len + 1);
 +
 +	if (nc_select_field(&str, &nc->nc_netid) < 0)
 +		goto failed_format;
 +
 +	if (nc_select_field(&str, &token) < 0)
 +		goto failed_format;
 +	for (i = 0; i < NC_SEMANTICS_TBL_SIZE; ++i)
 +		if (strcmp(token, nc_semantics_tbl[i].name) == 0) {
 +			nc->nc_semantics = nc_semantics_tbl[i].code;
 +			break;
 +		}
 +	if (i == NC_SEMANTICS_TBL_SIZE)
 +		goto failed_format;
 +
 +	if (nc_select_field(&str, &token) < 0)
 +		goto failed_format;
 +	nc->nc_flag = NC_NOFLAG;
 +	if (token[0] == '-') {
 +		if (token[1] != '\0')
 +			goto failed_format;
 +	} else {
 +		do {
 +			switch (*token) {
 +			case 'v':
 +				nc->nc_flag |= NC_VISIBLE;
 +				break;
 +			case 'b':
 +				nc->nc_flag |= NC_BROADCAST;
 +				break;
 +			default:
 +				goto failed_format;
 +			}
 +		} while (*++token != '\0');
 +	}
 +
 +	if (nc_select_field(&str, &nc->nc_protofmly) < 0)
 +		goto failed_format;
 +
 +	if (nc_select_field(&str, &nc->nc_proto) < 0)
 +		goto failed_format;
 +
 +	if (nc_select_field(&str, &nc->nc_device) < 0)
 +		goto failed_format;
 +
 +	if (nc_select_field(&str, &token) < 0)
 +		goto failed_format;
 +	nc->nc_nlookups = 0;
 +	nc->nc_lookups = NULL;
 +	if (token[0] == '-') {
 +		if (token[1] != '\0')
 +			goto failed_format;
 +	} else {
 +		while ((s = token) != NULL) {
 +			token = nc_next_token(s, ',');
 +			if (*s != '\0') {
 +				nc->nc_nlookups++;
 +				nc_lookups = realloc(nc->nc_lookups,
 +				    nc->nc_nlookups * sizeof(*nc->nc_lookups));
 +				if (nc_lookups == NULL) {
 +					free(nc->nc_lookups);
 +					nc_error = NC_ENOMEM;
 +					goto failed;
 +				}
 +				nc->nc_lookups = nc_lookups;
 +				nc->nc_lookups[nc->nc_nlookups - 1] = s;
 +			}
 +		}
 +	}
 +
 +	if (*str != '\0') {
 +		free(nc->nc_lookups);
 +		goto failed_format;
 +	}
 +	return (0);
 +
 +failed_format:
 +	nc_error = NC_EFORMAT;
 +failed:
 +	free(buf);
 +	return (-1);
 +}
 +
 +/*
 + * Duplicate the given netconfig structure.
 + */
 +static struct netconfig *
 +nc_dup(const struct netconfig *nc_src)
 +{
 +	struct netconfig *nc_dst;
 +	size_t line_size;
 +	u_long i;
 +
 +	nc_dst = malloc(sizeof(*nc_dst));
 +	if (nc_dst == NULL)
 +		goto failed;
 +	if (nc_src->nc_nlookups != 0) {
 +		i = nc_src->nc_nlookups - 1;
 +		line_size = nc_src->nc_lookups[i] +
 +		    strlen(nc_src->nc_lookups[i]) - nc_src->nc_netid;
 +	} else
 +		line_size = nc_src->nc_device +
 +		    strlen(nc_src->nc_device) - nc_src->nc_netid;
 +	++line_size;
 +
 +	nc_dst->nc_netid = malloc(line_size);
 +	if (nc_dst->nc_netid == NULL)
 +		goto failed;
 +	memcpy(nc_dst->nc_netid, nc_src->nc_netid, line_size);
 +
 +	nc_dst->nc_nlookups = nc_src->nc_nlookups;
 +	if (nc_dst->nc_nlookups != 0) {
 +		nc_dst->nc_lookups = malloc(nc_dst->nc_nlookups *
 +		    sizeof(*nc_dst->nc_lookups));
 +		if (nc_dst->nc_lookups == NULL) {
 +			free(nc_dst->nc_netid);
 +			goto failed;
 +		}
 +		for (i = 0; i < nc_dst->nc_nlookups; i++)
 +			nc_dst->nc_lookups[i] = nc_dst->nc_netid +
 +			    (nc_src->nc_lookups[i] - nc_src->nc_netid);
 +	} else
 +		nc_dst->nc_lookups = NULL;
 +
 +	nc_dst->nc_semantics = nc_src->nc_semantics;
 +	nc_dst->nc_flag = nc_src->nc_flag;
 +	nc_dst->nc_protofmly = nc_dst->nc_netid +
 +	    (nc_src->nc_protofmly - nc_src->nc_netid);
 +	nc_dst->nc_proto = nc_dst->nc_netid +
 +	    (nc_src->nc_proto - nc_src->nc_netid);
 +	nc_dst->nc_device = nc_dst->nc_netid +
 +	    (nc_src->nc_device - nc_src->nc_netid);
 +
 +	return (nc_dst);
 +
 +failed:
 +	nc_error = NC_ENOMEM;
 +	free(nc_dst);
 +	return (NULL);
 +}
 +
 +void *
 +setnetconfig(void)
 +{
 +	struct nc_handle *nc_handle;
 +
 +	nc_handle = malloc(sizeof(*nc_handle));
 +	if (nc_handle == NULL) {
 +		nc_error = NC_ENOMEM;
 +		return (NULL);
 +	}
 +
 +	mutex_lock(&nc_cache_lock);
 +	if (nc_cache.error == NC_EINIT) {
 +		nc_file = fopen(NETCONFIG, "r");
 +		if (nc_file == NULL) {
 +			nc_error = NC_EFILE;
 +			mutex_unlock(&nc_cache_lock);
 +			free(nc_handle);
 +			return (NULL);
 +		}
 +		nc_cache.error = NC_NOERROR;
 +	}
 +	nc_cache.ref++;
 +	mutex_unlock(&nc_cache_lock);
 +
 +	nc_session_rewind(nc_handle);
 +	return (nc_handle);
 +}
 +
 +struct netconfig *
 +getnetconfig(void *handle)
 +{
 +	struct nc_handle *nc_handle;
 +	struct nc_entry *nc_entry;
 +	char *line, *line_data;
 +	size_t line_len;
 +
 +	if (handle == NULL) {
 +		nc_error = NC_EINIT;
 +		return (NULL);
 +	}
 +	nc_handle = handle;
 +
 +	mutex_lock(&nc_cache_lock);
 +
 +	if (nc_handle->error != NC_NOERROR) {
 +		nc_error = nc_handle->error;
 +		mutex_unlock(&nc_cache_lock);
 +		return (NULL);
 +	}
 +
 +	nc_entry = nc_handle->nc_entry == NULL ?
 +	    STAILQ_FIRST(&nc_cache.list) :
 +	    STAILQ_NEXT(nc_handle->nc_entry, link);
 +	if (nc_entry != NULL)
 +		goto done;
 +
 +	if (nc_cache.error != NC_NOERROR) {
 +		nc_error = nc_handle->error = nc_cache.error;
 +		goto done;
 +	}
 +
 +	line = malloc(NC_LINE_MAX);
 +	nc_entry = malloc(sizeof(*nc_entry));
 +	if (line == NULL || nc_entry == NULL) {
 +		nc_error = NC_ENOMEM;
 +		goto failed;
 +	}
 +
 +	do {
 +		if (fgets(line, NC_LINE_MAX, nc_file) == NULL) {
 +			nc_error = feof(nc_file) ? NC_EEOF : NC_EIO;
 +			goto failed;
 +		}
 +		line_len = strlen(line);
 +		if (line[line_len - 1] != '\n' && !feof(nc_file)) {
 +			nc_error = NC_ELBIG;
 +			goto failed;
 +		}
 +		if (line[line_len - 1] == '\n') {
 +			--line_len;
 +			line[line_len] = '\0';
 +		}
 +		line_data = nc_skip_spaces(line);
 +		line_len -= line_data - line;
 +	} while (*line_data == '#' || *line_data == '\0');
 +
 +	if (nc_parse(line_data, line_len, &nc_entry->nc) < 0)
 +		goto failed;
 +
 +	STAILQ_INSERT_TAIL(&nc_cache.list, nc_entry, link);
 +	free(line);
 +done:
 +	nc_handle->nc_entry = nc_entry;
 +	mutex_unlock(&nc_cache_lock);
 +	return (nc_entry != NULL ? &nc_entry->nc : NULL);
 +
 +failed:
 +	(void)fclose(nc_file);
 +	nc_file = NULL;
 +	nc_cache.error = nc_handle->error = nc_error;
 +	mutex_unlock(&nc_cache_lock);
 +	free(line);
 +	free(nc_entry);
 +	return (NULL);
 +}
 +
 +void
 +freenetconfigent(struct netconfig *nc)
 +{
 +	if (nc != NULL) {
 +		free(nc->nc_netid);
 +		free(nc->nc_lookups);
 +		free(nc);
 +	}
 +}
 +
 +int
 +endnetconfig(void *handle)
 +{
 +	struct nc_entry *nc_entry, *nc_entry_next;
 +	int rv;
 +
 +	if (handle == NULL) {
 +		nc_error = NC_EINIT;
 +		return (-1);
 +	}
 +	free(handle);
 +
 +	rv = 0;
 +	mutex_lock(&nc_cache_lock);
 +	if (--nc_cache.ref == 0) {
 +		nc_entry = STAILQ_FIRST(&nc_cache.list);
 +		STAILQ_INIT(&nc_cache.list);
 +		nc_cache.error = NC_EINIT;
 +		if (nc_file != NULL) {
 +			if (fclose(nc_file) != 0) {
 +				nc_error = NC_EIO;
 +				rv = -1;
 +			}
 +			nc_file = NULL;
 +		}
 +	} else
 +		nc_entry = NULL;
 +	mutex_unlock(&nc_cache_lock);
 +
 +	for (; nc_entry != NULL; nc_entry = nc_entry_next) {
 +		nc_entry_next = STAILQ_NEXT(nc_entry, link);
 +		free(nc_entry->nc.nc_netid);
 +		free(nc_entry->nc.nc_lookups);
 +		free(nc_entry);
 +	}
 +
 +	return (rv);
 +}
 +
 +struct netconfig *
 +getnetconfigent(const char *netid)
 +{
 +	struct netconfig *nc;
 +	void *handle;
 +
 +	if (netid == NULL) {
 +		nc_error = NC_ENOENT;
 +		return (NULL);
 +	}
 +
 +	handle = setnetconfig();
 +	if (handle == NULL)
 +		return (NULL);
 +
 +	while ((nc = getnetconfig(handle)) != NULL)
 +		if (strcmp(nc->nc_netid, netid) == 0) {
 +			nc = nc_dup(nc);
 +			break;
 +		}
 +	if (nc == NULL && nc_error == NC_EEOF)
 +		nc_error = NC_ENOENT;
 +
 +	if (endnetconfig(handle) < 0) {
 +		freenetconfigent(nc);
 +		nc = NULL;
 +	}
 +
 +	return (nc);
 +}
 +
 +char *
 +nc_sperror(void)
 +{
 +	return ((char *)nc_errlist[nc_error]);
 +}
 +
 +void
 +nc_perror(const char *s)
 +{
 +	fprintf(stderr, "%s: %s\n", s, nc_sperror());
 +}
 +
 +void *
 +setnetpath(void)
 +{
 +	const char *env;
 +	struct np_handle *np_handle;
 +
 +	np_handle = malloc(sizeof(*np_handle));
 +	if (np_handle == NULL) {
 +		nc_error = NC_ENOMEM;
 +		return (NULL);
 +	}
 +
 +	env = getenv(NETPATH);
 +	if (env != NULL) {
 +		np_handle->np_env = strdup(env);
 +		if (np_handle->np_env == NULL) {
 +			nc_error = NC_ENOMEM;
 +			goto failed;
 +		}
 +	} else
 +		np_handle->np_env = NULL;
 +	np_handle->np_cur = np_handle->np_env;
 +
 +	np_handle->nc_handle = setnetconfig();
 +	if (np_handle->nc_handle == NULL)
 +		goto failed;
 +
 +	return (np_handle);
 +
 +failed:
 +	free(np_handle);
 +	return (NULL);
 +}
 +
 +struct netconfig *
 +getnetpath(void *handle)
 +{
 +	struct np_handle *np_handle;
 +	struct netconfig *nc;
 +	void *nc_handle;
 +	char *netid;
 +
 +	if (handle == NULL) {
 +		nc_error = NC_EINIT;
 +		return (NULL);
 +	}
 +	np_handle = handle;
 +
 +	nc_handle = np_handle->nc_handle;
 +	if (np_handle->np_env == NULL) {
 +		while ((nc = getnetconfig(nc_handle)) != NULL)
 +			if (nc->nc_flag & NC_VISIBLE)
 +				 break;
 +	} else {
 +		nc = NULL;
 +		nc_error = NC_EEOF;
 +		mutex_lock(&np_handle_lock);
 +		while ((netid = np_handle->np_cur) != NULL) {
 +			np_handle->np_cur = nc_next_token(netid, ':');
 +			if (*netid != '\0') {
 +				nc_session_rewind(nc_handle);
 +				nc_error = NC_NOERROR;
 +				while ((nc = getnetconfig(nc_handle)) != NULL)
 +					if (strcmp(nc->nc_netid, netid) == 0)
 +						break;
 +				if (nc != NULL || nc_error != NC_EEOF)
 +					break;
 +			}
 +		}
 +		mutex_unlock(&np_handle_lock);
 +	}
 +	return (nc);
 +}
 +
 +int
 +endnetpath(void *handle)
 +{
 +	struct np_handle *np_handle;
 +	void *nc_handle;
 +
 +	if (handle == NULL) {
 +		nc_error = NC_EINIT;
 +		return (-1);
 +	}
 +	np_handle = handle;
 +
 +	nc_handle = np_handle->nc_handle;
 +	free(np_handle->np_env);
 +	free(np_handle);
 +
 +	return (endnetconfig(nc_handle));
 +}
 diff -ruNp libc.orig/rpc/rpc_com.h libc/rpc/rpc_com.h
 --- libc.orig/rpc/rpc_com.h	2006-02-28 00:10:59.000000000 +0200
 +++ libc/rpc/rpc_com.h	2012-09-27 13:39:20.000000000 +0300
 @@ -80,8 +80,6 @@ struct netbuf *__rpcb_findaddr_timed(rpc
  
  bool_t __rpc_control(int,void *);
  
 -char *_get_next_token(char *, int);
 -
  bool_t __svc_clean_idle(fd_set *, int, bool_t);
  bool_t __xdrrec_setnonblock(XDR *, int);
  bool_t __xdrrec_getrec(XDR *, enum xprt_stat *, bool_t);



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201209271320.q8RDK68K023792>