Bug 6280 - Linux mknod does not work when syncing fifos and sockets from Solaris
Summary: Linux mknod does not work when syncing fifos and sockets from Solaris
Alias: None
Product: rsync
Classification: Unclassified
Component: core (show other bugs)
Version: 3.0.6
Hardware: x64 Linux
: P3 normal (vote)
Target Milestone: ---
Assignee: Wayne Davison
QA Contact: Rsync QA Contact
Depends on:
Reported: 2009-04-20 15:48 UTC by Sebastian Kapfer
Modified: 2009-04-26 13:49 UTC (History)
0 users

See Also:

Changes to excise rdev use with special files (4.68 KB, patch)
2009-04-25 12:07 UTC, Wayne Davison
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description Sebastian Kapfer 2009-04-20 15:48:18 UTC
When syncing specials, namely pipes and sockets from a Solaris host, rsync -a prints error 22.  Remote version is 2.6.3pre1.

sk@noether(~/rsnyc/rsync-3.0.6pre1)> ./rsync -a klein:/tmp/xhyjxhy .
rsync: mknod "/home/sk/rsnyc/rsync-3.0.6pre1/xhyjxhy" failed: Invalid argument (22)
rsync error: some files/attrs were not transferred (see previous errors) (code 23) at main.c(1505) [generator=3.0.6pre1]

Reason:  rsync calls mknod ("filename", ..., 0xffffffff), which Linux rejects, as allowed by POSIX.

rsync should clear the third parameter before calling mknod.

Suggested patch in syscall.c, do_mknod:

111 #ifdef HAVE_MKNOD
112         if (S_ISSOCK (mode) || S_ISFIFO(mode)) {
113             /* this variable is not ignored by Linux 2.6. */
114             dev = 0;
115         }
116 >-------return mknod(pathname, mode, dev);
117 #else
Comment 1 Sebastian Kapfer 2009-04-20 16:00:36 UTC
Three additional comments:

1. Updating the Solaris side of things to rsync-3.06 does not help.

2. Pushing to instead of pulling from Linux does not help.

3. Reproduce the behaviour with this code#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main () {
    if (mknod ("test_fifo_fifi", 0777 | S_IFIFO, (dev_t)-1)) {
        perror ("mknod");
        return 1;
    unlink ("test_fifo_fifi");
    return 0;

This works on Solaris, and does not work on Linux.  The Linux docs are not completely clear as to if this should work.
Comment 2 Wayne Davison 2009-04-24 09:08:12 UTC
Does Solaris allow mknod("test_fifo_fifi", 0777 | S_IFIFO, (dev_t)0) to work?  If so, the fix I'm contemplating is setting rdev to 0 down in flist.c's make_file():

        if (IS_DEVICE(st.st_mode)) {
                tmp_rdev = st.st_rdev;
                st.st_size = 0;
        } else if (IS_SPECIAL(st.st_mode)) {
                tmp_rdev = 0;
                st.st_size = 0;

I wonder if that would break any OS?  Perhaps a safer change would be for that final tmp_rdev assignment to be:

                tmp_rdev = st.st_rdev == (dev_t)-1 ? 0 : st.st_rdev;
Comment 3 Sebastian Kapfer 2009-04-25 03:45:31 UTC

from Solaris mknod(2):

     If mode does not indicate a
     block special or character special device, dev  is  ignored.

Similar prose is in Linux mknod(2), but in the case of Solaris, it is actually true :-)

In short, dev=0 works on Linux and Solaris.

I'd prefer the fix being in the receiving end of rsync, that is, the one that does the actual mknod.  This would maintain compatibility work legacy rsyncs on the remove host.  Is make_file on the receiving end?

Greetings, Sebastian
Comment 4 Wayne Davison 2009-04-25 12:07:11 UTC
Created attachment 4082 [details]
Changes to excise rdev use with special files

Here's the patch I came up with.  It has the following features:

- Should avoid the error when talking to an older rsync version, regardless of the direction of transfer.
- Makes the transmission of special files a little more efficient (and will be made even more efficient in protocol 31, which is being created for 3.1.0).
- Saves memory by not remembering a useless rdev value for special files.

I looked at the Linux kernel code, and all the file systems I saw validate that the dev value is a valid device number before figuring out what kind of device/special-file is being created.  So, the code above ensures that mknod() should always see a valid device number.
Comment 5 Wayne Davison 2009-04-26 10:07:05 UTC
Fix checked into git.
Comment 6 Sebastian Kapfer 2009-04-26 13:49:49 UTC
I tried the Git version in all combinations of patched/unpatched and Solaris/Linux.  It works beautifully, tough I don't quite see the reason for a protocol change.  Thank you very much for your help!