xinstall.c - sbase - suckless unix tools
(HTM) git clone git://git.suckless.org/sbase
(DIR) Log
(DIR) Files
(DIR) Refs
(DIR) README
(DIR) 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 ... | [-D] (-t dest source ... | source ... dest))\n", argv0);
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 }