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