install(1) with option "-d" creates directories. If the final target or an intermediate directory is a symbolic link, that points to a none existing file/directory, then install will enter an endless loop. I believe the behaviour was introduced with base r272026 | mjg | 2014-09-23 13:41:09 +0200 (Tue, 23 Sep 2014). It was observed when using mergemaster for a jail setup with ezjail. In that case symlinks visited from host can point to not existing directories on host system. environment: FreeBSD 11.0-CURRENT #10 r292982M: how to repeat: % ln -s /notexists /tmp/ % install -d /tmp/notexists & [1] 9843 % ps -v -p 9843 PID STAT TIME SL RE PAGEIN VSZ RSS LIM TSIZ %CPU %MEM COMMAND 9843 R 1:12.80 127 73 0 8356 2024 - 28 100.0 0.0 install -d /tmp/notexists % kill -ABRT 9843 % gdb /usr/bin/install install.core (gdb) bt #0 stat () at stat.S:3 #1 0x0000000000402e0b in main (argc=<value optimized out>, argv=<value optimized out>) at /usr/src11/usr.bin/xinstall/xinstall.c:1269 (gdb) list 1269 1264 for (p = path;; ++p) 1265 if (!*p || (p != path && *p == '/')) { 1266 ch = *p; 1267 *p = '\0'; 1268 again: 1269 if (stat(path, &sb) < 0) { 1270 if (errno != ENOENT) 1271 err(EX_OSERR, "stat %s", path); 1272 if (mkdir(path, 0755) < 0) { 1273 if (errno == EEXIST) (gdb) q The stat call returns ENOENT and mkdir returns with EEXIST - that creates an endless loop.
Bugreport looks legitimate. However, it is unclear what to do here - do an lstat or stat + lstat combo? I'll have to look around.
(In reply to Mateusz Guzik from comment #1) I think a stat() call should be done after mkdir() fails with [EEXIST]; however, after that stat() call, we should not retry mkdir(). The stat() call may fail (error), report non-directory (error) or report directory (continue silently). Replacing the existing stat() call with lstat() will fail for symlinks to directories anywhere in the path. Another direction is to pass pathnames ending with a slash to stat() (or lstat()) and mkdir(). Per POSIX, this will cause lstat() to follow the symlink (and fail if the file pointed to is not a directory) and mkdir() to create the directory through the symlink. However, Linux does not implement the latter.
batch change: For bugs that match the following - Status Is In progress AND - Untouched since 2018-01-01. AND - Affects Base System OR Documentation DO: Reset to open status. Note: I did a quick pass but if you are getting this email it might be worthwhile to double check to see if this bug ought to be closed.
I forgot about this bug. The issue was fixed in r324547 ( https://svnweb.freebsd.org/base?view=revision&revision=324547 ).