return 1;
}
+ // TODO: check return of spawnv
{
char *homedir = argv[1];
char *skeldir = argv[3];
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]);
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;