Abort on unexpected SCTP errors
[public/pyceo-broken.git] / src / zfsaddhomedir.c
1 #include <stdio.h>
2 #include <unistd.h>
3 #include <dirent.h>
4 #include <limits.h>
5 #include <sys/stat.h>
6 #include <sys/types.h>
7 #include <fcntl.h>
8 #include <assert.h>
9 #include "util.h"
10
11 int main(int argc, char *argv[]) {
12     if(argc < 7) {
13         fprintf(stderr, "Usage: zfsaddhomedir homedir refquota skeldir uid gid mode acl\n");
14         return 1;
15     }
16
17     char *homedir = argv[1];
18     char *skeldir = argv[3];
19     char refquota[32];
20     char *mode = argv[6];
21     char *acl = (argc >= 8) ? argv[7] : NULL;
22     uid_t uid, gid;
23     char *zfs_bin = "/usr/sbin/zfs";
24     char *chmod_bin = "/usr/bin/chmod";
25     char *dataset = homedir + 1;
26     char *create_argv[] = { "zfs", "create", dataset, NULL };
27     char *quota_argv[] = { "zfs", "set", refquota, dataset, NULL };
28     char *mode_argv[] = { "chmod", mode, homedir, NULL };
29     char *acl_argv[] = { "chmod", acl, homedir, NULL };
30     DIR *skel;
31     struct dirent *skelent;
32
33     assert(homedir[0]);
34     uid = atol(argv[4]);
35     gid = atol(argv[5]);
36     snprintf(refquota, sizeof(refquota), "refquota=%s", argv[2]);
37
38     if(spawnv(zfs_bin, create_argv))
39         return 1;
40     if(spawnv(zfs_bin, quota_argv))
41         return 1;
42     if(spawnv(chmod_bin, mode_argv))
43         return 1;
44     if(acl && spawnv(chmod_bin, acl_argv))
45         return 1;
46
47     skel = opendir(skeldir);
48     if (!skel) {
49         errorpe("failed to open %s", skeldir);
50         return -1;
51     }
52
53     while ((skelent = readdir(skel))) {
54         struct stat sb;
55         char src[PATH_MAX], dest[PATH_MAX];
56
57         if (!strcmp(skelent->d_name, ".") || !strcmp(skelent->d_name, ".."))
58             continue;
59
60         snprintf(src, sizeof(src), "%s/%s", skeldir, skelent->d_name);
61         snprintf(dest, sizeof(dest), "/%s/%s", homedir, skelent->d_name);
62         lstat(src, &sb);
63
64         if (sb.st_uid || sb.st_gid) {
65             warn("not creating %s due to ownership", dest);
66             continue;
67         }
68
69         if (S_ISREG(sb.st_mode)) {
70             int bytes;
71             char buf[4096];
72
73             int srcfd = open(src, O_RDONLY);
74             if (srcfd == -1) {
75                 warnpe("open: %s", src);
76                 continue;
77             }
78
79             int destfd = open(dest, O_WRONLY|O_CREAT|O_EXCL, sb.st_mode & 0777);
80             if (destfd == -1) {
81                 warnpe("open: %s", dest);
82                 close(srcfd);
83                 continue;
84             }
85
86             for (;;) {
87                 bytes = read(srcfd, buf, sizeof(buf));
88                 if (!bytes)
89                     break;
90                 if (bytes < 0) {
91                     warnpe("read");
92                     break;
93                 }
94                 if (write(destfd, buf, bytes) < 0) {
95                     warnpe("write");
96                     break;
97                 }
98             }
99             if (fchown(destfd, uid, gid))
100                 errorpe("chown: %s", dest);
101
102             close(srcfd);
103             close(destfd);
104         } else if (S_ISDIR(sb.st_mode)) {
105             if (mkdir(dest, sb.st_mode & 0777)) {
106                 warnpe("mkdir: %s", dest);
107                 continue;
108             }
109             if (chown(dest, uid, gid))
110                 errorpe("chown: %s", dest);
111         } else if (S_ISLNK(sb.st_mode)) {
112             char lnkdest[PATH_MAX];
113             int bytes;
114             bytes = readlink(src, lnkdest, sizeof(lnkdest));
115             lnkdest[bytes] = '\0';
116             if (bytes == -1) {
117                 warnpe("readlink: %s", src);
118                 continue;
119             }
120             if (symlink(lnkdest, dest)) {
121                 warnpe("symlink: %s", dest);
122                 continue;
123             }
124             if (lchown(dest, uid, gid))
125                 errorpe("lchown: %s", dest);
126         } else {
127             warn("not creating %s", dest);
128         }
129     }
130
131     closedir(skel);
132
133     if (chown(homedir, uid, gid)) {
134         errorpe("failed to chown %s", homedir);
135         return -1;
136     }
137
138     return 0;
139 }