mv a file to /dev/null breaks dev/null

7,963

Solution 1

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.

Solution 2

Moving a file to the location of an already existing file replaces the existing file. In this case the /dev/null device file is replaced, just as any normal file would be. To avoid this use the -i (interactive, warns before overwriting) or -n (no clober) option for mv.

/dev/null only performs its special function as a bit-bucket then the device is opened as is. Eg, when the > shell operator is used, the file is opened then truncated (not removed an replaced, which may be what you expected). As mentioned by casey, the correct way to remove a file is with rm or even with unlink.

Solution 3

Umm, because you overwrite the special file with normal one? What did you expect to happen? dev/null is not a directory, it is a file pointing to a null device. When you mv something to it, you delete the original and replace it with whatever you moved:

$ file /dev/null 
/dev/null: character special 
$ sudo mv file /dev/null 
$ file /dev/null 
/dev/null: ASCII text
Share:
7,963
Gregg Leventhal
Author by

Gregg Leventhal

Updated on September 18, 2022

Comments

  • Gregg Leventhal
    Gregg Leventhal over 1 year

    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.

    • Admin
      Admin about 10 years
      Don't mess with /dev/null.
    • Admin
      Admin about 10 years
      so says @devnull
    • Admin
      Admin about 10 years
      The proper way to delete files is the rm command.
    • Admin
      Admin about 10 years
      I am not trying to delete anything, this was an experiment. The thing I am curious about is that replacing the file results in the file being missing when ls -la /dev/null is run. I am guessing this is due to the nature of devfs.
    • Admin
      Admin about 10 years
      @Gregg, does a Mac use devfs?
    • Admin
      Admin about 10 years
      Yes df -h Greggs-MacBook-Air1:~ gleventhal$ df -h /dev Filesystem Size Used Avail Capacity iused ifree %iused Mounted on devfs 191Ki 191Ki 0Bi 100% 660 0 100% /dev
    • Admin
      Admin about 10 years
      @Gregg, can you also create normal files on the OSX /dev, eg touch /dev/testfile.
    • Admin
      Admin about 10 years
      Just to make sure it's not specific to ls, run find /dev -n name null to test whether find can see it. I really doubt it will but may as well.
    • Admin
      Admin about 10 years
      On a Mac, as root touch /dev/test results in operation not supported.
    • Admin
      Admin about 10 years
      Seems like that is the root of your problem, OSX devfs is funny about normal files. Strange you didn't get an error from mv though. How about this way: touch testfile; mv testfile /dev?
    • Admin
      Admin about 10 years
      touch testfile; mv testfile /dev results in operation not supported too, so I am going to assume when you mv file /dev/null on a Mac you are "unlinking" /dev/null and then the mv fails, but this seems weird since mv is supposed to be atomic.
    • Admin
      Admin about 10 years
      @GreggLeventhal So it was pointed out to me. I deleted my comment, but too late to stop you answering. :-) In the interest of reducing clutter, if you delete your comment, I'll delete mine. Just ping me on chat, and sorry about the noise.
    • Admin
      Admin about 10 years
      @Gregg, mv can only be atomic on the same filesystem.
    • Admin
      Admin about 10 years
      Maybe this @DE_WHITEOUT flag?
  • Gregg Leventhal
    Gregg Leventhal about 10 years
    But I am saying /dev/null was showing as missing when running an ls -lad /dev/null. This must be something specific to the devfs, that it what I wanted to know about.
  • Gregg Leventhal
    Gregg Leventhal about 10 years
    If I mv file /dev/null then /dev/null should contain what file contained but still exist. I want to know why this caused /dev/null to not be found in an ls.
  • Gregg Leventhal
    Gregg Leventhal about 10 years
    See my comments to terdon.
  • Gregg Leventhal
    Gregg Leventhal about 10 years
    Understood, the -d was unneeded, that is just a bad habit however the file should still show up in the ls output, it should not show as nonexistent.
  • terdon
    terdon about 10 years
    @GreggLeventhal yes, it must be an OSX or BSD thing (please edit your Q and specify your OS). On my Linux I can still see /dev/null, it's just become the file I moved.
  • slm
    slm about 10 years
    @Graeme - welcome to 3K, nice job!
  • Gregg Leventhal
    Gregg Leventhal about 10 years
    I am giving this best answer right now for providing source code and acknowledging this as a bug, which is what I was driving at.