From owner-freebsd-bugs@FreeBSD.ORG Sat Apr 21 10:20:10 2012 Return-Path: Delivered-To: freebsd-bugs@hub.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [69.147.83.52]) by hub.freebsd.org (Postfix) with ESMTP id 9E2C81065670 for ; Sat, 21 Apr 2012 10:20:10 +0000 (UTC) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (freefall.freebsd.org [IPv6:2001:4f8:fff6::28]) by mx1.freebsd.org (Postfix) with ESMTP id 831BA8FC14 for ; Sat, 21 Apr 2012 10:20:10 +0000 (UTC) Received: from freefall.freebsd.org (localhost [127.0.0.1]) by freefall.freebsd.org (8.14.5/8.14.5) with ESMTP id q3LAKAtk042867 for ; Sat, 21 Apr 2012 10:20:10 GMT (envelope-from gnats@freefall.freebsd.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.14.5/8.14.5/Submit) id q3LAKA3a042866; Sat, 21 Apr 2012 10:20:10 GMT (envelope-from gnats) Date: Sat, 21 Apr 2012 10:20:10 GMT Message-Id: <201204211020.q3LAKA3a042866@freefall.freebsd.org> To: freebsd-bugs@FreeBSD.org From: Andrey Simonenko Cc: Subject: Re: bin/165710: RPC: getnetconfig() and other netconfig's functions correct implementation. X-BeenThere: freebsd-bugs@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list Reply-To: Andrey Simonenko List-Id: Bug reports List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 21 Apr 2012 10:20:10 -0000 The following reply was made to PR kern/165710; it has been noted by GNATS. From: Andrey Simonenko To: bug-followup@FreeBSD.org Cc: Subject: Re: bin/165710: RPC: getnetconfig() and other netconfig's functions correct implementation. Date: Sat, 21 Apr 2012 13:13:12 +0300 Updated changes with better names for structures. 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-04-21 11:56:00.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-04-21 11:56:00.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-04-21 11:56:00.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-04-21 11:56:00.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-04-21 03:46:30.000000000 +0300 @@ -0,0 +1,735 @@ +/*- + * 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 +__FBSDID("$FreeBSD$"); + +#include +#include + +#include "namespace.h" +#include "reentrant.h" +#include +#include +#include +#include +#include +#include "un-namespace.h" + +/* + * Semantics as strings. + */ +#define NC_TPI_CLTS_S "tpi_clts" +#define NC_TPI_COTS_S "tpi_cots" +#define NC_TPI_COTS_ORD_S "tpi_cots_ord" +#define NC_TPI_RAW_S "tpi_raw" + +#define NC_SEMANTICS_TBL_ELEM(x) { .name = x ## _S, .code = x } +static const struct { + const char *name; + u_long code; +} nc_semantics_tbl[] = { + NC_SEMANTICS_TBL_ELEM(NC_TPI_COTS_ORD), + NC_SEMANTICS_TBL_ELEM(NC_TPI_COTS), + NC_SEMANTICS_TBL_ELEM(NC_TPI_CLTS), + NC_SEMANTICS_TBL_ELEM(NC_TPI_RAW) +}; + +#define NC_SEMANTICS_TBL_SIZE \ + (sizeof(nc_semantics_tbl) / sizeof(nc_semantics_tbl[0])) + +/* + * Flags as characters. + */ +#define NC_NOFLAG_C '-' +#define NC_VISIBLE_C 'v' +#define NC_BROADCAST_C 'b' + +/* + * Character used to indicate there is no name-to-address lookup library. + */ +#define NC_NOLOOKUP_C '-' + +/* + * 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] = "Not initialized", + [NC_EFORMAT] = "Netconfig database has invalid 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 read 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] == NC_NOFLAG_C) { + if (token[1] != '\0') + goto failed_format; + } else { + do { + switch (*token) { + case NC_VISIBLE_C: + nc->nc_flag |= NC_VISIBLE; + break; + case NC_BROADCAST_C: + 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] == NC_NOLOOKUP_C) { + 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: + 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; + + if (handle == NULL) { + nc_error = NC_EINIT; + return (-1); + } + free(handle); + + 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) { + fclose(nc_file); + 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 (0); +} + +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-04-21 11:56:00.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);