The following reply was made to PR kern/165710; it has been noted by GNATS.

From: Andrey Simonenko <[email protected]>
To: [email protected]
Cc:  
Subject: bin/165710: RPC: getnetconfig() and other netconfig's functions
 correct implementation.
Date: Mon, 1 Oct 2012 12:50:43 +0300

 Slightly optimized netconfig.c:nc_parse().
 
 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-30 21:53:42.000000000 +0300
 @@ -0,0 +1,723 @@
 +/*-
 + * 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;;) {
 +              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);
_______________________________________________
[email protected] mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-bugs
To unsubscribe, send any mail to "[email protected]"

Reply via email to