Revert "Use rsync in zfsaddhomedir"
authorMichael Spang <mspang@uwaterloo.ca>
Mon, 20 Jul 2009 04:12:59 +0000 (00:12 -0400)
committerMichael Spang <mspang@uwaterloo.ca>
Mon, 20 Jul 2009 04:12:59 +0000 (00:12 -0400)
This reverts commit 88952ae56a2572559a073667d9ef704087a7c479.

src/zfsaddhomedir.c

index 5f65c07..e3c3271 100644 (file)
@@ -10,6 +10,7 @@ int main(int argc, char *argv[]) {
         return 1;
     }
 
+    // TODO: check return of spawnv
     {
         char *homedir = argv[1];
         char *skeldir = argv[3];
@@ -19,13 +20,13 @@ int main(int argc, char *argv[]) {
         uid_t uid, gid;
         char *zfs_bin = "/usr/sbin/zfs";
         char *chmod_bin = "/usr/bin/chmod";
-        char *rsync_bin = "/usr/bin/rsync";
         char *dataset = homedir + 1;
         char *create_argv[] = { "zfs", "create", dataset, NULL };
         char *quota_argv[] = { "zfs", "set", refquota, dataset, NULL };
         char *mode_argv[] = { "chmod", mode, homedir, NULL };
         char *acl_argv[] = { "chmod", acl, homedir, NULL };
-        char *rsync_argv[] = { "rsync", "-avH", skeldir, homedir, NULL };
+        DIR *skel;
+        struct dirent *skelent;
 
         assert(homedir[0]);
         uid = atol(argv[4]);
@@ -41,16 +42,96 @@ int main(int argc, char *argv[]) {
         if(acl && spawnv(chmod_bin, acl_argv))
             return 1;
 
+        skel = opendir(skeldir);
+        if (!skel) {
+            errorpe("failed to open %s", skeldir);
+            return -1;
+        }
+
+        while ((skelent = readdir(skel))) {
+            struct stat sb;
+            char src[PATH_MAX], dest[PATH_MAX];
+
+            if (!strcmp(skelent->d_name, ".") || !strcmp(skelent->d_name, ".."))
+                continue;
+
+            snprintf(src, sizeof(src), "%s/%s", skeldir, skelent->d_name);
+            snprintf(dest, sizeof(dest), "/%s/%s", homedir, skelent->d_name);
+            lstat(src, &sb);
+
+            if (sb.st_uid || sb.st_gid) {
+                warn("not creating %s due to ownership", dest);
+                continue;
+            }
+
+            if (S_ISREG(sb.st_mode)) {
+                int bytes;
+                char buf[4096];
+
+                int srcfd = open(src, O_RDONLY);
+                if (srcfd == -1) {
+                    warnpe("open: %s", src);
+                    continue;
+                }
+
+                int destfd = open(dest, O_WRONLY|O_CREAT|O_EXCL, sb.st_mode & 0777);
+                if (destfd == -1) {
+                    warnpe("open: %s", dest);
+                    close(srcfd);
+                    continue;
+                }
+
+                for (;;) {
+                    bytes = read(srcfd, buf, sizeof(buf));
+                    if (!bytes)
+                        break;
+                    if (bytes < 0) {
+                        warnpe("read");
+                        break;
+                    }
+                    if (write(destfd, buf, bytes) < 0) {
+                        warnpe("write");
+                        break;
+                    }
+                }
+                if (fchown(destfd, uid, gid))
+                    errorpe("chown: %s", dest);
+
+                close(srcfd);
+                close(destfd);
+            } else if (S_ISDIR(sb.st_mode)) {
+                if (mkdir(dest, sb.st_mode & 0777)) {
+                    warnpe("mkdir: %s", dest);
+                    continue;
+                }
+                if (chown(dest, uid, gid))
+                    errorpe("chown: %s", dest);
+            } else if (S_ISLNK(sb.st_mode)) {
+                char lnkdest[PATH_MAX];
+                int bytes;
+                bytes = readlink(src, lnkdest, sizeof(lnkdest));
+                lnkdest[bytes] = '\0';
+                if (bytes == -1) {
+                    warnpe("readlink: %s", src);
+                    continue;
+                }
+                if (symlink(lnkdest, dest)) {
+                    warnpe("symlink: %s", dest);
+                    continue;
+                }
+                if (lchown(dest, uid, gid))
+                    errorpe("lchown: %s", dest);
+            } else {
+                warn("not creating %s", dest);
+            }
+        }
+
+        closedir(skel);
+
         if (chown(homedir, uid, gid)) {
             errorpe("failed to chown %s", homedir);
             return 1;
         }
-
-        if(seteuid(uid) != 0 || setegid(gid) != 0)
-            errorpe("failed to seteuid(%d) or setegid(%d)", (int)uid, (int)gid);
-            return 1;
-        if(spawnv(rsync_bin, rsync_argv))
-            return 1;
     }
 
     return 0;