/* Return the pathname of the terminal FD is open on, or NULL on errors. The returned storage is good only until the next call to this function. */ char * ttyname (int fd) { struct stat64 st, st1; int dostat = 0; char *name; int save = errno; struct termios term; /* isatty check, tcgetattr is used because it sets the correct errno (EBADF resp. ENOTTY) on error. */ if (__builtin_expect (__tcgetattr (fd, &term) < 0, 0)) return NULL; if (__fxstat64 (_STAT_VER, fd, &st) < 0) return NULL; if (__xstat64 (_STAT_VER, "/dev/pts", &st1) == 0 && S_ISDIR (st1.st_mode)) { #ifdef _STATBUF_ST_RDEV name = getttyname ("/dev/pts", st.st_rdev, st.st_ino, save, &dostat); #else name = getttyname ("/dev/pts", st.st_dev, st.st_ino, save, &dostat); #endif } else { __set_errno (save); name = NULL; } if (!name && dostat != -1) { #ifdef _STATBUF_ST_RDEV name = getttyname ("/dev", st.st_rdev, st.st_ino, save, &dostat); #else name = getttyname ("/dev", st.st_dev, st.st_ino, save, &dostat); #endif } if (!name && dostat != -1) { dostat = 1; #ifdef _STATBUF_ST_RDEV name = getttyname ("/dev", st.st_rdev, st.st_ino, save, &dostat); #else name = getttyname ("/dev", st.st_dev, st.st_ino, save, &dostat); #endif } return name; }
static int internal_function getttyname_r (char *buf, size_t buflen, dev_t mydev, ino64_t myino, int save) { struct stat64 st; DIR *dirstream; struct dirent *d; size_t devlen = strlen (buf); dirstream = __opendir (buf); if (dirstream == NULL) { return errno; } while ((d = __readdir (dirstream)) != NULL) if (d->d_fileno == myino) { char *cp; size_t needed = _D_EXACT_NAMLEN (d) + 1; if (needed > buflen) { (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; }
static long int __sysconf_check_spec (const char *spec) { int save_errno = errno; const char *getconf_dir = __libc_secure_getenv ("GETCONF_DIR") ?: GETCONF_DIR; size_t getconf_dirlen = strlen (getconf_dir); size_t speclen = strlen (spec); char name[getconf_dirlen + sizeof ("/POSIX_V6_") + speclen]; memcpy (mempcpy (mempcpy (name, getconf_dir, getconf_dirlen), "/POSIX_V6_", sizeof ("/POSIX_V6_") - 1), spec, speclen + 1); struct stat64 st; long int ret = __xstat64 (_STAT_VER, name, &st) >= 0 ? 1 : -1; __set_errno (save_errno); return ret; }
/* 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 stat64 (const char *file, struct stat64 *buf) { return __xstat64 (_STAT_VER, file, buf); }
/* Store at most BUFLEN character of the pathname of the terminal FD is open on in BUF. Return 0 on success, otherwise an error number. */ int __ttyname_r (int fd, char *buf, size_t buflen) { char procname[30]; struct stat64 st, st1; int dostat = 0; int save = errno; /* Test for the absolute minimal size. This makes life easier inside the loop. */ if (!buf) { __set_errno (EINVAL); return EINVAL; } if (buflen < sizeof ("/dev/pts/")) { __set_errno (ERANGE); return ERANGE; } /* isatty check, tcgetattr is used because it sets the correct errno (EBADF resp. ENOTTY) on error. */ struct termios term; if (__glibc_unlikely (__tcgetattr (fd, &term) < 0)) return errno; if (__fxstat64 (_STAT_VER, fd, &st) < 0) return errno; /* We try using the /proc filesystem. */ *_fitoa_word (fd, __stpcpy (procname, "/proc/self/fd/"), 10, 0) = '\0'; ssize_t ret = __readlink (procname, buf, buflen - 1); if (__glibc_unlikely (ret == -1 && errno == ENAMETOOLONG)) { __set_errno (ERANGE); return ERANGE; } if (__glibc_likely (ret != -1)) { #define UNREACHABLE_LEN strlen ("(unreachable)") if (ret > UNREACHABLE_LEN && memcmp (buf, "(unreachable)", UNREACHABLE_LEN) == 0) { memmove (buf, buf + UNREACHABLE_LEN, ret - UNREACHABLE_LEN); ret -= UNREACHABLE_LEN; } /* readlink need not terminate the string. */ buf[ret] = '\0'; /* Verify readlink result, fall back on iterating through devices. */ if (buf[0] == '/' && __xstat64 (_STAT_VER, buf, &st1) == 0 #ifdef _STATBUF_ST_RDEV && S_ISCHR (st1.st_mode) && st1.st_rdev == st.st_rdev #else && st1.st_ino == st.st_ino && st1.st_dev == st.st_dev #endif ) return 0; } /* Prepare the result buffer. */ memcpy (buf, "/dev/pts/", sizeof ("/dev/pts/")); buflen -= sizeof ("/dev/pts/") - 1; if (__xstat64 (_STAT_VER, buf, &st1) == 0 && S_ISDIR (st1.st_mode)) { #ifdef _STATBUF_ST_RDEV ret = getttyname_r (buf, buflen, st.st_rdev, st.st_ino, save, &dostat); #else ret = getttyname_r (buf, buflen, st.st_dev, st.st_ino, save, &dostat); #endif } else { __set_errno (save); ret = ENOENT; } if (ret && dostat != -1) { buf[sizeof ("/dev/") - 1] = '\0'; buflen += sizeof ("pts/") - 1; #ifdef _STATBUF_ST_RDEV ret = getttyname_r (buf, buflen, st.st_rdev, st.st_ino, save, &dostat); #else ret = getttyname_r (buf, buflen, st.st_dev, st.st_ino, save, &dostat); #endif } if (ret && dostat != -1) { buf[sizeof ("/dev/") - 1] = '\0'; dostat = 1; #ifdef _STATBUF_ST_RDEV ret = getttyname_r (buf, buflen, st.st_rdev, st.st_ino, save, &dostat); #else ret = getttyname_r (buf, buflen, st.st_dev, st.st_ino, save, &dostat); #endif } return ret; }
/* 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; }
int attribute_hidden stat64 (const char *file, struct stat64 *buf) { return __xstat64 (_STAT_VER, file, buf); }
__attribute__((weak)) int stat64(const char *path, struct stat64 *buf) { return __xstat64(1, path, buf); }
/* Get file-specific information about PATH. */ long int __pathconf (const char *path, int name) { if (path[0] == '\0') { __set_errno (ENOENT); return -1; } switch (name) { default: __set_errno (EINVAL); return -1; case _PC_LINK_MAX: #ifdef LINK_MAX return LINK_MAX; #else return -1; #endif case _PC_MAX_CANON: #ifdef MAX_CANON return MAX_CANON; #else return -1; #endif case _PC_MAX_INPUT: #ifdef MAX_INPUT return MAX_INPUT; #else return -1; #endif case _PC_NAME_MAX: #ifdef NAME_MAX { struct statvfs64 sv; int save_errno = errno; if (__statvfs64 (path, &sv) < 0) { if (errno == ENOSYS) { errno = save_errno; return NAME_MAX; } return -1; } else { return sv.f_namemax; } } #else return -1; #endif case _PC_PATH_MAX: #ifdef PATH_MAX return PATH_MAX; #else return -1; #endif case _PC_PIPE_BUF: #ifdef PIPE_BUF return PIPE_BUF; #else return -1; #endif case _PC_CHOWN_RESTRICTED: #ifdef _POSIX_CHOWN_RESTRICTED return _POSIX_CHOWN_RESTRICTED; #else return -1; #endif case _PC_NO_TRUNC: #ifdef _POSIX_NO_TRUNC return _POSIX_NO_TRUNC; #else return -1; #endif case _PC_VDISABLE: #ifdef _POSIX_VDISABLE return _POSIX_VDISABLE; #else return -1; #endif case _PC_SYNC_IO: #ifdef _POSIX_SYNC_IO return _POSIX_SYNC_IO; #else return -1; #endif case _PC_ASYNC_IO: #ifdef _POSIX_ASYNC_IO { /* AIO is only allowed on regular files and block devices. */ struct stat64 st; if (__xstat64 (_STAT_VER, path, &st) < 0 || (! S_ISREG (st.st_mode) && ! S_ISBLK (st.st_mode))) return -1; else return 1; } #else return -1; #endif case _PC_PRIO_IO: #ifdef _POSIX_PRIO_IO return _POSIX_PRIO_IO; #else return -1; #endif case _PC_SOCK_MAXBUF: #ifdef SOCK_MAXBUF return SOCK_MAXBUF; #else return -1; #endif case _PC_FILESIZEBITS: #ifdef FILESIZEBITS return FILESIZEBITS; #else /* We let platforms with larger file sizes overwrite this value. */ return 32; #endif case _PC_REC_INCR_XFER_SIZE: /* XXX It is not entirely clear what the limit is supposed to do. What is incremented? */ return -1; case _PC_REC_MAX_XFER_SIZE: /* XXX It is not entirely clear what the limit is supposed to do. In general there is no top limit of the number of bytes which case be transported at once. */ return -1; case _PC_REC_MIN_XFER_SIZE: { /* XXX It is not entirely clear what the limit is supposed to do. I assume this is the block size of the filesystem. */ struct statvfs64 sv; if (__statvfs64 (path, &sv) < 0) return -1; return sv.f_bsize; } case _PC_REC_XFER_ALIGN: { /* XXX It is not entirely clear what the limit is supposed to do. I assume that the number should reflect the minimal block alignment. */ struct statvfs64 sv; if (__statvfs64 (path, &sv) < 0) return -1; return sv.f_frsize; } case _PC_ALLOC_SIZE_MIN: { /* XXX It is not entirely clear what the limit is supposed to do. I assume that the number should reflect the minimal block alignment. */ struct statvfs64 sv; if (__statvfs64 (path, &sv) < 0) return -1; return sv.f_frsize; } case _PC_SYMLINK_MAX: /* In general there are no limits. If a system has one it should overwrite this case. */ return -1; case _PC_2_SYMLINKS: /* Unix systems generally have symlinks. */ return 1; } }
/* 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 flags = O_RDONLY|O_NDELAY|EXTRA_FLAGS|O_LARGEFILE; #ifdef O_CLOEXEC flags |= O_CLOEXEC; #endif int fd = open_not_cancel_2 (name, flags); 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); }
/* Return the pathname of the terminal FD is open on, or NULL on errors. The returned storage is good only until the next call to this function. */ char * ttyname (int fd) { static size_t buflen; char procname[30]; struct stat64 st, st1; int dostat = 0; char *name; int save = errno; struct termios term; /* isatty check, tcgetattr is used because it sets the correct errno (EBADF resp. ENOTTY) on error. */ if (__glibc_unlikely (__tcgetattr (fd, &term) < 0)) return NULL; if (__fxstat64 (_STAT_VER, fd, &st) < 0) return NULL; /* We try using the /proc filesystem. */ *_fitoa_word (fd, __stpcpy (procname, "/proc/self/fd/"), 10, 0) = '\0'; if (buflen == 0) { buflen = 4095; ttyname_buf = (char *) malloc (buflen + 1); if (ttyname_buf == NULL) { buflen = 0; return NULL; } } ssize_t len = __readlink (procname, ttyname_buf, buflen); if (__glibc_likely (len != -1)) { if ((size_t) len >= buflen) return NULL; #define UNREACHABLE_LEN strlen ("(unreachable)") if (len > UNREACHABLE_LEN && memcmp (ttyname_buf, "(unreachable)", UNREACHABLE_LEN) == 0) { memmove (ttyname_buf, ttyname_buf + UNREACHABLE_LEN, len - UNREACHABLE_LEN); len -= UNREACHABLE_LEN; } /* readlink need not terminate the string. */ ttyname_buf[len] = '\0'; /* Verify readlink result, fall back on iterating through devices. */ if (ttyname_buf[0] == '/' && __xstat64 (_STAT_VER, ttyname_buf, &st1) == 0 #ifdef _STATBUF_ST_RDEV && S_ISCHR (st1.st_mode) && st1.st_rdev == st.st_rdev #else && st1.st_ino == st.st_ino && st1.st_dev == st.st_dev #endif ) return ttyname_buf; } if (__xstat64 (_STAT_VER, "/dev/pts", &st1) == 0 && S_ISDIR (st1.st_mode)) { #ifdef _STATBUF_ST_RDEV name = getttyname ("/dev/pts", st.st_rdev, st.st_ino, save, &dostat); #else name = getttyname ("/dev/pts", st.st_dev, st.st_ino, save, &dostat); #endif } else { __set_errno (save); name = NULL; } if (!name && dostat != -1) { #ifdef _STATBUF_ST_RDEV name = getttyname ("/dev", st.st_rdev, st.st_ino, save, &dostat); #else name = getttyname ("/dev", st.st_dev, st.st_ino, save, &dostat); #endif } if (!name && dostat != -1) { dostat = 1; #ifdef _STATBUF_ST_RDEV name = getttyname ("/dev", st.st_rdev, st.st_ino, save, &dostat); #else name = getttyname ("/dev", st.st_dev, st.st_ino, save, &dostat); #endif } return name; }
int __ptsname_internal (int fd, char *buf, size_t buflen, struct stat64 *stp) { int save_errno = errno; unsigned int ptyno; if (buf == NULL) { __set_errno (EINVAL); return EINVAL; } if (!__isatty (fd)) { __set_errno (ENOTTY); return ENOTTY; } #ifdef TIOCGPTN if (__ioctl (fd, TIOCGPTN, &ptyno) == 0) { /* Buffer we use to print the number in. For a maximum size for `int' of 8 bytes we never need more than 20 digits. */ char numbuf[21]; const char *devpts = _PATH_DEVPTS; const size_t devptslen = strlen (_PATH_DEVPTS); char *p; numbuf[sizeof (numbuf) - 1] = '\0'; p = _itoa_word (ptyno, &numbuf[sizeof (numbuf) - 1], 10, 0); if (buflen < devptslen + (&numbuf[sizeof (numbuf)] - p)) { __set_errno (ERANGE); return ERANGE; } memcpy (__stpcpy (buf, devpts), p, &numbuf[sizeof (numbuf)] - p); } else if (errno != EINVAL) return errno; else #endif { char *p; if (buflen < strlen (_PATH_TTY) + 3) { __set_errno (ERANGE); return ERANGE; } if (__fxstat64 (_STAT_VER, fd, stp) < 0) return errno; /* Check if FD really is a master pseudo terminal. */ if (! MASTER_P (stp->st_rdev)) { __set_errno (ENOTTY); return ENOTTY; } ptyno = minor (stp->st_rdev); if (ptyno / 16 >= strlen (__libc_ptyname1)) { __set_errno (ENOTTY); return ENOTTY; } p = __stpcpy (buf, _PATH_TTY); p[0] = __libc_ptyname1[ptyno / 16]; p[1] = __libc_ptyname2[ptyno % 16]; p[2] = '\0'; } if (__xstat64 (_STAT_VER, buf, stp) < 0) return errno; /* Check if the name we're about to return really corresponds to a slave pseudo terminal. */ if (! S_ISCHR (stp->st_mode) || ! SLAVE_P (stp->st_rdev)) { /* This really is a configuration problem. */ __set_errno (ENOTTY); return ENOTTY; } __set_errno (save_errno); return 0; }
/* Store at most BUFLEN character of the pathname of the terminal FD is open on in BUF. Return 0 on success, otherwise an error number. */ int __ttyname_r (int fd, char *buf, size_t buflen) { char procname[30]; struct stat64 st, st1; int dostat = 0; int save = errno; int ret; /* Test for the absolute minimal size. This makes life easier inside the loop. */ if (!buf) { __set_errno (EINVAL); return EINVAL; } if (buflen < sizeof ("/dev/pts/")) { __set_errno (ERANGE); return ERANGE; } /* We try using the /proc filesystem. */ *_fitoa_word (fd, __stpcpy (procname, "/proc/self/fd/"), 10, 0) = '\0'; ret = __readlink (procname, buf, buflen - 1); if (ret == -1 && errno == ENOENT) { __set_errno (EBADF); return EBADF; } if (!__isatty (fd)) { __set_errno (ENOTTY); return ENOTTY; } if (ret == -1 && errno == ENAMETOOLONG) { __set_errno (ERANGE); return ERANGE; } if (ret != -1 && buf[0] != '[') { buf[ret] = '\0'; return 0; } if (__fxstat64 (_STAT_VER, fd, &st) < 0) return errno; /* Prepare the result buffer. */ memcpy (buf, "/dev/pts/", sizeof ("/dev/pts/")); buflen -= sizeof ("/dev/pts/") - 1; if (__xstat64 (_STAT_VER, buf, &st1) == 0 && S_ISDIR (st1.st_mode)) { #ifdef _STATBUF_ST_RDEV ret = getttyname_r (buf, buflen, st.st_rdev, st.st_ino, save, &dostat); #else ret = getttyname_r (buf, buflen, st.st_dev, st.st_ino, save, &dostat); #endif } else { __set_errno (save); ret = ENOENT; } if (ret && dostat != -1) { buf[sizeof ("/dev/") - 1] = '\0'; buflen += sizeof ("pts/") - 1; #ifdef _STATBUF_ST_RDEV ret = getttyname_r (buf, buflen, st.st_rdev, st.st_ino, save, &dostat); #else ret = getttyname_r (buf, buflen, st.st_dev, st.st_ino, save, &dostat); #endif } if (ret && dostat != -1) { buf[sizeof ("/dev/") - 1] = '\0'; dostat = 1; #ifdef _STATBUF_ST_RDEV ret = getttyname_r (buf, buflen, st.st_rdev, st.st_ino, save, &dostat); #else ret = getttyname_r (buf, buflen, st.st_dev, st.st_ino, save, &dostat); #endif } return ret; }
/* Return the pathname of the terminal FD is open on, or NULL on errors. The returned storage is good only until the next call to this function. */ char * ttyname (int fd) { static size_t buflen; char procname[30]; struct stat64 st, st1; int dostat = 0; char *name; int save = errno; struct termios term; /* isatty check, tcgetattr is used because it sets the correct errno (EBADF resp. ENOTTY) on error. */ if (__builtin_expect (__tcgetattr (fd, &term) < 0, 0)) return NULL; /* We try using the /proc filesystem. */ *_fitoa_word (fd, __stpcpy (procname, "/proc/self/fd/"), 10, 0) = '\0'; if (buflen == 0) { buflen = 4095; ttyname_buf = (char *) malloc (buflen + 1); if (ttyname_buf == NULL) { buflen = 0; return NULL; } } ssize_t len = __readlink (procname, ttyname_buf, buflen); if (__builtin_expect (len == -1 && errno == ENOENT, 0)) { __set_errno (EBADF); return NULL; } if (__builtin_expect (len != -1 #ifndef __ASSUME_PROC_SELF_FD_SYMLINK /* This is for Linux 2.0. */ && ttyname_buf[0] != '[' #endif , 1)) { if ((size_t) len >= buflen) return NULL; /* readlink need not terminate the string. */ ttyname_buf[len] = '\0'; return ttyname_buf; } if (__fxstat64 (_STAT_VER, fd, &st) < 0) return NULL; if (__xstat64 (_STAT_VER, "/dev/pts", &st1) == 0 && S_ISDIR (st1.st_mode)) { #ifdef _STATBUF_ST_RDEV name = getttyname ("/dev/pts", st.st_rdev, st.st_ino, save, &dostat); #else name = getttyname ("/dev/pts", st.st_dev, st.st_ino, save, &dostat); #endif } else { __set_errno (save); name = NULL; } if (!name && dostat != -1) { #ifdef _STATBUF_ST_RDEV name = getttyname ("/dev", st.st_rdev, st.st_ino, save, &dostat); #else name = getttyname ("/dev", st.st_dev, st.st_ino, save, &dostat); #endif } if (!name && dostat != -1) { dostat = 1; #ifdef _STATBUF_ST_RDEV name = getttyname ("/dev", st.st_rdev, st.st_ino, save, &dostat); #else name = getttyname ("/dev", st.st_dev, st.st_ino, save, &dostat); #endif } return name; }
/* Return nonzero if DIR is an existent directory. */ static bool direxists (const char *dir) { struct_stat64 buf; return __xstat64 (_STAT_VER, dir, &buf) == 0 && S_ISDIR (buf.st_mode); }
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; } /* Prepare for the loop. If we already have a buffer copy the directory name we look at into it. */ if (devlen < namelen) *((char *) __mempcpy (getttyname_name, dev, devlen - 1)) = '/'; 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; }
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); }
void attribute_hidden __atfct_seterrno_2 (int errval, int fd1, const char *buf1, int fd2, const char *buf2) { if (buf1 != NULL || buf2 != NULL) { struct stat64 st; if (errval == ENOTDIR) { /* This can mean either the file descriptor is invalid or /proc is not mounted. */ if (buf1 != NULL) { if (__fxstat64 (_STAT_VER, fd1, &st) != 0) /* errno is already set correctly. */ return; /* If /proc is not mounted there is nothing we can do. */ if (S_ISDIR (st.st_mode) && (__xstat64 (_STAT_VER, "/proc/self/fd", &st) != 0 || !S_ISDIR (st.st_mode))) { errval = ENOSYS; goto out; } } if (buf2 != NULL) { if (__fxstat64 (_STAT_VER, fd2, &st) != 0) /* errno is already set correctly. */ return; /* If /proc is not mounted there is nothing we can do. */ if (S_ISDIR (st.st_mode) && (__xstat64 (_STAT_VER, "/proc/self/fd", &st) != 0 || !S_ISDIR (st.st_mode))) errval = ENOSYS; } } else if (errval == ENOENT) { /* This could mean the file descriptor is not valid. We reuse BUF for the stat call. Find the slash after the file descriptor number. */ if (buf1 != NULL) { *(char *) strchr (buf1 + sizeof "/proc/self/fd", '/') = '\0'; int e = __lxstat64 (_STAT_VER, buf1, &st); if ((e == -1 && errno == ENOENT) ||(e == 0 && !S_ISLNK (st.st_mode))) { errval = EBADF; goto out; } } if (buf2 != NULL) { *(char *) strchr (buf2 + sizeof "/proc/self/fd", '/') = '\0'; int e = __lxstat64 (_STAT_VER, buf2, &st); if ((e == -1 && errno == ENOENT) ||(e == 0 && !S_ISLNK (st.st_mode))) errval = EBADF; } } } out: __set_errno (errval); }