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; }
/* 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; }
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; }
/* 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; }
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; }
__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; }
/* 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); }
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); }
/* 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; }
/* 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); }
/* 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); }
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); }
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; }
/* 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; }
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); }
/* -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; } } }