/* Close all file descriptors except the one specified. */ static void close_all_fds (void) { DIR *dir = __opendir ("/proc/self/fd"); if (dir != NULL) { struct dirent64 *d; while ((d = __readdir64 (dir)) != NULL) if (isdigit (d->d_name[0])) { char *endp; long int fd = strtol (d->d_name, &endp, 10); if (*endp == '\0' && fd != PTY_FILENO && fd != dirfd (dir)) close_not_cancel_no_status (fd); } __closedir (dir); int nullfd = open_not_cancel_2 (_PATH_DEVNULL, O_RDONLY); assert (nullfd == STDIN_FILENO); nullfd = open_not_cancel_2 (_PATH_DEVNULL, O_WRONLY); assert (nullfd == STDOUT_FILENO); __dup2 (STDOUT_FILENO, STDERR_FILENO); } }
static void backtrace_and_maps (int do_abort, bool written, int fd) { if (do_abort > 1 && written) { void *addrs[64]; #define naddrs (sizeof (addrs) / sizeof (addrs[0])) int n = __backtrace (addrs, naddrs); if (n > 2) { #define strnsize(str) str, strlen (str) #define writestr(str) write_not_cancel (fd, str) writestr (strnsize ("======= Backtrace: =========\n")); __backtrace_symbols_fd (addrs + 1, n - 1, fd); writestr (strnsize ("======= Memory map: ========\n")); int fd2 = open_not_cancel_2 ("/proc/self/maps", O_RDONLY); char buf[1024]; ssize_t n2; while ((n2 = read_not_cancel (fd2, buf, sizeof (buf))) > 0) if (write_not_cancel (fd, buf, n2) != n2) break; close_not_cancel_no_status (fd2); } } }
/* Open the database stored in FILE. If succesful, store either a pointer to the mapped file or a file handle for the file in H and return NSS_STATUS_SUCCESS. On failure, return the appropriate lookup status. */ enum nss_status internal_setent (const char *file, struct nss_db_map *mapping) { enum nss_status status = NSS_STATUS_UNAVAIL; int mode = O_RDONLY | O_LARGEFILE; #ifdef O_CLOEXEC mode |= O_CLOEXEC; #endif int fd = open_not_cancel_2 (file, mode); if (fd != -1) { struct nss_db_header header; if (read (fd, &header, sizeof (header)) == sizeof (header)) { mapping->header = mmap (NULL, header.allocate, PROT_READ, MAP_PRIVATE, fd, 0); mapping->len = header.allocate; if (mapping->header != MAP_FAILED) status = NSS_STATUS_SUCCESS; else if (errno == ENOMEM) status = NSS_STATUS_TRYAGAIN; } close_not_cancel_no_status (fd); } return status; }
internal_function __opendirat (int dfd, const char *name) { if (name[0] == '\0') { /* POSIX.1-1990 says an empty name gets ENOENT; but `open' might like it fine. */ __set_errno (ENOENT); return NULL; } int flags = O_RDONLY | O_NONBLOCK | O_DIRECTORY | O_CLOEXEC; int fd; #ifdef IS_IN_rtld assert (dfd == AT_FDCWD); fd = open_not_cancel_2 (name, flags); #else fd = openat_not_cancel_3 (dfd, name, flags); #endif if (fd < 0) return NULL; /* Extract the pointer to the descriptor structure. */ DIR *dirp = _hurd_fd_opendir (_hurd_fd_get (fd)); if (dirp == NULL) __close (fd); return dirp; }
/* Open a directory stream on NAME. */ DIR * __opendir (const char *name) { struct stat64 statbuf; if (__builtin_expect (name[0], '\1') == '\0') { /* POSIX.1-1990 says an empty name gets ENOENT; but `open' might like it fine. */ __set_errno (ENOENT); return NULL; } #ifdef O_DIRECTORY /* Test whether O_DIRECTORY works. */ if (o_directory_works == 0) tryopen_o_directory (); /* We can skip the expensive `stat' call if O_DIRECTORY works. */ if (o_directory_works < 0) #endif { /* We first have to check whether the name is for a directory. We cannot do this after the open() call since the open/close operation performed on, say, a tape device might have undesirable effects. */ if (__builtin_expect (__xstat64 (_STAT_VER, name, &statbuf), 0) < 0) return NULL; if (__builtin_expect (! S_ISDIR (statbuf.st_mode), 0)) { __set_errno (ENOTDIR); return NULL; } } int fd = open_not_cancel_2 (name, O_RDONLY|O_NDELAY|EXTRA_FLAGS|O_LARGEFILE); if (__builtin_expect (fd, 0) < 0) return NULL; /* Now make sure this really is a directory and nothing changed since the `stat' call. We do not have to perform the test for the descriptor being associated with a directory if we know the O_DIRECTORY flag is honored by the kernel. */ if (__builtin_expect (__fxstat64 (_STAT_VER, fd, &statbuf), 0) < 0) goto lose; #ifdef O_DIRECTORY if (o_directory_works <= 0) #endif { if (__builtin_expect (! S_ISDIR (statbuf.st_mode), 0)) { __set_errno (ENOTDIR); lose: close_not_cancel_no_status (fd); return NULL; } } return __alloc_dir (fd, true, &statbuf); }
int __get_nprocs () { /* XXX Here will come a test for the new system call. */ const size_t buffer_size = __libc_use_alloca (8192) ? 8192 : 512; char *buffer = alloca (buffer_size); char *buffer_end = buffer + buffer_size; char *cp = buffer_end; char *re = buffer_end; int result = 1; #ifdef O_CLOEXEC const int flags = O_RDONLY | O_CLOEXEC; #else const int flags = O_RDONLY; #endif /* The /proc/stat format is more uniform, use it by default. */ int fd = open_not_cancel_2 ("/proc/stat", flags); if (fd != -1) { result = 0; char *l; while ((l = next_line (fd, buffer, &cp, &re, buffer_end)) != NULL) /* The current format of /proc/stat has all the cpu* entries at the front. We assume here that stays this way. */ if (strncmp (l, "cpu", 3) != 0) break; else if (isdigit (l[3])) ++result; close_not_cancel_no_status (fd); } else { fd = open_not_cancel_2 ("/proc/cpuinfo", flags); if (fd != -1) { GET_NPROCS_PARSER (fd, buffer, cp, re, buffer_end, result); close_not_cancel_no_status (fd); } } return result; }
/* This function must be called with the LOCK held */ static void __set_unlocked(void) { if (static_fd < 0) { static_fd = open_not_cancel_2(current_file, O_RDWR | O_CLOEXEC); if (static_fd < 0) { static_fd = open_not_cancel_2(current_file, O_RDONLY | O_CLOEXEC); if (static_fd < 0) { return; /* static_fd remains < 0 */ } } #ifndef __ASSUME_O_CLOEXEC /* Make sure the file will be closed on exec() */ fcntl_not_cancel(static_fd, F_SETFD, FD_CLOEXEC); #endif return; } lseek(static_fd, 0, SEEK_SET); }
static void __updwtmp(const char *wtmp_file, const struct utmp *lutmp) { int fd; fd = open_not_cancel_2(wtmp_file, O_APPEND | O_WRONLY); if (fd >= 0) { if (lockf(fd, F_LOCK, 0) == 0) { write_not_cancel(fd, lutmp, sizeof(struct utmp)); lockf(fd, F_ULOCK, 0); close_not_cancel_no_status(fd); } } }
static void tryopen_o_directory (void) { int serrno = errno; int x = open_not_cancel_2 ("/dev/null", O_RDONLY|O_NDELAY|O_DIRECTORY); if (x >= 0) { close_not_cancel_no_status (x); o_directory_works = -1; } else if (errno != ENOTDIR) o_directory_works = -1; else o_directory_works = 1; __set_errno (serrno); }
int pthread_getname_np (pthread_t th, char *buf, size_t len) { const struct pthread *pd = (const struct pthread *) th; /* Unfortunately the kernel headers do not export the TASK_COMM_LEN macro. So we have to define it here. */ #define TASK_COMM_LEN 16 if (len < TASK_COMM_LEN) return ERANGE; if (pd == THREAD_SELF) return prctl (PR_GET_NAME, buf) ? errno : 0; #define FMT "/proc/self/task/%u/comm" char fname[sizeof (FMT) + 8]; sprintf (fname, FMT, (unsigned int) pd->tid); int fd = open_not_cancel_2 (fname, O_RDONLY); if (fd == -1) return errno; int res = 0; ssize_t n = TEMP_FAILURE_RETRY (read_not_cancel (fd, buf, len)); if (n < 0) res = errno; else { if (buf[n - 1] == '\n') buf[n - 1] = '\0'; else if (n == len) res = ERANGE; else buf[n] = '\0'; } close_not_cancel_no_status (fd); return res; }
/* Get file-specific information about FILE. */ long int __pathconf (const char *file, int name) { struct statfs fsbuf; int fd; int flags; switch (name) { case _PC_LINK_MAX: return __statfs_link_max (__statfs (file, &fsbuf), &fsbuf, file, -1); case _PC_FILESIZEBITS: return __statfs_filesize_max (__statfs (file, &fsbuf), &fsbuf); case _PC_2_SYMLINKS: return __statfs_symlinks (__statfs (file, &fsbuf), &fsbuf); case _PC_CHOWN_RESTRICTED: return __statfs_chown_restricted (__statfs (file, &fsbuf), &fsbuf); case _PC_PIPE_BUF: flags = O_RDONLY|O_NONBLOCK|O_NOCTTY; #ifdef O_CLOEXEC flags |= O_CLOEXEC; #endif fd = open_not_cancel_2 (file, flags); if (fd >= 0) { long int r = __fcntl (fd, F_GETPIPE_SZ); close_not_cancel_no_status (fd); if (r > 0) return r; } /* FALLTHROUGH */ default: return posix_pathconf (file, name); } }
/* Used like: return __statfs_chown_restricted (__statfs (name, &buf), &buf);*/ long int __statfs_chown_restricted (int result, const struct statfs *fsbuf) { if (result < 0) { if (errno == ENOSYS) /* Not possible, return the default value. */ return 1; /* Some error occured. */ return -1; } int fd; long int retval = 1; switch (fsbuf->f_type) { case XFS_SUPER_MAGIC: /* Read the value from /proc/sys/fs/xfs/restrict_chown. If we cannot read it default to assume the restriction is in place. */ fd = open_not_cancel_2 ("/proc/sys/fs/xfs/restrict_chown", O_RDONLY); if (fd != -1) { char buf[2]; if (TEMP_FAILURE_RETRY (read_not_cancel (fd, buf, 2)) == 2 && buf[0] >= '0' && buf[0] <= '1') retval = buf[0] - '0'; close_not_cancel_no_status (fd); } break; default: break; } return retval; }
int getloadavg (double loadavg[], int nelem) { int fd; fd = open_not_cancel_2 ("/proc/loadavg", O_RDONLY); if (fd < 0) return -1; else { char buf[65], *p; ssize_t nread; int i; nread = read_not_cancel (fd, buf, sizeof buf - 1); close_not_cancel_no_status (fd); if (nread <= 0) return -1; buf[nread - 1] = '\0'; if (nelem > 3) nelem = 3; p = buf; for (i = 0; i < nelem; ++i) { char *endp; loadavg[i] = __strtod_l (p, &endp, _nl_C_locobj_ptr); if (endp == p) /* This should not happen. The format of /proc/loadavg must have changed. Don't return with what we have, signal an error. */ return -1; p = endp; } return i; } }
/* Open a directory stream on NAME. */ DIR * __opendir (const char *name) { if (__glibc_unlikely (invalid_name (name))) return NULL; if (need_isdir_precheck ()) { /* We first have to check whether the name is for a directory. We cannot do this after the open() call since the open/close operation performed on, say, a tape device might have undesirable effects. */ struct stat64 statbuf; if (__glibc_unlikely (__xstat64 (_STAT_VER, name, &statbuf) < 0)) return NULL; if (__glibc_unlikely (! S_ISDIR (statbuf.st_mode))) { __set_errno (ENOTDIR); return NULL; } } return opendir_tail (open_not_cancel_2 (name, opendir_oflags ())); }
int __open_catalog (const char *cat_name, const char *nlspath, const char *env_var, __nl_catd catalog) { int fd = -1; struct stat64 st; int swapping; size_t cnt; size_t max_offset; size_t tab_size; const char *lastp; int result = -1; char *buf = NULL; if (strchr (cat_name, '/') != NULL || nlspath == NULL) fd = open_not_cancel_2 (cat_name, O_RDONLY); else { const char *run_nlspath = nlspath; #define ENOUGH(n) \ if (__glibc_unlikely (bufact + (n) >= bufmax)) \ { \ char *old_buf = buf; \ bufmax += (bufmax < 256 + (n)) ? 256 + (n) : bufmax; \ buf = realloc (buf, bufmax); \ if (__glibc_unlikely (buf == NULL)) \ { \ free (old_buf); \ return -1; \ } \ } /* The RUN_NLSPATH variable contains a colon separated list of descriptions where we expect to find catalogs. We have to recognize certain % substitutions and stop when we found the first existing file. */ size_t bufact; size_t bufmax = 0; size_t len; fd = -1; while (*run_nlspath != '\0') { bufact = 0; if (*run_nlspath == ':') { /* Leading colon or adjacent colons - treat same as %N. */ len = strlen (cat_name); ENOUGH (len); memcpy (&buf[bufact], cat_name, len); bufact += len; } else while (*run_nlspath != ':' && *run_nlspath != '\0') if (*run_nlspath == '%') { const char *tmp; ++run_nlspath; /* We have seen the `%'. */ switch (*run_nlspath++) { case 'N': /* Use the catalog name. */ len = strlen (cat_name); ENOUGH (len); memcpy (&buf[bufact], cat_name, len); bufact += len; break; case 'L': /* Use the current locale category value. */ len = strlen (env_var); ENOUGH (len); memcpy (&buf[bufact], env_var, len); bufact += len; break; case 'l': /* Use language element of locale category value. */ tmp = env_var; do { ENOUGH (1); buf[bufact++] = *tmp++; } while (*tmp != '\0' && *tmp != '_' && *tmp != '.'); break; case 't': /* Use territory element of locale category value. */ tmp = env_var; do ++tmp; while (*tmp != '\0' && *tmp != '_' && *tmp != '.'); if (*tmp == '_') { ++tmp; do { ENOUGH (1); buf[bufact++] = *tmp++; } while (*tmp != '\0' && *tmp != '.'); } break; case 'c': /* Use code set element of locale category value. */ tmp = env_var; do ++tmp; while (*tmp != '\0' && *tmp != '.'); if (*tmp == '.') { ++tmp; do { ENOUGH (1); buf[bufact++] = *tmp++; } while (*tmp != '\0'); } break; case '%': ENOUGH (1); buf[bufact++] = '%'; break; default: /* Unknown variable: ignore this path element. */ bufact = 0; while (*run_nlspath != '\0' && *run_nlspath != ':') ++run_nlspath; break; } } else { ENOUGH (1); buf[bufact++] = *run_nlspath++; } ENOUGH (1); buf[bufact] = '\0'; if (bufact != 0) { fd = open_not_cancel_2 (buf, O_RDONLY); if (fd >= 0) break; } ++run_nlspath; } } /* Avoid dealing with directories and block devices */ if (__builtin_expect (fd, 0) < 0) { free (buf); return -1; } if (__builtin_expect (__fxstat64 (_STAT_VER, fd, &st), 0) < 0) goto close_unlock_return; if (__builtin_expect (!S_ISREG (st.st_mode), 0) || (size_t) st.st_size < sizeof (struct catalog_obj)) { /* `errno' is not set correctly but the file is not usable. Use an reasonable error value. */ __set_errno (EINVAL); goto close_unlock_return; } catalog->file_size = st.st_size; #ifdef _POSIX_MAPPED_FILES # ifndef MAP_COPY /* Linux seems to lack read-only copy-on-write. */ # define MAP_COPY MAP_PRIVATE # endif # ifndef MAP_FILE /* Some systems do not have this flag; it is superfluous. */ # define MAP_FILE 0 # endif catalog->file_ptr = (struct catalog_obj *) __mmap (NULL, st.st_size, PROT_READ, MAP_FILE|MAP_COPY, fd, 0); if (__builtin_expect (catalog->file_ptr != (struct catalog_obj *) MAP_FAILED, 1)) /* Tell the world we managed to mmap the file. */ catalog->status = mmapped; else #endif /* _POSIX_MAPPED_FILES */ { /* mmap failed perhaps because the system call is not implemented. Try to load the file. */ size_t todo; catalog->file_ptr = malloc (st.st_size); if (catalog->file_ptr == NULL) goto close_unlock_return; todo = st.st_size; /* Save read, handle partial reads. */ do { size_t now = read_not_cancel (fd, (((char *) catalog->file_ptr) + (st.st_size - todo)), todo); if (now == 0 || now == (size_t) -1) { #ifdef EINTR if (now == (size_t) -1 && errno == EINTR) continue; #endif free ((void *) catalog->file_ptr); goto close_unlock_return; } todo -= now; } while (todo > 0); catalog->status = malloced; } /* Determine whether the file is a catalog file and if yes whether it is written using the correct byte order. Else we have to swap the values. */ if (__glibc_likely (catalog->file_ptr->magic == CATGETS_MAGIC)) swapping = 0; else if (catalog->file_ptr->magic == SWAPU32 (CATGETS_MAGIC)) swapping = 1; else { invalid_file: /* Invalid file. Free the resources and mark catalog as not usable. */ #ifdef _POSIX_MAPPED_FILES if (catalog->status == mmapped) __munmap ((void *) catalog->file_ptr, catalog->file_size); else #endif /* _POSIX_MAPPED_FILES */ free (catalog->file_ptr); goto close_unlock_return; } #define SWAP(x) (swapping ? SWAPU32 (x) : (x)) /* Get dimensions of the used hashing table. */ catalog->plane_size = SWAP (catalog->file_ptr->plane_size); catalog->plane_depth = SWAP (catalog->file_ptr->plane_depth); /* The file contains two versions of the pointer tables. Pick the right one for the local byte order. */ #if __BYTE_ORDER == __LITTLE_ENDIAN catalog->name_ptr = &catalog->file_ptr->name_ptr[0]; #elif __BYTE_ORDER == __BIG_ENDIAN catalog->name_ptr = &catalog->file_ptr->name_ptr[catalog->plane_size * catalog->plane_depth * 3]; #else # error Cannot handle __BYTE_ORDER byte order #endif /* The rest of the file contains all the strings. They are addressed relative to the position of the first string. */ catalog->strings = (const char *) &catalog->file_ptr->name_ptr[catalog->plane_size * catalog->plane_depth * 3 * 2]; /* Determine the largest string offset mentioned in the table. */ max_offset = 0; tab_size = 3 * catalog->plane_size * catalog->plane_depth; for (cnt = 2; cnt < tab_size; cnt += 3) if (catalog->name_ptr[cnt] > max_offset) max_offset = catalog->name_ptr[cnt]; /* Now we can check whether the file is large enough to contain the tables it says it contains. */ if ((size_t) st.st_size <= (sizeof (struct catalog_obj) + 2 * tab_size + max_offset)) /* The last string is not contained in the file. */ goto invalid_file; lastp = catalog->strings + max_offset; max_offset = (st.st_size - sizeof (struct catalog_obj) + 2 * tab_size + max_offset); while (*lastp != '\0') { if (--max_offset == 0) goto invalid_file; ++lastp; } /* We succeeded. */ result = 0; /* Release the lock again. */ close_unlock_return: close_not_cancel_no_status (fd); free (buf); return result; }
/* Get the value of the system variable NAME. */ long int __sysconf (int name) { const char *procfname = NULL; switch (name) { struct rlimit rlimit; #ifdef __NR_clock_getres case _SC_MONOTONIC_CLOCK: /* Check using the clock_getres system call. */ { struct timespec ts; INTERNAL_SYSCALL_DECL (err); int r; r = INTERNAL_SYSCALL (clock_getres, err, 2, CLOCK_MONOTONIC, &ts); return INTERNAL_SYSCALL_ERROR_P (r, err) ? -1 : _POSIX_VERSION; } #endif case _SC_CPUTIME: case _SC_THREAD_CPUTIME: return HAS_CPUCLOCK (name); case _SC_ARG_MAX: #if !__ASSUME_ARG_MAX_STACK_BASED /* Determine whether this is a kernel with an argument limit determined by the stack size. */ if (GLRO(dl_discover_osversion) () >= __LINUX_ARG_MAX_STACK_BASED_MIN_KERNEL) #endif /* Use getrlimit to get the stack limit. */ if (__getrlimit (RLIMIT_STACK, &rlimit) == 0) return MAX (legacy_ARG_MAX, rlimit.rlim_cur / 4); return legacy_ARG_MAX; case _SC_NGROUPS_MAX: /* Try to read the information from the /proc/sys/kernel/ngroups_max file. */ procfname = "/proc/sys/kernel/ngroups_max"; break; case _SC_SIGQUEUE_MAX: if (__getrlimit (RLIMIT_SIGPENDING, &rlimit) == 0) return rlimit.rlim_cur; /* The /proc/sys/kernel/rtsig-max file contains the answer. */ procfname = "/proc/sys/kernel/rtsig-max"; break; default: break; } if (procfname != NULL) { int fd = open_not_cancel_2 (procfname, O_RDONLY); if (fd != -1) { /* This is more than enough, the file contains a single integer. */ char buf[32]; ssize_t n; n = TEMP_FAILURE_RETRY (read_not_cancel (fd, buf, sizeof (buf) - 1)); close_not_cancel_no_status (fd); if (n > 0) { /* Terminate the string. */ buf[n] = '\0'; char *endp; long int res = strtol (buf, &endp, 10); if (endp != buf && (*endp == '\0' || *endp == '\n')) return res; } } } return posix_sysconf (name); }
int __get_nprocs (void) { static int cached_result = -1; static time_t timestamp; time_t now = time (NULL); time_t prev = timestamp; atomic_read_barrier (); if (now == prev && cached_result > -1) return cached_result; /* XXX Here will come a test for the new system call. */ const size_t buffer_size = __libc_use_alloca (8192) ? 8192 : 512; char *buffer = alloca (buffer_size); char *buffer_end = buffer + buffer_size; char *cp = buffer_end; char *re = buffer_end; const int flags = O_RDONLY | O_CLOEXEC; int fd = open_not_cancel_2 ("/sys/devices/system/cpu/online", flags); char *l; int result = 0; if (fd != -1) { l = next_line (fd, buffer, &cp, &re, buffer_end); if (l != NULL) do { char *endp; unsigned long int n = strtoul (l, &endp, 10); if (l == endp) { result = 0; break; } unsigned long int m = n; if (*endp == '-') { l = endp + 1; m = strtoul (l, &endp, 10); if (l == endp) { result = 0; break; } } result += m - n + 1; l = endp; while (l < re && isspace (*l)) ++l; } while (l < re); close_not_cancel_no_status (fd); if (result > 0) goto out; } cp = buffer_end; re = buffer_end; result = 1; /* The /proc/stat format is more uniform, use it by default. */ fd = open_not_cancel_2 ("/proc/stat", flags); if (fd != -1) { result = 0; while ((l = next_line (fd, buffer, &cp, &re, buffer_end)) != NULL) /* The current format of /proc/stat has all the cpu* entries at the front. We assume here that stays this way. */ if (strncmp (l, "cpu", 3) != 0) break; else if (isdigit (l[3])) ++result; close_not_cancel_no_status (fd); } else { fd = open_not_cancel_2 ("/proc/cpuinfo", flags); if (fd != -1) { GET_NPROCS_PARSER (fd, buffer, cp, re, buffer_end, result); close_not_cancel_no_status (fd); } } out: cached_result = result; atomic_write_barrier (); timestamp = now; return result; }
/* Open a directory stream on NAME. */ DIR * __opendir (const char *name) { DIR *dirp; struct stat64 statbuf; int fd; size_t allocation; int save_errno; if (__builtin_expect (name[0], '\1') == '\0') { /* POSIX.1-1990 says an empty name gets ENOENT; but `open' might like it fine. */ __set_errno (ENOENT); return NULL; } #ifdef O_DIRECTORY /* Test whether O_DIRECTORY works. */ if (o_directory_works == 0) tryopen_o_directory (); /* We can skip the expensive `stat' call if O_DIRECTORY works. */ if (o_directory_works < 0) #endif { /* We first have to check whether the name is for a directory. We cannot do this after the open() call since the open/close operation performed on, say, a tape device might have undesirable effects. */ if (__builtin_expect (__xstat64 (_STAT_VER, name, &statbuf), 0) < 0) return NULL; if (__builtin_expect (! S_ISDIR (statbuf.st_mode), 0)) { __set_errno (ENOTDIR); return NULL; } } fd = open_not_cancel_2 (name, O_RDONLY|O_NDELAY|EXTRA_FLAGS|O_LARGEFILE); if (__builtin_expect (fd, 0) < 0) return NULL; /* Now make sure this really is a directory and nothing changed since the `stat' call. We do not have to perform the test for the descriptor being associated with a directory if we know the O_DIRECTORY flag is honored by the kernel. */ if (__builtin_expect (__fxstat64 (_STAT_VER, fd, &statbuf), 0) < 0) goto lose; #ifdef O_DIRECTORY if (o_directory_works <= 0) #endif { if (__builtin_expect (! S_ISDIR (statbuf.st_mode), 0)) { save_errno = ENOTDIR; goto lose; } } if (__builtin_expect (__fcntl (fd, F_SETFD, FD_CLOEXEC), 0) < 0) goto lose; #ifdef _STATBUF_ST_BLKSIZE if (__builtin_expect ((size_t) statbuf.st_blksize >= sizeof (struct dirent64), 1)) allocation = statbuf.st_blksize; else #endif allocation = (BUFSIZ < sizeof (struct dirent64) ? sizeof (struct dirent64) : BUFSIZ); const int pad = -sizeof (DIR) % __alignof__ (struct dirent64); dirp = (DIR *) malloc (sizeof (DIR) + allocation + pad); if (dirp == NULL) lose: { save_errno = errno; close_not_cancel_no_status (fd); __set_errno (save_errno); return NULL; } memset (dirp, '\0', sizeof (DIR)); dirp->data = (char *) (dirp + 1) + pad; dirp->allocation = allocation; dirp->fd = fd; __libc_lock_init (dirp->lock); return dirp; }
internal_function __opendirat (int dfd, const char *name) { struct stat64 statbuf; struct stat64 *statp = NULL; if (__builtin_expect (name[0], '\1') == '\0') { /* POSIX.1-1990 says an empty name gets ENOENT; but `open' might like it fine. */ __set_errno (ENOENT); return NULL; } #ifdef O_DIRECTORY /* Test whether O_DIRECTORY works. */ if (o_directory_works == 0) tryopen_o_directory (); /* We can skip the expensive `stat' call if O_DIRECTORY works. */ if (o_directory_works < 0) #endif { /* We first have to check whether the name is for a directory. We cannot do this after the open() call since the open/close operation performed on, say, a tape device might have undesirable effects. */ if (__builtin_expect (__xstat64 (_STAT_VER, name, &statbuf), 0) < 0) return NULL; if (__builtin_expect (! S_ISDIR (statbuf.st_mode), 0)) { __set_errno (ENOTDIR); return NULL; } } int flags = O_RDONLY|O_NDELAY|EXTRA_FLAGS|O_LARGEFILE; #ifdef O_CLOEXEC flags |= O_CLOEXEC; #endif int fd; #ifdef IS_IN_rtld assert (dfd == AT_FDCWD); fd = open_not_cancel_2 (name, flags); #else fd = openat_not_cancel_3 (dfd, name, flags); #endif if (__builtin_expect (fd, 0) < 0) return NULL; #ifdef O_DIRECTORY if (o_directory_works <= 0) #endif { /* Now make sure this really is a directory and nothing changed since the `stat' call. */ if (__builtin_expect (__fxstat64 (_STAT_VER, fd, &statbuf), 0) < 0) goto lose; if (__builtin_expect (! S_ISDIR (statbuf.st_mode), 0)) { __set_errno (ENOTDIR); lose: close_not_cancel_no_status (fd); return NULL; } statp = &statbuf; } return __alloc_dir (fd, true, 0, statp); }
static int setutent_file (void) { if (file_fd < 0) { const char *file_name; file_name = TRANSFORM_UTMP_FILE_NAME (__libc_utmp_file_name); #ifdef O_CLOEXEC # define O_flags O_LARGEFILE | O_CLOEXEC #else # define O_flags O_LARGEFILE #endif file_writable = false; file_fd = open_not_cancel_2 (file_name, O_RDONLY | O_flags); if (file_fd == -1) return 0; #ifndef __ASSUME_O_CLOEXEC # ifdef O_CLOEXEC if (__have_o_cloexec <= 0) # endif { /* We have to make sure the file is `closed on exec'. */ int result = fcntl_not_cancel (file_fd, F_GETFD, 0); if (result >= 0) { # ifdef O_CLOEXEC if (__have_o_cloexec == 0) __have_o_cloexec = (result & FD_CLOEXEC) ? 1 : -1; if (__have_o_cloexec < 0) # endif result = fcntl_not_cancel (file_fd, F_SETFD, result | FD_CLOEXEC); } if (result == -1) { close_not_cancel_no_status (file_fd); return 0; } } #endif } __lseek64 (file_fd, 0, SEEK_SET); file_offset = 0; /* Make sure the entry won't match. */ #if _HAVE_UT_TYPE - 0 last_entry.ut_type = -1; #else last_entry.ut_line[0] = '\177'; # if _HAVE_UT_ID - 0 last_entry.ut_id[0] = '\0'; # endif #endif return 1; }