/* 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_nocancel_nostatus (fd); } __closedir (dir); int nullfd = __open_nocancel (_PATH_DEVNULL, O_RDONLY); assert (nullfd == STDIN_FILENO); nullfd = __open_nocancel (_PATH_DEVNULL, O_WRONLY); assert (nullfd == STDOUT_FILENO); __dup2 (STDOUT_FILENO, STDERR_FILENO); } }
internal_function attribute_compat_text_section getttyname (const char *dev, dev_t mydev, ino64_t myino, int save, int *dostat) { static size_t namelen; struct stat64 st; DIR *dirstream; struct dirent64 *d; size_t devlen = strlen (dev) + 1; dirstream = __opendir (dev); if (dirstream == NULL) { *dostat = -1; return NULL; } while ((d = __readdir64 (dirstream)) != NULL) if ((d->d_fileno == myino || *dostat) && strcmp (d->d_name, "stdin") && strcmp (d->d_name, "stdout") && strcmp (d->d_name, "stderr")) { size_t dlen = _D_ALLOC_NAMLEN (d); if (devlen + dlen > namelen) { free (getttyname_name); namelen = 2 * (devlen + dlen); /* Big enough. */ getttyname_name = malloc (namelen); if (! getttyname_name) { *dostat = -1; /* Perhaps it helps to free the directory stream buffer. */ (void) __closedir (dirstream); return NULL; } *((char *) __mempcpy (getttyname_name, dev, devlen - 1)) = '/'; } memcpy (&getttyname_name[devlen], d->d_name, dlen); if (__xstat64 (_STAT_VER, getttyname_name, &st) == 0 #ifdef _STATBUF_ST_RDEV && S_ISCHR (st.st_mode) && st.st_rdev == mydev #else && d->d_fileno == myino && st.st_dev == mydev #endif ) { (void) __closedir (dirstream); #if 0 __ttyname = getttyname_name; #endif __set_errno (save); return getttyname_name; } } (void) __closedir (dirstream); __set_errno (save); return NULL; }
static int internal_function attribute_compat_text_section getttyname_r (char *buf, size_t buflen, dev_t mydev, ino64_t myino, int save, int *dostat) { struct stat64 st; DIR *dirstream; struct dirent64 *d; size_t devlen = strlen (buf); dirstream = __opendir (buf); if (dirstream == NULL) { *dostat = -1; return errno; } while ((d = __readdir64 (dirstream)) != NULL) if ((d->d_fileno == myino || *dostat) && strcmp (d->d_name, "stdin") && strcmp (d->d_name, "stdout") && strcmp (d->d_name, "stderr")) { char *cp; size_t needed = _D_EXACT_NAMLEN (d) + 1; if (needed > buflen) { *dostat = -1; (void) __closedir (dirstream); __set_errno (ERANGE); return ERANGE; } cp = __stpncpy (buf + devlen, d->d_name, needed); cp[0] = '\0'; if (__xstat64 (_STAT_VER, buf, &st) == 0 #ifdef _STATBUF_ST_RDEV && S_ISCHR (st.st_mode) && st.st_rdev == mydev #else && d->d_fileno == myino && st.st_dev == mydev #endif ) { (void) __closedir (dirstream); __set_errno (save); return 0; } } (void) __closedir (dirstream); __set_errno (save); /* It is not clear what to return in this case. `isatty' says FD refers to a TTY but no entry in /dev has this inode. */ return ENOTTY; }
/* On some architectures it is possible to distinguish between configured and active cpus. */ int __get_nprocs_conf () { /* XXX Here will come a test for the new system call. */ /* Try to use the sysfs filesystem. It has actual information about online processors. */ DIR *dir = __opendir ("/sys/devices/system/cpu"); if (dir != NULL) { int count = 0; struct dirent64 *d; while ((d = __readdir64 (dir)) != NULL) /* NB: the sysfs has d_type support. */ if (d->d_type == DT_DIR && strncmp (d->d_name, "cpu", 3) == 0) { char *endp; unsigned long int nr = strtoul (d->d_name + 3, &endp, 10); if (nr != ULONG_MAX && endp != d->d_name + 3 && *endp == '\0') ++count; } __closedir (dir); return count; } int result = 1; #ifdef GET_NPROCS_CONF_PARSER /* If we haven't found an appropriate entry return 1. */ FILE *fp = fopen ("/proc/cpuinfo", "rce"); if (fp != NULL) { char buffer[8192]; /* No threads use this stream. */ __fsetlocking (fp, FSETLOCKING_BYCALLER); GET_NPROCS_CONF_PARSER (fp, buffer, result); fclose (fp); } #else result = __get_nprocs (); #endif return result; }
/* Read a directory entry from DIRP. */ struct dirent * __readdir (DIR *dirp) { struct dirent64 *entry64 = __readdir64 (dirp); if (sizeof (struct dirent64) == sizeof (struct dirent)) /* We should in fact just be an alias to readdir64 on this machine. */ return (struct dirent *) entry64; /* These are all compile-time constants. We know that d_ino is the first member and that the layout of the following members matches exactly in both structures. */ assert (offsetof (struct dirent, d_ino) == 0); assert (offsetof (struct dirent64, d_ino) == 0); # define MATCH(memb) \ assert (offsetof (struct dirent64, memb) - sizeof (entry64->d_ino) \ == offsetof (struct dirent, memb) - sizeof (ino_t)) MATCH (d_reclen); MATCH (d_type); MATCH (d_namlen); # undef MATCH if (entry64 == NULL) return NULL; struct dirent *const entry = ((void *) (&entry64->d_ino + 1) - sizeof entry->d_ino); const ino_t d_ino = entry64->d_ino; if (d_ino != entry64->d_ino) { __set_errno (EOVERFLOW); return NULL; } # if BYTE_ORDER != BIG_ENDIAN /* We just skipped over the zero high word. */ entry->d_ino = d_ino; /* ... or the nonzero low word, swap it. */ # endif entry->d_reclen -= sizeof entry64->d_ino - sizeof entry->d_ino; return entry; }
ftw_dir (struct ftw_data *data, struct STAT *st, struct dir_data *old_dir) { struct dir_data dir; struct dirent64 *d; int previous_base = data->ftw.base; int result; char *startp; /* Open the stream for this directory. This might require that another stream has to be closed. */ result = open_dir_stream (old_dir == NULL ? NULL : &old_dir->streamfd, data, &dir); if (result != 0) { if (errno == EACCES) /* We cannot read the directory. Signal this with a special flag. */ result = (*data->func) (data->dirbuf, st, FTW_DNR, &data->ftw); return result; } /* First, report the directory (if not depth-first). */ if (!(data->flags & FTW_DEPTH)) { result = (*data->func) (data->dirbuf, st, FTW_D, &data->ftw); if (result != 0) { int save_err; fail: save_err = errno; __closedir (dir.stream); dir.streamfd = -1; __set_errno (save_err); if (data->actdir-- == 0) data->actdir = data->maxdir - 1; data->dirstreams[data->actdir] = NULL; return result; } } /* If necessary, change to this directory. */ if (data->flags & FTW_CHDIR) { if (__fchdir (__dirfd (dir.stream)) < 0) { result = -1; goto fail; } } /* Next, update the `struct FTW' information. */ ++data->ftw.level; startp = __rawmemchr (data->dirbuf, '\0'); /* There always must be a directory name. */ assert (startp != data->dirbuf); if (startp[-1] != '/') *startp++ = '/'; data->ftw.base = startp - data->dirbuf; while (dir.stream != NULL && (d = __readdir64 (dir.stream)) != NULL) { int d_type = DT_UNKNOWN; #ifdef _DIRENT_HAVE_D_TYPE d_type = d->d_type; #endif result = process_entry (data, &dir, d->d_name, NAMLEN (d), d_type); if (result != 0) break; } if (dir.stream != NULL) { /* The stream is still open. I.e., we did not need more descriptors. Simply close the stream now. */ int save_err = errno; assert (dir.content == NULL); __closedir (dir.stream); dir.streamfd = -1; __set_errno (save_err); if (data->actdir-- == 0) data->actdir = data->maxdir - 1; data->dirstreams[data->actdir] = NULL; } else { int save_err; char *runp = dir.content; while (result == 0 && *runp != '\0') { char *endp = strchr (runp, '\0'); // XXX Should store the d_type values as well?! result = process_entry (data, &dir, runp, endp - runp, DT_UNKNOWN); runp = endp + 1; } save_err = errno; free (dir.content); __set_errno (save_err); } if ((data->flags & FTW_ACTIONRETVAL) && result == FTW_SKIP_SIBLINGS) result = 0; /* Prepare the return, revert the `struct FTW' information. */ data->dirbuf[data->ftw.base - 1] = '\0'; --data->ftw.level; data->ftw.base = previous_base; /* Finally, if we process depth-first report the directory. */ if (result == 0 && (data->flags & FTW_DEPTH)) result = (*data->func) (data->dirbuf, st, FTW_DP, &data->ftw); if (old_dir && (data->flags & FTW_CHDIR) && (result == 0 || ((data->flags & FTW_ACTIONRETVAL) && (result != -1 && result != FTW_STOP)))) { /* Change back to the parent directory. */ int done = 0; if (old_dir->stream != NULL) if (__fchdir (__dirfd (old_dir->stream)) == 0) done = 1; if (!done) { if (data->ftw.base == 1) { if (__chdir ("/") < 0) result = -1; } else if (__chdir ("..") < 0) result = -1; } } return result; }
open_dir_stream (int *dfdp, struct ftw_data *data, struct dir_data *dirp) { int result = 0; if (data->dirstreams[data->actdir] != NULL) { /* Oh, oh. We must close this stream. Get all remaining entries and store them as a list in the `content' member of the `struct dir_data' variable. */ size_t bufsize = 1024; char *buf = malloc (bufsize); if (buf == NULL) result = -1; else { DIR *st = data->dirstreams[data->actdir]->stream; struct dirent64 *d; size_t actsize = 0; while ((d = __readdir64 (st)) != NULL) { size_t this_len = NAMLEN (d); if (actsize + this_len + 2 >= bufsize) { char *newp; bufsize += MAX (1024, 2 * this_len); newp = (char *) realloc (buf, bufsize); if (newp == NULL) { /* No more memory. */ int save_err = errno; free (buf); __set_errno (save_err); return -1; } buf = newp; } *((char *) __mempcpy (buf + actsize, d->d_name, this_len)) = '\0'; actsize += this_len + 1; } /* Terminate the list with an additional NUL byte. */ buf[actsize++] = '\0'; /* Shrink the buffer to what we actually need. */ data->dirstreams[data->actdir]->content = realloc (buf, actsize); if (data->dirstreams[data->actdir]->content == NULL) { int save_err = errno; free (buf); __set_errno (save_err); result = -1; } else { __closedir (st); data->dirstreams[data->actdir]->stream = NULL; data->dirstreams[data->actdir]->streamfd = -1; data->dirstreams[data->actdir] = NULL; } } } /* Open the new stream. */ if (result == 0) { assert (data->dirstreams[data->actdir] == NULL); if (dfdp != NULL && *dfdp != -1) { int fd = __openat64_nocancel (*dfdp, data->dirbuf + data->ftw.base, O_RDONLY | O_DIRECTORY | O_NDELAY); dirp->stream = NULL; if (fd != -1 && (dirp->stream = __fdopendir (fd)) == NULL) __close_nocancel_nostatus (fd); } else { const char *name; if (data->flags & FTW_CHDIR) { name = data->dirbuf + data->ftw.base; if (name[0] == '\0') name = "."; } else name = data->dirbuf; dirp->stream = __opendir (name); } if (dirp->stream == NULL) result = -1; else { dirp->streamfd = __dirfd (dirp->stream); dirp->content = NULL; data->dirstreams[data->actdir] = dirp; if (++data->actdir == data->maxdir) data->actdir = 0; } } return result; }