Example #1
0
LOOKUP_TYPE *
FUNCTION_NAME (ADD_PARAMS)
{
  static size_t buffer_size;
  static LOOKUP_TYPE resbuf;
  LOOKUP_TYPE *result;
#ifdef NEED_H_ERRNO
  int h_errno_tmp = 0;
#endif

  /* Get lock.  */
  __libc_lock_lock (lock);

  if (buffer == NULL)
    {
      buffer_size = BUFLEN;
      buffer = (char *) malloc (buffer_size);
    }

#ifdef HANDLE_DIGITS_DOTS
  if (buffer != NULL)
    {
      if (__nss_hostname_digits_dots (name, &resbuf, &buffer,
				      &buffer_size, 0, &result, NULL, AF_VAL,
				      H_ERRNO_VAR_P))
	goto done;
    }
#endif

  while (buffer != NULL
	 && (INTERNAL (REENTRANT_NAME) (ADD_VARIABLES, &resbuf, buffer,
					buffer_size, &result H_ERRNO_VAR)
	     == ERANGE)
#ifdef NEED_H_ERRNO
	 && h_errno_tmp == NETDB_INTERNAL
#endif
	 )
    {
      char *new_buf;
      buffer_size *= 2;
      new_buf = (char *) realloc (buffer, buffer_size);
      if (new_buf == NULL)
	{
	  /* We are out of memory.  Free the current buffer so that the
	     process gets a chance for a normal termination.  */
	  free (buffer);
	  __set_errno (ENOMEM);
	}
      buffer = new_buf;
    }

  if (buffer == NULL)
    result = NULL;

#ifdef HANDLE_DIGITS_DOTS
done:
#endif
  /* Release lock.  */
  __libc_lock_unlock (lock);

#ifdef NEED_H_ERRNO
  if (h_errno_tmp != 0)
    __set_h_errno (h_errno_tmp);
#endif

  return result;
}
Example #2
0
/* Read a directory entry from DIRP.  */
int
__READDIR_R (DIR *dirp, DIRENT_TYPE *entry, DIRENT_TYPE **result)
{
  DIRENT_TYPE *dp;
  size_t reclen;
  const int saved_errno = errno;

  __libc_lock_lock (dirp->lock);

  do
    {
      if (dirp->offset >= dirp->size)
	{
	  /* We've emptied out our buffer.  Refill it.  */

	  size_t maxread;
	  ssize_t bytes;

#ifndef _DIRENT_HAVE_D_RECLEN
	  /* Fixed-size struct; must read one at a time (see below).  */
	  maxread = sizeof *dp;
#else
	  maxread = dirp->allocation;
#endif

	  bytes = __GETDENTS (dirp->fd, dirp->data, maxread);
	  if (bytes <= 0)
	    {
	      /* On some systems getdents fails with ENOENT when the
		 open directory has been rmdir'd already.  POSIX.1
		 requires that we treat this condition like normal EOF.  */
	      if (bytes < 0 && errno == ENOENT)
		{
		  bytes = 0;
		  __set_errno (saved_errno);
		}

	      dp = NULL;
	      /* Reclen != 0 signals that an error occurred.  */
	      reclen = bytes != 0;
	      break;
	    }
	  dirp->size = (size_t) bytes;

	  /* Reset the offset into the buffer.  */
	  dirp->offset = 0;
	}

      dp = (DIRENT_TYPE *) &dirp->data[dirp->offset];

#ifdef _DIRENT_HAVE_D_RECLEN
      reclen = dp->d_reclen;
#else
      /* The only version of `struct dirent*' that lacks `d_reclen'
	 is fixed-size.  */
      assert (sizeof dp->d_name > 1);
      reclen = sizeof *dp;
      /* The name is not terminated if it is the largest possible size.
	 Clobber the following byte to ensure proper null termination.  We
	 read just one entry at a time above so we know that byte will not
	 be used later.  */
      dp->d_name[sizeof dp->d_name] = '\0';
#endif

      dirp->offset += reclen;

#ifdef _DIRENT_HAVE_D_OFF
      dirp->filepos = dp->d_off;
#else
      dirp->filepos += reclen;
#endif

      /* Skip deleted files.  */
    }
  while (dp->d_ino == 0);

  if (dp != NULL)
    {
#ifdef GETDENTS_64BIT_ALIGNED
      /* The d_reclen value might include padding which is not part of
	 the DIRENT_TYPE data structure.  */
      reclen = MIN (reclen,
		    offsetof (DIRENT_TYPE, d_name) + sizeof (dp->d_name));
#endif
      *result = memcpy (entry, dp, reclen);
#ifdef GETDENTS_64BIT_ALIGNED
      entry->d_reclen = reclen;
#endif
    }
  else
    *result = NULL;

  __libc_lock_unlock (dirp->lock);

  return dp != NULL ? 0 : reclen ? errno : 0;
}
Example #3
0
enum nss_status
_nss_nisplus_getntohost_r (const struct ether_addr *addr, struct etherent *eth,
			   char *buffer, size_t buflen, int *errnop)
{
  if (tablename_val == NULL)
    {
      __libc_lock_lock (lock);

      enum nss_status status = _nss_create_tablename (errnop);

      __libc_lock_unlock (lock);

      if (status != NSS_STATUS_SUCCESS)
	return status;
    }

  if (addr == NULL)
    {
      *errnop = EINVAL;
      return NSS_STATUS_UNAVAIL;
    }

  char buf[26 + tablename_len];

  snprintf (buf, sizeof (buf),
	    "[addr=%" PRIx8 ":%" PRIx8 ":%" PRIx8 ":%" PRIx8 ":%" PRIx8
	    ":%" PRIx8 "],%s",
	    addr->ether_addr_octet[0], addr->ether_addr_octet[1],
	    addr->ether_addr_octet[2], addr->ether_addr_octet[3],
	    addr->ether_addr_octet[4], addr->ether_addr_octet[5],
	    tablename_val);

  nis_result *result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS | USE_DGRAM,
				 NULL, NULL);

  if (result == NULL)
    {
      *errnop = ENOMEM;
      return NSS_STATUS_TRYAGAIN;
    }

  if (__glibc_unlikely (niserr2nss (result->status) != NSS_STATUS_SUCCESS))
    {
      enum nss_status status = niserr2nss (result->status);
      nis_freeresult (result);
      return status;
    }

  int parse_res = _nss_nisplus_parse_etherent (result, eth, buffer,
					       buflen, errnop);

  /* We do not need the lookup result anymore.  */
  nis_freeresult (result);

  if (__glibc_unlikely (parse_res < 1))
    {
      if (parse_res == -1)
	return NSS_STATUS_TRYAGAIN;

      return NSS_STATUS_NOTFOUND;
    }

  return NSS_STATUS_SUCCESS;
}
Example #4
0
/* Read a directory entry from DIRP.  */
struct dirent64 *
__readdir64 (DIR *dirp)
{
  struct dirent64 *dp;

  if (dirp == NULL)
    {
      errno = EINVAL;
      return NULL;
    }

  __libc_lock_lock (dirp->__lock);

  do
    {
      if (dirp->__ptr - dirp->__data >= dirp->__size)
	{
	  /* We've emptied out our buffer.  Refill it.  */

	  char *data = dirp->__data;
	  int nentries;
	  error_t err;

	  if (err = HURD_FD_PORT_USE (dirp->__fd,
				      __dir_readdir (port,
						     &data, &dirp->__size,
						     dirp->__entry_ptr,
						     -1, 0, &nentries)))
	    {
	      __hurd_fail (err);
	      dp = NULL;
	      break;
	    }

	  /* DATA now corresponds to entry index DIRP->__entry_ptr.  */
	  dirp->__entry_data = dirp->__entry_ptr;

	  if (data != dirp->__data)
	    {
	      /* The data was passed out of line, so our old buffer is no
		 longer useful.  Deallocate the old buffer and reset our
		 information for the new buffer.  */
	      __vm_deallocate (__mach_task_self (),
			       (vm_address_t) dirp->__data,
			       dirp->__allocation);
	      dirp->__data = data;
	      dirp->__allocation = round_page (dirp->__size);
	    }

	  /* Reset the pointer into the buffer.  */
	  dirp->__ptr = dirp->__data;

	  if (nentries == 0)
	    {
	      /* End of file.  */
	      dp = NULL;
	      break;
	    }

	  /* We trust the filesystem to return correct data and so we
	     ignore NENTRIES.  */
	}

      dp = (struct dirent64 *) dirp->__ptr;
      dirp->__ptr += dp->d_reclen;
      ++dirp->__entry_ptr;

      /* Loop to ignore deleted files.  */
    } while (dp->d_fileno == 0);

  __libc_lock_unlock (dirp->__lock);

  return dp;
}
Example #5
0
void *
__nss_lookup_function (service_user *ni, const char *fct_name)
{
  void **found, *result;

  /* We now modify global data.  Protect it.  */
  __libc_lock_lock (lock);

  /* Search the tree of functions previously requested.  Data in the
     tree are `known_function' structures, whose first member is a
     `const char *', the lookup key.  The search returns a pointer to
     the tree node structure; the first member of the is a pointer to
     our structure (i.e. what will be a `known_function'); since the
     first member of that is the lookup key string, &FCT_NAME is close
     enough to a pointer to our structure to use as a lookup key that
     will be passed to `known_compare' (above).  */

  found = __tsearch (&fct_name, (void **) &ni->known, &known_compare);
  if (*found != &fct_name)
    /* The search found an existing structure in the tree.  */
    result = ((known_function *) *found)->fct_ptr;
  else
    {
      /* This name was not known before.  Now we have a node in the tree
	 (in the proper sorted position for FCT_NAME) that points to
	 &FCT_NAME instead of any real `known_function' structure.
	 Allocate a new structure and fill it in.  */

      known_function *known = malloc (sizeof *known);
      if (! known)
	{
	remove_from_tree:
	  /* Oops.  We can't instantiate this node properly.
	     Remove it from the tree.  */
	  __tdelete (&fct_name, (void **) &ni->known, &known_compare);
	  result = NULL;
	}
      else
	{
	  /* Point the tree node at this new structure.  */
	  *found = known;
	  known->fct_name = fct_name;

	  if (ni->library == NULL)
	    {
	      /* This service has not yet been used.  Fetch the service
		 library for it, creating a new one if need be.  If there
		 is no service table from the file, this static variable
		 holds the head of the service_library list made from the
		 default configuration.  */
	      static name_database default_table;
	      ni->library = nss_new_service (service_table ?: &default_table,
					     ni->name);
	      if (ni->library == NULL)
		{
		  /* This only happens when out of memory.  */
		  free (known);
		  goto remove_from_tree;
		}
	    }

#if !defined DO_STATIC_NSS || defined SHARED
	  if (ni->library->lib_handle == NULL)
	    {
	      /* Load the shared library.  */
	      size_t shlen = (7 + strlen (ni->library->name) + 3
			      + strlen (__nss_shlib_revision) + 1);
	      int saved_errno = errno;
	      char shlib_name[shlen];

	      /* Construct shared object name.  */
	      __stpcpy (__stpcpy (__stpcpy (__stpcpy (shlib_name,
						      "libnss_"),
					    ni->library->name),
				  ".so"),
			__nss_shlib_revision);

	      ni->library->lib_handle = __libc_dlopen (shlib_name);
	      if (ni->library->lib_handle == NULL)
		{
		  /* Failed to load the library.  */
		  ni->library->lib_handle = (void *) -1l;
		  __set_errno (saved_errno);
		}
	    }

	  if (ni->library->lib_handle == (void *) -1l)
	    /* Library not found => function not found.  */
	    result = NULL;
	  else
	    {
	      /* Get the desired function.  */
	      size_t namlen = (5 + strlen (ni->library->name) + 1
			       + strlen (fct_name) + 1);
	      char name[namlen];

	      /* Construct the function name.  */
	      __stpcpy (__stpcpy (__stpcpy (__stpcpy (name, "_nss_"),
					    ni->library->name),
				  "_"),
			fct_name);

	      /* Look up the symbol.  */
	      result = __libc_dlsym (ni->library->lib_handle, name);
	    }
#else
	  /* We can't get function address dynamically in static linking. */
	  {
# define DEFINE_ENT(h,nm)						      \
	    { #h"_get"#nm"ent_r", _nss_##h##_get##nm##ent_r },		      \
	    { #h"_end"#nm"ent", _nss_##h##_end##nm##ent },		      \
	    { #h"_set"#nm"ent", _nss_##h##_set##nm##ent },
# define DEFINE_GET(h,nm)						      \
	    { #h"_get"#nm"_r", _nss_##h##_get##nm##_r },
# define DEFINE_GETBY(h,nm,ky)						      \
	    { #h"_get"#nm"by"#ky"_r", _nss_##h##_get##nm##by##ky##_r },
	    static struct fct_tbl { const char *fname; void *fp; } *tp, tbl[] =
	      {
# include "function.def"
		{ NULL, NULL }
	      };
	    size_t namlen = (5 + strlen (ni->library->name) + 1
			     + strlen (fct_name) + 1);
	    char name[namlen];

	    /* Construct the function name.  */
	    __stpcpy (__stpcpy (__stpcpy (name, ni->library->name),
				"_"),
		      fct_name);

	    result = NULL;
	    for (tp = &tbl[0]; tp->fname; tp++)
	      if (strcmp (tp->fname, name) == 0)
		{
		  result = tp->fp;
		  break;
		}
	  }
#endif

	  /* Remember function pointer for later calls.  Even if null, we
	     record it so a second try needn't search the library again.  */
	  known->fct_ptr = result;
	}
    }

  /* Remove the lock.  */
  __libc_lock_unlock (lock);

  return result;
}
Example #6
0
__locale_t
__newlocale (int category_mask, const char *locale, __locale_t base)
{
  /* Intermediate memory for result.  */
  const char *newnames[__LC_LAST];
  struct __locale_struct result;
  __locale_t result_ptr;
  char *locale_path;
  size_t locale_path_len;
  const char *locpath_var;
  int cnt;
  size_t names_len;

  /* We treat LC_ALL in the same way as if all bits were set.  */
  if (category_mask == 1 << LC_ALL)
    category_mask = (1 << __LC_LAST) - 1 - (1 << LC_ALL);

  /* Sanity check for CATEGORY argument.  */
  if ((category_mask & ~((1 << __LC_LAST) - 1 - (1 << LC_ALL))) != 0)
    ERROR_RETURN;

  /* `newlocale' does not support asking for the locale name. */
  if (locale == NULL)
    ERROR_RETURN;

  if (base == _nl_C_locobj_ptr)
    /* We're to modify BASE, returned for a previous call with "C".
       We can't really modify the read-only structure, so instead
       start over by copying it.  */
    base = NULL;

  if ((base == NULL || category_mask == (1 << __LC_LAST) - 1 - (1 << LC_ALL))
      && (category_mask == 0 || !strcmp (locale, "C")))
    /* Asking for the "C" locale needn't allocate a new object.  */
    return _nl_C_locobj_ptr;

  /* Allocate memory for the result.  */
  if (base != NULL)
    result = *base;
  else
    /* Fill with pointers to C locale data.  */
    result = _nl_C_locobj;

  /* If no category is to be set we return BASE if available or a
     dataset using the C locale data.  */
  if (category_mask == 0)
    {
      result_ptr = (__locale_t) malloc (sizeof (struct __locale_struct));
      if (result_ptr == NULL)
	return NULL;
      *result_ptr = result;

      goto update;
    }

  /* We perhaps really have to load some data.  So we determine the
     path in which to look for the data now.  The environment variable
     `LOCPATH' must only be used when the binary has no SUID or SGID
     bit set.  If using the default path, we tell _nl_find_locale
     by passing null and it can check the canonical locale archive.  */
  locale_path = NULL;
  locale_path_len = 0;

  locpath_var = getenv ("LOCPATH");
  if (locpath_var != NULL && locpath_var[0] != '\0')
    {
      if (__argz_create_sep (locpath_var, ':',
			     &locale_path, &locale_path_len) != 0)
	return NULL;

      if (__argz_add_sep (&locale_path, &locale_path_len,
			  _nl_default_locale_path, ':') != 0)
	return NULL;
    }

  /* Get the names for the locales we are interested in.  We either
     allow a composite name or a single name.  */
  for (cnt = 0; cnt < __LC_LAST; ++cnt)
    if (cnt != LC_ALL)
      newnames[cnt] = locale;
  if (strchr (locale, ';') != NULL)
    {
      /* This is a composite name.  Make a copy and split it up.  */
      char *np = strdupa (locale);
      char *cp;
      int specified_mask = 0;

      while ((cp = strchr (np, '=')) != NULL)
	{
	  for (cnt = 0; cnt < __LC_LAST; ++cnt)
	    if (cnt != LC_ALL
		&& (size_t) (cp - np) == _nl_category_name_sizes[cnt]
		&& memcmp (np, (_nl_category_names.str
				+ _nl_category_name_idxs[cnt]), cp - np) == 0)
	      break;

	  if (cnt == __LC_LAST)
	    /* Bogus category name.  */
	    ERROR_RETURN;

	  /* Found the category this clause sets.  */
	  specified_mask |= 1 << cnt;
	  newnames[cnt] = ++cp;
	  cp = strchr (cp, ';');
	  if (cp != NULL)
	    {
	      /* Examine the next clause.  */
	      *cp = '\0';
	      np = cp + 1;
	    }
	  else
	    /* This was the last clause.  We are done.  */
	    break;
	}

      if (category_mask &~ specified_mask)
	/* The composite name did not specify all categories we need.  */
	ERROR_RETURN;
    }

  /* Protect global data.  */
  __libc_lock_lock (__libc_setlocale_lock);

  /* Now process all categories we are interested in.  */
  names_len = 0;
  for (cnt = 0; cnt < __LC_LAST; ++cnt)
    {
      if ((category_mask & 1 << cnt) != 0)
	{
	  result.__locales[cnt] = _nl_find_locale (locale_path,
						   locale_path_len,
						   cnt, &newnames[cnt]);
	  if (result.__locales[cnt] == NULL)
	    {
	    free_cnt_data_and_exit:
	      while (cnt-- > 0)
		if (((category_mask & 1 << cnt) != 0)
		    && result.__locales[cnt]->usage_count != UNDELETABLE)
		  /* We can remove the data.  */
		  _nl_remove_locale (cnt, result.__locales[cnt]);

              /* Critical section left.  */
              __libc_lock_unlock (__libc_setlocale_lock);
	      return NULL;
	    }

	  if (newnames[cnt] != _nl_C_name)
	    names_len += strlen (newnames[cnt]) + 1;
	}
      else if (cnt != LC_ALL && result.__names[cnt] != _nl_C_name)
	/* Tally up the unchanged names from BASE as well.  */
	names_len += strlen (result.__names[cnt]) + 1;
    }

  /* We successfully loaded all required data.  Allocate a new structure.
     We can't just reuse the BASE pointer, because the name strings are
     changing and we need the old name string area intact so we can copy
     out of it into the new one without overlap problems should some
     category's name be getting longer.  */
  result_ptr = malloc (sizeof (struct __locale_struct) + names_len);
  if (result_ptr == NULL)
    {
      cnt = __LC_LAST;
      goto free_cnt_data_and_exit;
    }

  if (base == NULL)
    {
      /* Fill in this new structure from scratch.  */

      char *namep = (char *) (result_ptr + 1);

      /* Install copied new names in the new structure's __names array.
	 If resolved to "C", that is already in RESULT.__names to start.  */
      for (cnt = 0; cnt < __LC_LAST; ++cnt)
	if ((category_mask & 1 << cnt) != 0 && newnames[cnt] != _nl_C_name)
	  {
	    result.__names[cnt] = namep;
	    namep = __stpcpy (namep, newnames[cnt]) + 1;
	  }

      *result_ptr = result;
    }
  else
    {
      /* We modify the base structure.  */

      char *namep = (char *) (result_ptr + 1);

      for (cnt = 0; cnt < __LC_LAST; ++cnt)
	if ((category_mask & 1 << cnt) != 0)
	  {
	    if (base->__locales[cnt]->usage_count != UNDELETABLE)
	      /* We can remove the old data.  */
	      _nl_remove_locale (cnt, base->__locales[cnt]);
	    result_ptr->__locales[cnt] = result.__locales[cnt];

	    if (newnames[cnt] == _nl_C_name)
	      result_ptr->__names[cnt] = _nl_C_name;
	    else
	      {
		result_ptr->__names[cnt] = namep;
		namep = __stpcpy (namep, newnames[cnt]) + 1;
	      }
	  }
	else if (cnt != LC_ALL)
	  {
	    /* The RESULT members point into the old BASE structure.  */
	    result_ptr->__locales[cnt] = result.__locales[cnt];
	    if (result.__names[cnt] == _nl_C_name)
	      result_ptr->__names[cnt] = _nl_C_name;
	    else
	      {
		result_ptr->__names[cnt] = namep;
		namep = __stpcpy (namep, result.__names[cnt]) + 1;
	      }
	  }

      free (base);
    }

  /* Critical section left.  */
  __libc_lock_unlock (__libc_setlocale_lock);

  /* Update the special members.  */
 update:
  {
    union locale_data_value *ctypes = result_ptr->__locales[LC_CTYPE]->values;
    result_ptr->__ctype_b = (const unsigned short int *)
      ctypes[_NL_ITEM_INDEX (_NL_CTYPE_CLASS)].string + 128;
    result_ptr->__ctype_tolower = (const int *)
      ctypes[_NL_ITEM_INDEX (_NL_CTYPE_TOLOWER)].string + 128;
    result_ptr->__ctype_toupper = (const int *)
      ctypes[_NL_ITEM_INDEX (_NL_CTYPE_TOUPPER)].string + 128;
  }

  return result_ptr;
}
Example #7
0
/* Early SCP context doesn't need the locks, since we're single threaded, and we
 * can't grab the PDR locks in some cases.  Specifically, we might not have a
 * TLS for thread 0 yet, so we can't do things like check in_vcore_context(). */
static void brk_lock(void)
{
	if (is_early_scp())
		return;
	__libc_lock_lock(__brk_lock);
}
Example #8
0
void
__vsyslog_internal(int pri, const char *fmt, va_list ap,
		   unsigned int mode_flags)
{
	struct tm now_tm;
	time_t now;
	int fd;
	FILE *f;
	char *buf = 0;
	size_t bufsize = 0;
	size_t msgoff;
#ifndef NO_SIGPIPE
 	struct sigaction action, oldaction;
 	int sigpipe;
#endif
	int saved_errno = errno;
	char failbuf[3 * sizeof (pid_t) + sizeof "out of memory []"];

#define	INTERNALLOG	LOG_ERR|LOG_CONS|LOG_PERROR|LOG_PID
	/* Check for invalid bits. */
	if (pri & ~(LOG_PRIMASK|LOG_FACMASK)) {
		syslog(INTERNALLOG,
		    "syslog: unknown facility/priority: %x", pri);
		pri &= LOG_PRIMASK|LOG_FACMASK;
	}

	/* Check priority against setlogmask values. */
	if ((LOG_MASK (LOG_PRI (pri)) & LogMask) == 0)
		return;

	/* Set default facility if none specified. */
	if ((pri & LOG_FACMASK) == 0)
		pri |= LogFacility;

	/* Build the message in a memory-buffer stream.  */
	f = __open_memstream (&buf, &bufsize);
	if (f == NULL)
	  {
	    /* We cannot get a stream.  There is not much we can do but
	       emitting an error messages.  */
	    char numbuf[3 * sizeof (pid_t)];
	    char *nump;
	    char *endp = __stpcpy (failbuf, "out of memory [");
	    pid_t pid = __getpid ();

	    nump = numbuf + sizeof (numbuf);
	    /* The PID can never be zero.  */
	    do
	      *--nump = '0' + pid % 10;
	    while ((pid /= 10) != 0);

	    endp = __mempcpy (endp, nump, (numbuf + sizeof (numbuf)) - nump);
	    *endp++ = ']';
	    *endp = '\0';
	    buf = failbuf;
	    bufsize = endp - failbuf;
	    msgoff = 0;
	  }
	else
	  {
	    __fsetlocking (f, FSETLOCKING_BYCALLER);
	    fprintf (f, "<%d>", pri);
	    (void) time (&now);
	    f->_IO_write_ptr += __strftime_l (f->_IO_write_ptr,
					      f->_IO_write_end
					      - f->_IO_write_ptr,
					      "%h %e %T ",
					      __localtime_r (&now, &now_tm),
					      _nl_C_locobj_ptr);
	    msgoff = ftell (f);
	    if (LogTag == NULL)
	      LogTag = __progname;
	    if (LogTag != NULL)
	      __fputs_unlocked (LogTag, f);
	    if (LogStat & LOG_PID)
	      fprintf (f, "[%d]", (int) __getpid ());
	    if (LogTag != NULL)
	      {
		__putc_unlocked (':', f);
		__putc_unlocked (' ', f);
	      }

	    /* Restore errno for %m format.  */
	    __set_errno (saved_errno);

	    /* We have the header.  Print the user's format into the
	       buffer.  */
	    __vfprintf_internal (f, fmt, ap, mode_flags);

	    /* Close the memory stream; this will finalize the data
	       into a malloc'd buffer in BUF.  */
	    fclose (f);
	  }

	/* Output to stderr if requested. */
	if (LogStat & LOG_PERROR) {
		struct iovec iov[2];
		struct iovec *v = iov;

		v->iov_base = buf + msgoff;
		v->iov_len = bufsize - msgoff;
		/* Append a newline if necessary.  */
		if (buf[bufsize - 1] != '\n')
		  {
		    ++v;
		    v->iov_base = (char *) "\n";
		    v->iov_len = 1;
		  }

		__libc_cleanup_push (free, buf == failbuf ? NULL : buf);

		/* writev is a cancellation point.  */
		(void)__writev(STDERR_FILENO, iov, v - iov + 1);

		__libc_cleanup_pop (0);
	}

	/* Prepare for multiple users.  We have to take care: open and
	   write are cancellation points.  */
	struct cleanup_arg clarg;
	clarg.buf = buf;
	clarg.oldaction = NULL;
	__libc_cleanup_push (cancel_handler, &clarg);
	__libc_lock_lock (syslog_lock);

#ifndef NO_SIGPIPE
	/* Prepare for a broken connection.  */
 	memset (&action, 0, sizeof (action));
 	action.sa_handler = sigpipe_handler;
 	sigemptyset (&action.sa_mask);
 	sigpipe = __sigaction (SIGPIPE, &action, &oldaction);
	if (sigpipe == 0)
	  clarg.oldaction = &oldaction;
#endif

	/* Get connected, output the message to the local logger. */
	if (!connected)
		openlog_internal(LogTag, LogStat | LOG_NDELAY, 0);

	/* If we have a SOCK_STREAM connection, also send ASCII NUL as
	   a record terminator.  */
	if (LogType == SOCK_STREAM)
	  ++bufsize;

	if (!connected || __send(LogFile, buf, bufsize, send_flags) < 0)
	  {
	    if (connected)
	      {
		/* Try to reopen the syslog connection.  Maybe it went
		   down.  */
		closelog_internal ();
		openlog_internal(LogTag, LogStat | LOG_NDELAY, 0);
	      }

	    if (!connected || __send(LogFile, buf, bufsize, send_flags) < 0)
	      {
		closelog_internal ();	/* attempt re-open next time */
		/*
		 * Output the message to the console; don't worry
		 * about blocking, if console blocks everything will.
		 * Make sure the error reported is the one from the
		 * syslogd failure.
		 */
		if (LogStat & LOG_CONS &&
		    (fd = __open(_PATH_CONSOLE, O_WRONLY|O_NOCTTY, 0)) >= 0)
		  {
		    __dprintf (fd, "%s\r\n", buf + msgoff);
		    (void)__close(fd);
		  }
	      }
	  }

#ifndef NO_SIGPIPE
	if (sigpipe == 0)
		__sigaction (SIGPIPE, &oldaction, (struct sigaction *) NULL);
#endif

	/* End of critical section.  */
	__libc_cleanup_pop (0);
	__libc_lock_unlock (syslog_lock);

	if (buf != failbuf)
		free (buf);
}
Example #9
0
/* Read a directory entry from DIRP.  */
int
__READDIR_R (DIR *dirp, DIRENT_TYPE *entry, DIRENT_TYPE **result)
{
  DIRENT_TYPE *dp;
  size_t reclen;
  const int saved_errno = errno;
  int ret;

  __libc_lock_lock (dirp->lock);

  do
    {
      if (dirp->offset >= dirp->size)
	{
	  /* We've emptied out our buffer.  Refill it.  */

	  size_t maxread;
	  ssize_t bytes;

#ifndef _DIRENT_HAVE_D_RECLEN
	  /* Fixed-size struct; must read one at a time (see below).  */
	  maxread = sizeof *dp;
#else
	  maxread = dirp->allocation;
#endif

	  bytes = __GETDENTS (dirp->fd, dirp->data, maxread);
	  if (bytes <= 0)
	    {
	      /* On some systems getdents fails with ENOENT when the
		 open directory has been rmdir'd already.  POSIX.1
		 requires that we treat this condition like normal EOF.  */
	      if (bytes < 0 && errno == ENOENT)
		{
		  bytes = 0;
		  __set_errno (saved_errno);
		}
	      if (bytes < 0)
		dirp->errcode = errno;

	      dp = NULL;
	      break;
	    }
	  dirp->size = (size_t) bytes;

	  /* Reset the offset into the buffer.  */
	  dirp->offset = 0;
	}

      dp = (DIRENT_TYPE *) &dirp->data[dirp->offset];

#ifdef _DIRENT_HAVE_D_RECLEN
      reclen = dp->d_reclen;
#else
      /* The only version of `struct dirent*' that lacks `d_reclen'
	 is fixed-size.  */
      assert (sizeof dp->d_name > 1);
      reclen = sizeof *dp;
      /* The name is not terminated if it is the largest possible size.
	 Clobber the following byte to ensure proper null termination.  We
	 read just one entry at a time above so we know that byte will not
	 be used later.  */
      dp->d_name[sizeof dp->d_name] = '\0';
#endif

      dirp->offset += reclen;

#ifdef _DIRENT_HAVE_D_OFF
      dirp->filepos = dp->d_off;
#else
      dirp->filepos += reclen;
#endif

#ifdef NAME_MAX
      if (reclen > offsetof (DIRENT_TYPE, d_name) + NAME_MAX + 1)
	{
	  /* The record is very long.  It could still fit into the
	     caller-supplied buffer if we can skip padding at the
	     end.  */
	  size_t namelen = _D_EXACT_NAMLEN (dp);
	  if (namelen <= NAME_MAX)
	    reclen = offsetof (DIRENT_TYPE, d_name) + namelen + 1;
	  else
	    {
	      /* The name is too long.  Ignore this file.  */
	      dirp->errcode = ENAMETOOLONG;
	      dp->d_ino = 0;
	      continue;
	    }
	}
#endif

      /* Skip deleted and ignored files.  */
    }
  while (dp->d_ino == 0);

  if (dp != NULL)
    {
      *result = memcpy (entry, dp, reclen);
#ifdef _DIRENT_HAVE_D_RECLEN
      entry->d_reclen = reclen;
#endif
      ret = 0;
    }
  else
    {
      *result = NULL;
      ret = dirp->errcode;
    }

  __libc_lock_unlock (dirp->lock);

  return ret;
}
Example #10
0
/* Add to the log file an entry denoting a failed translation.  */
void _nl_log_untranslated(const char *logfilename, const char *domainname,
                          const char *msgid1, const char *msgid2, int plural) {
    __libc_lock_lock(lock);
    _nl_log_untranslated_locked(logfilename, domainname, msgid1, msgid2, plural);
    __libc_lock_unlock(lock);
}
Example #11
0
/* Determine the directories we are looking for data in.  */
void
internal_function
__gconv_get_path (void)
{
  struct path_elem *result;
  __libc_lock_define_initialized (static, lock);

  __libc_lock_lock (lock);

  /* Make sure there wasn't a second thread doing it already.  */
  result = (struct path_elem *) __gconv_path_elem;
  if (result == NULL)
    {
      /* Determine the complete path first.  */
      char *gconv_path;
      size_t gconv_path_len;
      char *elem;
      char *oldp;
      char *cp;
      int nelems;
      char *cwd;
      size_t cwdlen;

      if (__gconv_path_envvar == NULL)
	{
	  /* No user-defined path.  Make a modifiable copy of the
	     default path.  */
	  gconv_path = strdupa (default_gconv_path);
	  gconv_path_len = sizeof (default_gconv_path);
	  cwd = NULL;
	  cwdlen = 0;
	}
      else
	{
	  /* Append the default path to the user-defined path.  */
	  size_t user_len = strlen (__gconv_path_envvar);

	  gconv_path_len = user_len + 1 + sizeof (default_gconv_path);
	  gconv_path = alloca (gconv_path_len);
	  __mempcpy (__mempcpy (__mempcpy (gconv_path, __gconv_path_envvar,
					   user_len),
				":", 1),
		     default_gconv_path, sizeof (default_gconv_path));
	  cwd = __getcwd (NULL, 0);
	  cwdlen = strlen (cwd);
	}
      assert (default_gconv_path[0] == '/');

      /* In a first pass we calculate the number of elements.  */
      oldp = NULL;
      cp = strchr (gconv_path, ':');
      nelems = 1;
      while (cp != NULL)
	{
	  if (cp != oldp + 1)
	    ++nelems;
	  oldp = cp;
	  cp =  strchr (cp + 1, ':');
	}

      /* Allocate the memory for the result.  */
      result = (struct path_elem *) malloc ((nelems + 1)
					    * sizeof (struct path_elem)
					    + gconv_path_len + nelems
					    + (nelems - 1) * (cwdlen + 1));
      if (result != NULL)
	{
	  char *strspace = (char *) &result[nelems + 1];
	  int n = 0;

	  /* Separate the individual parts.  */
	  __gconv_max_path_elem_len = 0;
	  elem = __strtok_r (gconv_path, ":", &gconv_path);
	  assert (elem != NULL);
	  do
	    {
	      result[n].name = strspace;
	      if (elem[0] != '/')
		{
		  assert (cwd != NULL);
		  strspace = __mempcpy (strspace, cwd, cwdlen);
		  *strspace++ = '/';
		}
	      strspace = __stpcpy (strspace, elem);
	      if (strspace[-1] != '/')
		*strspace++ = '/';

	      result[n].len = strspace - result[n].name;
	      if (result[n].len > __gconv_max_path_elem_len)
		__gconv_max_path_elem_len = result[n].len;

	      *strspace++ = '\0';
	      ++n;
	    }
	  while ((elem = __strtok_r (NULL, ":", &gconv_path)) != NULL);

	  result[n].name = NULL;
	  result[n].len = 0;
	}

      __gconv_path_elem = result ?: (struct path_elem *) &empty_path_elem;

      if (cwd != NULL)
	free (cwd);
    }
Example #12
0
int
__lckpwdf (void)
{
  int flags;
  sigset_t saved_set;			/* Saved set of caught signals.  */
  struct sigaction saved_act;		/* Saved signal action.  */
  sigset_t new_set;			/* New set of caught signals.  */
  struct sigaction new_act;		/* New signal action.  */
  struct flock fl;			/* Information struct for locking.  */
  int result;

  if (lock_fd != -1)
    /* Still locked by own process.  */
    return -1;

  /* Prevent problems caused by multiple threads.  */
  __libc_lock_lock (lock);

  int oflags = O_WRONLY | O_CREAT;
#ifdef O_CLOEXEC
  oflags |= O_CLOEXEC;
#endif
  lock_fd = __open (PWD_LOCKFILE, oflags, 0600);
  if (lock_fd == -1)
    /* Cannot create lock file.  */
    RETURN_CLOSE_FD (-1);

#ifndef __ASSUME_O_CLOEXEC
# ifdef O_CLOEXEC
  if (__have_o_cloexec <= 0)
# endif
    {
      /* Make sure file gets correctly closed when process finished.  */
      flags = __fcntl (lock_fd, F_GETFD, 0);
      if (flags == -1)
	/* Cannot get file flags.  */
	RETURN_CLOSE_FD (-1);
# ifdef O_CLOEXEC
      if (__have_o_cloexec == 0)
	__have_o_cloexec = (flags & FD_CLOEXEC) == 0 ? -1 : 1;
      if (__have_o_cloexec < 0)
# endif
	{
	  flags |= FD_CLOEXEC;		/* Close on exit.  */
	  if (__fcntl (lock_fd, F_SETFD, flags) < 0)
	    /* Cannot set new flags.  */
	    RETURN_CLOSE_FD (-1);
	}
    }
#endif

  /* Now we have to get exclusive write access.  Since multiple
     process could try this we won't stop when it first fails.
     Instead we set a timeout for the system call.  Once the timer
     expires it is likely that there are some problems which cannot be
     resolved by waiting.

     It is important that we don't change the signal state.  We must
     restore the old signal behaviour.  */
  memset (&new_act, '\0', sizeof (struct sigaction));
  new_act.sa_handler = noop_handler;
  __sigfillset (&new_act.sa_mask);
  new_act.sa_flags = 0ul;

  /* Install new action handler for alarm and save old.  */
  if (__sigaction (SIGALRM, &new_act, &saved_act) < 0)
    /* Cannot install signal handler.  */
    RETURN_CLOSE_FD (-1);

  /* Now make sure the alarm signal is not blocked.  */
  __sigemptyset (&new_set);
  __sigaddset (&new_set, SIGALRM);
  if (__sigprocmask (SIG_UNBLOCK, &new_set, &saved_set) < 0)
    RETURN_RESTORE_HANDLER (-1);

  /* Start timer.  If we cannot get the lock in the specified time we
     get a signal.  */
  alarm (TIMEOUT);

  /* Try to get the lock.  */
  memset (&fl, '\0', sizeof (struct flock));
  fl.l_type = F_WRLCK;
  fl.l_whence = SEEK_SET;
  result = __fcntl (lock_fd, F_SETLKW, &fl);

  RETURN_CLEAR_ALARM (result);
}
Example #13
0
static mstate
_int_new_arena (size_t size)
{
  mstate a;
  heap_info *h;
  char *ptr;
  unsigned long misalign;

  h = new_heap (size + (sizeof (*h) + sizeof (*a) + MALLOC_ALIGNMENT),
                mp_.top_pad);
  if (!h)
    {
      /* Maybe size is too large to fit in a single heap.  So, just try
         to create a minimally-sized arena and let _int_malloc() attempt
         to deal with the large request via mmap_chunk().  */
      h = new_heap (sizeof (*h) + sizeof (*a) + MALLOC_ALIGNMENT, mp_.top_pad);
      if (!h)
        return 0;
    }
  a = h->ar_ptr = (mstate) (h + 1);
  malloc_init_state (a);
  a->attached_threads = 1;
  /*a->next = NULL;*/
  a->system_mem = a->max_system_mem = h->size;

  /* Set up the top chunk, with proper alignment. */
  ptr = (char *) (a + 1);
  misalign = (unsigned long) chunk2mem (ptr) & MALLOC_ALIGN_MASK;
  if (misalign > 0)
    ptr += MALLOC_ALIGNMENT - misalign;
  top (a) = (mchunkptr) ptr;
  set_head (top (a), (((char *) h + h->size) - ptr) | PREV_INUSE);

  LIBC_PROBE (memory_arena_new, 2, a, size);
  mstate replaced_arena = thread_arena;
  thread_arena = a;
  __libc_lock_init (a->mutex);

  __libc_lock_lock (list_lock);

  /* Add the new arena to the global list.  */
  a->next = main_arena.next;
  /* FIXME: The barrier is an attempt to synchronize with read access
     in reused_arena, which does not acquire list_lock while
     traversing the list.  */
  atomic_write_barrier ();
  main_arena.next = a;

  __libc_lock_unlock (list_lock);

  __libc_lock_lock (free_list_lock);
  detach_arena (replaced_arena);
  __libc_lock_unlock (free_list_lock);

  /* Lock this arena.  NB: Another thread may have been attached to
     this arena because the arena is now accessible from the
     main_arena.next list and could have been picked by reused_arena.
     This can only happen for the last arena created (before the arena
     limit is reached).  At this point, some arena has to be attached
     to two threads.  We could acquire the arena lock before list_lock
     to make it less likely that reused_arena picks this new arena,
     but this could result in a deadlock with
     __malloc_fork_lock_parent.  */

  __libc_lock_lock (a->mutex);

  return a;
}
Example #14
0
File: arena.c Project: kraj/glibc
/* Lock and return an arena that can be reused for memory allocation.
   Avoid AVOID_ARENA as we have already failed to allocate memory in
   it and it is currently locked.  */
static mstate
reused_arena (mstate avoid_arena)
{
  mstate result;
  /* FIXME: Access to next_to_use suffers from data races.  */
  static mstate next_to_use;
  if (next_to_use == NULL)
    next_to_use = &main_arena;

  /* Iterate over all arenas (including those linked from
     free_list).  */
  result = next_to_use;
  do
    {
      if (!arena_is_corrupt (result) && !__libc_lock_trylock (result->mutex))
        goto out;

      /* FIXME: This is a data race, see _int_new_arena.  */
      result = result->next;
    }
  while (result != next_to_use);

  /* Avoid AVOID_ARENA as we have already failed to allocate memory
     in that arena and it is currently locked.   */
  if (result == avoid_arena)
    result = result->next;

  /* Make sure that the arena we get is not corrupted.  */
  mstate begin = result;
  while (arena_is_corrupt (result) || result == avoid_arena)
    {
      result = result->next;
      if (result == begin)
	/* We looped around the arena list.  We could not find any
	   arena that was either not corrupted or not the one we
	   wanted to avoid.  */
	return NULL;
    }

  /* No arena available without contention.  Wait for the next in line.  */
  LIBC_PROBE (memory_arena_reuse_wait, 3, &result->mutex, result, avoid_arena);
  __libc_lock_lock (result->mutex);

out:
  /* Attach the arena to the current thread.  */
  {
    /* Update the arena thread attachment counters.   */
    mstate replaced_arena = thread_arena;
    __libc_lock_lock (free_list_lock);
    detach_arena (replaced_arena);

    /* We may have picked up an arena on the free list.  We need to
       preserve the invariant that no arena on the free list has a
       positive attached_threads counter (otherwise,
       arena_thread_freeres cannot use the counter to determine if the
       arena needs to be put on the free list).  We unconditionally
       remove the selected arena from the free list.  The caller of
       reused_arena checked the free list and observed it to be empty,
       so the list is very short.  */
    remove_from_free_list (result);

    ++result->attached_threads;

    __libc_lock_unlock (free_list_lock);
  }

  LIBC_PROBE (memory_arena_reuse, 2, result, avoid_arena);
  thread_arena = result;
  next_to_use = result->next;

  return result;
}
Example #15
0
static void
_nl_init_era_entries (void)
{
  size_t cnt;

  __libc_lock_lock (__libc_setlocale_lock);

  if (era_initialized == 0)
    {
      size_t new_num_eras = _NL_CURRENT_WORD (LC_TIME,
					      _NL_TIME_ERA_NUM_ENTRIES);
      if (new_num_eras == 0)
	{
	  free (eras);
	  eras = NULL;
	}
      else
	{
	  if (num_eras != new_num_eras)
	    eras = (struct era_entry *) realloc (eras,
						 new_num_eras
						 * sizeof (struct era_entry));
	  if (eras == NULL)
	    {
	      num_eras = 0;
	      eras = NULL;
	    }
          else
	    {
	      const char *ptr = _NL_CURRENT (LC_TIME, _NL_TIME_ERA_ENTRIES);
	      num_eras = new_num_eras;

	      for (cnt = 0; cnt < num_eras; ++cnt)
		{
		  const char *base_ptr = ptr;
		  memcpy ((void *) (eras + cnt), (const void *) ptr,
			  sizeof (uint32_t) * 8);

		  if (ERA_DATE_CMP(eras[cnt].start_date,
				   eras[cnt].stop_date))
		    if (eras[cnt].direction == (uint32_t) '+')
		      eras[cnt].absolute_direction = 1;
		    else
		      eras[cnt].absolute_direction = -1;
		  else
		    if (eras[cnt].direction == (uint32_t) '+')
		      eras[cnt].absolute_direction = -1;
		    else
		      eras[cnt].absolute_direction = 1;

		  /* Skip numeric values.  */
		  ptr += sizeof (uint32_t) * 8;

		  /* Set and skip era name.  */
		  eras[cnt].era_name = ptr;
		  ptr = strchr (ptr, '\0') + 1;

		  /* Set and skip era format.  */
		  eras[cnt].era_format = ptr;
		  ptr = strchr (ptr, '\0') + 1;

		  ptr += 3 - (((ptr - (const char *) base_ptr) + 3) & 3);

		  /* Set and skip wide era name.  */
		  eras[cnt].era_wname = (wchar_t *) ptr;
		  ptr = (char *) (wcschr ((wchar_t *) ptr, L'\0') + 1);

		  /* Set and skip wide era format.  */
		  eras[cnt].era_wformat = (wchar_t *) ptr;
		  ptr = (char *) (wcschr ((wchar_t *) ptr, L'\0') + 1);
		}
	    }
	}

      era_initialized = 1;
    }

  __libc_lock_unlock (__libc_setlocale_lock);
}
Example #16
0
/* -1 == database not found
    0 == database entry pointer stored */
int
__nss_database_lookup (const char *database, const char *alternate_name,
		       const char *defconfig, service_user **ni)
{
  /* Prevent multiple threads to change the service table.  */
  __libc_lock_lock (lock);

  /* Reconsider database variable in case some other thread called
     `__nss_configure_lookup' while we waited for the lock.  */
  if (*ni != NULL)
    {
      __libc_lock_unlock (lock);
      return 0;
    }

  /* Are we initialized yet?  */
  if (service_table == NULL)
    /* Read config file.  */
    service_table = nss_parse_file (_PATH_NSSWITCH_CONF);

  /* Test whether configuration data is available.  */
  if (service_table != NULL)
    {
      /* Return first `service_user' entry for DATABASE.  */
      name_database_entry *entry;

      /* XXX Could use some faster mechanism here.  But each database is
	 only requested once and so this might not be critical.  */
      for (entry = service_table->entry; entry != NULL; entry = entry->next)
	if (strcmp (database, entry->name) == 0)
	  *ni = entry->service;

      if (*ni == NULL && alternate_name != NULL)
	/* We haven't found an entry so far.  Try to find it with the
	   alternative name.  */
	for (entry = service_table->entry; entry != NULL; entry = entry->next)
	  if (strcmp (alternate_name, entry->name) == 0)
	    *ni = entry->service;
    }

  /* No configuration data is available, either because nsswitch.conf
     doesn't exist or because it doesn't have a line for this database.

     DEFCONFIG specifies the default service list for this database,
     or null to use the most common default.  */
  if (*ni == NULL)
    {
      *ni = nss_parse_service_list (defconfig
				    ?: "nis [NOTFOUND=return] files");
      if (*ni != NULL)
	{
	  /* Record the memory we've just allocated in defconfig_entries list,
	     so we can free it later.  */
	  name_database_entry *entry;

	  /* Allocate ENTRY plus size of name (1 here).  */
	  entry = (name_database_entry *) malloc (sizeof (*entry) + 1);

	  if (entry != NULL)
	    {
	      entry->next = defconfig_entries;
	      entry->service = *ni;
	      entry->name[0] = '\0';
	      defconfig_entries = entry;
	    }
	}
    }