Mv a file to /dev/null breaks dev/null

devicesnullosx

If I do: touch file; mv file /dev/null as root, /dev/null disappears. ls -lad /dev/null results in no such file or directory. This breaks applications which depend on /dev/null like SSH and can be resolved by doing mknod /dev/null c 1 3; chmod 666 /dev/null. Why does moving a regular file to this special file result in the disappearance of /dev/null?

To clarify, this was for testing purposes, and I understand how the mv command works. What I am curious about is why ls -la /dev/null before replacing it with a regular file shows the expected output, but afterwards it shows that /dev/null does not exist even though a file was allegedly created via the original mv command and the file command shows ASCII Text. I think this must be a combination of the ls command behavior in conjunction with devfs when a non special file replaces a character/special file. This is on Mac OS X, behaviors may vary on other OS's.

Best Answer

Looking at the source code for mv, http://www.opensource.apple.com/source/file_cmds/file_cmds-220.7/mv/mv.c :

/*
 * If rename fails because we're trying to cross devices, and
 * it's a regular file, do the copy internally; otherwise, use
 * cp and rm.
 */
if (lstat(from, &sb)) {
    warn("%s", from);
    return (1);
}
return (S_ISREG(sb.st_mode) ?
    fastcopy(from, to, &sb) : copy(from, to));

...

int
fastcopy(char *from, char *to, struct stat *sbp)
{
...
while ((to_fd =
    open(to, O_CREAT | O_EXCL | O_TRUNC | O_WRONLY, 0)) < 0) {
        if (errno == EEXIST && unlink(to) == 0)
            continue;
        warn("%s", to);
        (void)close(from_fd);
        return (1);
}

In the first pass through the while loop, open(to, O_CREAT | O_EXCL | O_TRUNC | O_WRONLY, 0) will fail with EEXIST. Then /dev/null will be unlinked, and the loop repeated. But as you pointed out in your comment, regular files can't be created in /dev, so on the next pass through the loop, open(to, O_CREAT | O_EXCL | O_TRUNC | O_WRONLY, 0) is still going to fail.

I'd file a bug report with Apple. The mv source code is mostly unchanged from the FreeBSD version, but because OSX's devfs has that non-POSIX behavior with regular files, Apple should fix their mv.