Hi,

I've noticed an issue with openrsync and more than 1 source arguments and with
it's symlink behaviour (separate issues).

Reproduce:

        cd /tmp
        mkdir -p a b
        openrsync -av a/ b/ c/

Output:
        /usr/src/usr.bin/rsync/flist.c:823: error: b/: lstat: No such file or 
directory
        /usr/src/usr.bin/rsync/flist.c:1032: error: flist_gen_dirent
        /usr/src/usr.bin/rsync/sender.c:391: error: flist_gen
        /usr/src/usr.bin/rsync/client.c:85: error: rsync_sender


This is because in flist.c unveil(2) is called per argument. unveil(2) will
remove visibility after it's first call as described in the man page:

"
     The first call to unveil removes visibility of the entire filesystem from
     all other filesystem-related system calls (such as open(2), chmod(2) and
     rename(2)), except for the specified path and permissions.
"

For both files and recursive directories a list is created. I think the logic
can be simplified and unified and unveil(2) called on these list items after
the list is created.

After changing the unveil(2) logic, there is an error in the duplicate working
path detection code:

        /usr/src/usr.bin/rsync/flist.c:119: error: .: duplicate working path 
for possibly different file: a/., b/.
        /usr/src/usr.bin/rsync/flist.c:1149: error: flist_dedupe
        /usr/src/usr.bin/rsync/sender.c:391: error: flist_gen
        /usr/src/usr.bin/rsync/client.c:85: error: rsync_sender

In the below patch I have removed this code for now.

There is also an issue with symlinks:

        mkdir -p /tmp/a
        cd /tmp/a
        ln -s b a
        cd /tmp
        openrsync -av a/ b/

Result:

        /usr/src/usr.bin/rsync/symlinks.c:48: error: a/a: readlink: No such 
file or directory
        /usr/src/usr.bin/rsync/flist.c:985: error: symlink_read
        /usr/src/usr.bin/rsync/flist.c:1032: error: flist_gen_dirent
        /usr/src/usr.bin/rsync/sender.c:391: error: flist_gen
        /usr/src/usr.bin/rsync/client.c:85: error: rsync_sender

I think this is because the fts(3) interface by default chdir(2) to a directory
before running the callback function and the path is then incorrect there. I
think it can safely pass FTS_NOCHDIR as a flag (and also optimization) to
fts_open(3).

Work-in-progress patch below, feedback is welcome:


diff --git usr.bin/rsync/flist.c usr.bin/rsync/flist.c
index 4860e20f428..07285b87362 100644
--- usr.bin/rsync/flist.c
+++ usr.bin/rsync/flist.c
@@ -113,12 +113,6 @@ flist_dedupe(struct flist **fl, size_t *sz)
                        fnext->path = fnext->link = NULL;
                        continue;
                }
-
-               ERRX("%s: duplicate working path for "
-                   "possibly different file: %s, %s",
-                   f->wpath, f->path, fnext->path);
-               free(new);
-               return 0;
        }
 
        /* Don't forget the last entry. */
@@ -834,10 +828,6 @@ flist_gen_dirent(struct sess *sess, char *root, struct 
flist **fl, size_t *sz,
                        ERRX1("flist_append");
                        return 0;
                }
-               if (unveil(root, "r") == -1) {
-                       ERR("%s: unveil", root);
-                       return 0;
-               }
                return 1;
        } else if (S_ISLNK(st.st_mode)) {
                if (!sess->opts->preserve_links) {
@@ -854,10 +844,6 @@ flist_gen_dirent(struct sess *sess, char *root, struct 
flist **fl, size_t *sz,
                        ERRX1("flist_append");
                        return 0;
                }
-               if (unveil(root, "r") == -1) {
-                       ERR("%s: unveil", root);
-                       return 0;
-               }
                return 1;
        } else if (!S_ISDIR(st.st_mode)) {
                WARNX("%s: skipping special", root);
@@ -892,7 +878,7 @@ flist_gen_dirent(struct sess *sess, char *root, struct 
flist **fl, size_t *sz,
         * We'll make sense of it in flist_send.
         */
 
-       if ((fts = fts_open(cargv, FTS_PHYSICAL, NULL)) == NULL) {
+       if ((fts = fts_open(cargv, FTS_PHYSICAL|FTS_NOCHDIR, NULL)) == NULL) {
                ERR("fts_open");
                return 0;
        }
@@ -994,10 +980,6 @@ flist_gen_dirent(struct sess *sess, char *root, struct 
flist **fl, size_t *sz,
                ERR("fts_read");
                goto out;
        }
-       if (unveil(root, "r") == -1) {
-               ERR("%s: unveil", root);
-               goto out;
-       }
 
        LOG3("generated %zu filenames: %s", flsz, root);
        rc = 1;
@@ -1091,10 +1073,6 @@ flist_gen_files(struct sess *sess, size_t argc, char 
**argv,
 
                /* Add this file to our file-system worldview. */
 
-               if (unveil(argv[i], "r") == -1) {
-                       ERR("%s: unveil", argv[i]);
-                       goto out;
-               }
                if (!flist_append(f, &st, argv[i])) {
                        ERRX1("flist_append");
                        goto out;
@@ -1124,6 +1102,7 @@ int
 flist_gen(struct sess *sess, size_t argc, char **argv, struct flist **flp,
     size_t *sz)
 {
+       size_t   i;
        int      rc;
 
        assert(argc > 0);
@@ -1133,10 +1112,23 @@ flist_gen(struct sess *sess, size_t argc, char **argv, 
struct flist **flp,
 
        /* After scanning, lock our file-system view. */
 
+       for (i = 0; i < argc; i++) {
+               if (unveil(argv[i], "r") == -1) {
+                       ERR("%s: unveil", argv[i]);
+                       return 0;
+               }
+       }
+       for (i = 0; i < *sz; i++) {
+               if (unveil((*flp)[i].path, "r") == -1) {
+                       ERR("%s: unveil", (*flp)[i].path);
+                       return 0;
+               }
+       }
        if (unveil(NULL, NULL) == -1) {
                ERR("unveil");
                return 0;
        }
+
        if (!rc)
                return 0;
 
@@ -1276,7 +1268,7 @@ flist_gen_dels(struct sess *sess, const char *root, 
struct flist **fl,
         * If the directories don't exist, it's ok.
         */
 
-       if ((fts = fts_open(cargv, FTS_PHYSICAL, NULL)) == NULL) {
+       if ((fts = fts_open(cargv, FTS_PHYSICAL|FTS_NOCHDIR, NULL)) == NULL) {
                ERR("fts_open");
                goto out;
        }

-- 
Kind regards,
Hiltjo

Reply via email to