xinstall.c - sbase - suckless unix tools | |
git clone git://git.suckless.org/sbase | |
Log | |
Files | |
Refs | |
README | |
LICENSE | |
--- | |
xinstall.c (3531B) | |
--- | |
1 /* See LICENSE file for copyright and license details. */ | |
2 #include <grp.h> | |
3 #include <pwd.h> | |
4 #include <errno.h> | |
5 #include <fcntl.h> | |
6 #include <unistd.h> | |
7 #include <stdlib.h> | |
8 #include <string.h> | |
9 #include <dirent.h> | |
10 #include <sys/stat.h> | |
11 #include <sys/wait.h> | |
12 | |
13 #include "util.h" | |
14 | |
15 static int Dflag = 0; | |
16 static gid_t group; | |
17 static uid_t owner; | |
18 static mode_t mode = 0755; | |
19 | |
20 static void | |
21 make_dir(char *dir, int was_missing) | |
22 { | |
23 if (!mkdir(dir, was_missing ? 0755 : mode)) { | |
24 if (!was_missing && (lchown(dir, owner, group) < 0)) | |
25 eprintf("lchmod %s:", dir); | |
26 } else if (errno != EEXIST) { | |
27 eprintf("mkdir %s:", dir); | |
28 } | |
29 } | |
30 | |
31 static void | |
32 make_dirs(char *dir, int was_missing) | |
33 { | |
34 char *p; | |
35 for (p = strchr(dir + (dir[0] == '/'), '/'); p; p = strchr(p + 1… | |
36 *p = '\0'; | |
37 make_dir(dir, was_missing); | |
38 *p = '/'; | |
39 } | |
40 make_dir(dir, was_missing); | |
41 } | |
42 | |
43 static int | |
44 install(const char *s1, const char *s2, int depth) | |
45 { | |
46 int f1, f2; | |
47 | |
48 if ((f1 = open(s1, O_RDONLY)) < 0) | |
49 eprintf("open %s:", s1); | |
50 if ((f2 = creat(s2, 0600)) < 0) { | |
51 if (unlink(s2) < 0 && errno != ENOENT) | |
52 eprintf("unlink %s:", s2); | |
53 if ((f2 = creat(s2, 0600)) < 0) | |
54 eprintf("creat %s:", s2); | |
55 } | |
56 if (concat(f1, s1, f2, s2) < 0) | |
57 goto fail; | |
58 if (fchmod(f2, mode) < 0) { | |
59 weprintf("fchmod %s:", s2); | |
60 goto fail; | |
61 } | |
62 if (fchown(f2, owner, group) < 0) { | |
63 weprintf("fchown %s:", s2); | |
64 goto fail; | |
65 } | |
66 | |
67 close(f1); | |
68 close(f2); | |
69 | |
70 return 0; | |
71 | |
72 fail: | |
73 unlink(s2); | |
74 exit(1); | |
75 } | |
76 | |
77 static void | |
78 usage(void) | |
79 { | |
80 eprintf("usage: %s [-g group] [-o owner] [-m mode] (-d dir ... |… | |
81 } | |
82 | |
83 int | |
84 main(int argc, char *argv[]) | |
85 { | |
86 int dflag = 0; | |
87 char *gflag = 0; | |
88 char *oflag = 0; | |
89 char *mflag = 0; | |
90 char *tflag = 0; | |
91 struct group *gr; | |
92 struct passwd *pw; | |
93 struct stat st; | |
94 char *p; | |
95 | |
96 ARGBEGIN { | |
97 case 'c': | |
98 /* no-op for compatibility */ | |
99 break; | |
100 case 'd': | |
101 dflag = 1; | |
102 break; | |
103 case 'D': | |
104 Dflag = 1; | |
105 break; | |
106 case 's': | |
107 /* no-op for compatibility */ | |
108 break; | |
109 case 'g': | |
110 gflag = EARGF(usage()); | |
111 break; | |
112 case 'o': | |
113 oflag = EARGF(usage()); | |
114 break; | |
115 case 'm': | |
116 mflag = EARGF(usage()); | |
117 break; | |
118 case 't': | |
119 tflag = EARGF(usage()); | |
120 break; | |
121 default: | |
122 usage(); | |
123 } ARGEND | |
124 | |
125 if (argc < 1 + (!tflag & !dflag) || dflag & (Dflag | !!tflag)) | |
126 usage(); | |
127 | |
128 if (gflag) { | |
129 errno = 0; | |
130 gr = getgrnam(gflag); | |
131 if (gr) { | |
132 group = gr->gr_gid; | |
133 } else { | |
134 if (errno) | |
135 eprintf("getgrnam %s:", gflag); | |
136 group = estrtonum(gflag, 0, UINT_MAX); | |
137 } | |
138 } else { | |
139 group = getgid(); | |
140 } | |
141 | |
142 if (oflag) { | |
143 errno = 0; | |
144 pw = getpwnam(oflag); | |
145 if (pw) { | |
146 owner = pw->pw_uid; | |
147 } else { | |
148 if (errno) | |
149 eprintf("getpwnam %s:", oflag); | |
150 owner = estrtonum(oflag, 0, UINT_MAX); | |
151 } | |
152 } else { | |
153 owner = getuid(); | |
154 } | |
155 | |
156 if (mflag) | |
157 mode = parsemode(mflag, mode, 0); | |
158 | |
159 if (dflag) { | |
160 for (; *argv; argc--, argv++) | |
161 make_dirs(*argv, 0); | |
162 return 0; | |
163 } | |
164 | |
165 if (tflag) { | |
166 argv = memmove(argv - 1, argv, argc * sizeof(*argv)); | |
167 argv[argc++] = tflag; | |
168 } | |
169 if (tflag || argc > 2) { | |
170 if (stat(argv[argc - 1], &st) < 0) { | |
171 if ((errno == ENOENT) && Dflag) { | |
172 make_dirs(argv[argc - 1], 1); | |
173 } else { | |
174 eprintf("stat %s:", argv[argc - 1]); | |
175 } | |
176 } else if (!S_ISDIR(st.st_mode)) { | |
177 eprintf("%s: not a directory\n", argv[argc - 1]); | |
178 } | |
179 } | |
180 if (stat(argv[argc - 1], &st) < 0) { | |
181 if (errno != ENOENT) | |
182 eprintf("stat %s:", argv[argc - 1]); | |
183 if (tflag || Dflag || argc > 2) { | |
184 if ((p = strrchr(argv[argc - 1], '/')) != NULL) { | |
185 *p = '\0'; | |
186 make_dirs(argv[argc - 1], 1); | |
187 *p = '/'; | |
188 } | |
189 } | |
190 } | |
191 enmasse(argc, argv, install); | |
192 | |
193 return 0; | |
194 } |