From: "Theo de Raadt" Subject: Re: openat(2) is mostly useless, sadly To: Mark Kettenis Cc: h@hartzer.sh, tech@openbsd.org Date: Sat, 31 May 2025 09:04:51 -0600 Mark Kettenis wrote: > > From: "Theo de Raadt" > > Date: Fri, 30 May 2025 19:17:46 -0600 > > > > Steffen Nurpmeso wrote: > > > > > I would not use ENOTTY for F_BELOW on !DIR, maybe ENOTDIR is > > > better. > > > > >From errno(2) manpage: > > > > 20 ENOTDIR Not a directory. A component of the specified pathname > > existed, but it was not a directory, when a directory was > > expected. > > > > F_BELOW is fcntl(2). > > > > int > > fcntl(int fd, int cmd, ...); > > > > But there is no pathname. Yes it is partly vague, but then grep the whole > > tree for ENOTDIR and always anticipates a pathname at a higher level. > > Note that openat(2) says: > > [ENOTDIR] The path argument specifies a relative path and the fd > argument is a valid file descriptor but it does not > reference a directory. > > So here ENOTDIR does apply to a file descriptor. That is in the openat(2) page, where there is a pathname. But fcntl() has no pathname. However, it looks like this has been used for non-pathname circumstances before: int sys_fchdir(struct proc *p, void *v, register_t *retval) ... if (fp->f_type != DTYPE_VNODE || vp->v_type != VDIR) { FRELE(fp, p); return (ENOTDIR); } And fchdir(2) says: [ENOTDIR] The file descriptor does not reference a directory. Checking other manual pages in a sloppy way, grep 'file desc' * | grep 'directory' access.2:the directory associated with file descriptor access.2:argument is a valid file descriptor but it does not reference a directory. chdir.2:The file descriptor does not reference a directory. chmod.2:argument is a valid file descriptor but it does not reference a directory. chown.2:the directory associated with file descriptor chown.2:argument is a valid file descriptor but it does not reference a directory. chroot.2:Passing directory file descriptors via link.2:is a valid file descriptor but it does not reference a directory. mkdir.2:the directory associated with file descriptor mkdir.2:argument is a valid file descriptor but it does not reference a directory. mkfifo.2:the directory associated with file descriptor mkfifo.2:argument is a valid file descriptor but it does not reference a directory. mknod.2:the directory associated with file descriptor mknod.2:argument is a valid file descriptor but it does not reference a directory. open.2:the directory associated with file descriptor open.2:argument is a valid file descriptor but it does not reference a directory. pathconf.2:argument is a valid file descriptor but it does not reference a directory. readlink.2:the directory associated with file descriptor readlink.2:argument is a valid file descriptor but it does not reference a directory. rename.2:is a valid file descriptor but it does not reference a directory. stat.2:the directory associated with file descriptor stat.2:argument is a valid file descriptor but it does not reference a directory. symlink.2:the directory associated with file descriptor symlink.2:argument is a valid file descriptor but it does not reference a directory. unlink.2:the directory associated with file descriptor unlink.2:argument is a valid file descriptor but it does not reference a directory. utimes.2:the directory associated with file descriptor utimes.2:argument is a valid file descriptor but it does not reference a directory. Some of these follow the form [ENOTDIR] The path argument specifies a relative path and the fd argument is a valid file descriptor but it does not reference a directory. I think this would be a good diff to intro(2) to explain the situation that we had a few ENOTDIR related to non-pathname conditions, but the openat() family of calls has greatly expanded the situation. Index: intro.2 =================================================================== RCS file: /cvs/src/lib/libc/sys/intro.2,v diff -u -p -u -r1.73 intro.2 --- intro.2 19 Dec 2022 18:13:50 -0000 1.73 +++ intro.2 31 May 2025 15:03:24 -0000 @@ -159,8 +159,9 @@ A hard link to a file on another file sy An attempt was made to apply an inappropriate function to a device, for example, trying to read a write-only device such as a printer. .It Er 20 ENOTDIR Em "Not a directory" . -A component of the specified pathname existed, but it was +A file descriptor or a component of the specified pathname existed, but it was not a directory, when a directory was expected. +.Pp .It Er 21 EISDIR Em "Is a directory" . An attempt was made to open a directory with write mode specified. .It Er 22 EINVAL Em "Invalid argument" . Then, we can use ENOTDIR for a condition in fcntl(2).