Commit | Line | Data |
---|---|---|
9daf6813 KB |
1 | /* |
2 | * Copyright (c) 1987 Regents of the University of California. | |
a541407a KB |
3 | * All rights reserved. |
4 | * | |
5 | * Redistribution and use in source and binary forms are permitted | |
5e8b0e60 KB |
6 | * provided that the above copyright notice and this paragraph are |
7 | * duplicated in all such forms and that any documentation, | |
8 | * advertising materials, and other materials related to such | |
9 | * distribution and use acknowledge that the software was developed | |
10 | * by the University of California, Berkeley. The name of the | |
11 | * University may not be used to endorse or promote products derived | |
12 | * from this software without specific prior written permission. | |
13 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR | |
14 | * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED | |
15 | * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. | |
9daf6813 KB |
16 | */ |
17 | ||
18 | #ifndef lint | |
19 | char copyright[] = | |
20 | "@(#) Copyright (c) 1987 Regents of the University of California.\n\ | |
21 | All rights reserved.\n"; | |
a541407a | 22 | #endif /* not lint */ |
9daf6813 KB |
23 | |
24 | #ifndef lint | |
f31e9bdc | 25 | static char sccsid[] = "@(#)xinstall.c 5.12 (Berkeley) %G%"; |
a541407a | 26 | #endif /* not lint */ |
9daf6813 KB |
27 | |
28 | #include <sys/param.h> | |
29 | #include <sys/stat.h> | |
30 | #include <sys/file.h> | |
31 | #include <a.out.h> | |
32 | #include <grp.h> | |
33 | #include <pwd.h> | |
34 | #include <stdio.h> | |
35 | #include <ctype.h> | |
36 | ||
a541407a KB |
37 | #define YES 1 /* yes/true */ |
38 | #define NO 0 /* no/false */ | |
9daf6813 | 39 | |
75e0e63a KB |
40 | #define PERROR(head, msg) { \ |
41 | fputs(head, stderr); \ | |
42 | perror(msg); \ | |
43 | } | |
9daf6813 | 44 | |
6544b76d KB |
45 | static struct passwd *pp; |
46 | static struct group *gp; | |
47 | static int docopy, dostrip, | |
48 | mode = 0755; | |
cd03af1a KB |
49 | static char *group, *owner, |
50 | pathbuf[MAXPATHLEN]; | |
6544b76d | 51 | |
9daf6813 | 52 | main(argc, argv) |
f31e9bdc KB |
53 | int argc; |
54 | char **argv; | |
9daf6813 | 55 | { |
f31e9bdc KB |
56 | extern char *optarg; |
57 | extern int optind; | |
58 | struct stat from_sb, to_sb; | |
59 | int ch, no_target; | |
60 | char *to_name; | |
9daf6813 KB |
61 | |
62 | while ((ch = getopt(argc, argv, "cg:m:o:s")) != EOF) | |
63 | switch((char)ch) { | |
64 | case 'c': | |
65 | docopy = YES; | |
66 | break; | |
67 | case 'g': | |
68 | group = optarg; | |
69 | break; | |
70 | case 'm': | |
71 | mode = atoo(optarg); | |
72 | break; | |
73 | case 'o': | |
74 | owner = optarg; | |
75 | break; | |
76 | case 's': | |
77 | dostrip = YES; | |
78 | break; | |
79 | case '?': | |
80 | default: | |
81 | usage(); | |
82 | } | |
83 | argc -= optind; | |
84 | argv += optind; | |
6544b76d | 85 | if (argc < 2) |
9daf6813 KB |
86 | usage(); |
87 | ||
5f10a190 | 88 | /* get group and owner id's */ |
cd03af1a | 89 | if (group && !(gp = getgrnam(group))) { |
5f10a190 KB |
90 | fprintf(stderr, "install: unknown group %s.\n", group); |
91 | exit(1); | |
92 | } | |
cd03af1a | 93 | if (owner && !(pp = getpwnam(owner))) { |
5f10a190 KB |
94 | fprintf(stderr, "install: unknown user %s.\n", owner); |
95 | exit(1); | |
96 | } | |
97 | ||
6544b76d | 98 | no_target = stat(to_name = argv[argc - 1], &to_sb); |
20264d07 | 99 | if (!no_target && (to_sb.st_mode & S_IFMT) == S_IFDIR) { |
6544b76d KB |
100 | for (; *argv != to_name; ++argv) |
101 | install(*argv, to_name, YES); | |
102 | exit(0); | |
9daf6813 KB |
103 | } |
104 | ||
6544b76d KB |
105 | /* can't do file1 file2 directory/file */ |
106 | if (argc != 2) | |
107 | usage(); | |
426871e1 | 108 | |
6544b76d KB |
109 | if (!no_target) { |
110 | if (stat(*argv, &from_sb)) { | |
111 | fprintf(stderr, "install: can't find %s.\n", *argv); | |
112 | exit(1); | |
426871e1 | 113 | } |
20264d07 | 114 | if ((to_sb.st_mode & S_IFMT) != S_IFREG) { |
6544b76d | 115 | fprintf(stderr, "install: %s isn't a regular file.\n", to_name); |
426871e1 | 116 | exit(1); |
9daf6813 KB |
117 | } |
118 | if (to_sb.st_dev == from_sb.st_dev && to_sb.st_ino == from_sb.st_ino) { | |
6544b76d | 119 | fprintf(stderr, "install: %s and %s are the same file.\n", *argv, to_name); |
9daf6813 KB |
120 | exit(1); |
121 | } | |
122 | /* unlink now... avoid ETXTBSY errors later */ | |
6544b76d KB |
123 | (void)unlink(to_name); |
124 | } | |
125 | install(*argv, to_name, NO); | |
126 | exit(0); | |
127 | } | |
128 | ||
129 | /* | |
130 | * install -- | |
131 | * build a path name and install the file | |
132 | */ | |
133 | static | |
134 | install(from_name, to_name, isdir) | |
f31e9bdc KB |
135 | char *from_name, *to_name; |
136 | int isdir; | |
6544b76d | 137 | { |
f31e9bdc KB |
138 | struct stat from_sb; |
139 | int devnull, from_fd, to_fd; | |
140 | char *C, *rindex(); | |
6544b76d KB |
141 | |
142 | /* if try to install "/dev/null" to a directory, fails */ | |
a541407a KB |
143 | if (isdir || strcmp(from_name, "/dev/null")) { |
144 | if (stat(from_name, &from_sb)) { | |
6544b76d KB |
145 | fprintf(stderr, "install: can't find %s.\n", from_name); |
146 | exit(1); | |
147 | } | |
20264d07 | 148 | if ((from_sb.st_mode & S_IFMT) != S_IFREG) { |
6544b76d KB |
149 | fprintf(stderr, "install: %s isn't a regular file.\n", from_name); |
150 | exit(1); | |
151 | } | |
a541407a KB |
152 | /* build the target path */ |
153 | if (isdir) { | |
154 | (void)sprintf(pathbuf, "%s/%s", to_name, (C = rindex(from_name, '/')) ? ++C : from_name); | |
155 | to_name = pathbuf; | |
156 | } | |
157 | devnull = NO; | |
9daf6813 | 158 | } |
a541407a KB |
159 | else |
160 | devnull = YES; | |
6544b76d KB |
161 | |
162 | /* unlink now... avoid ETXTBSY errors later */ | |
163 | (void)unlink(to_name); | |
164 | ||
a541407a | 165 | /* create target */ |
6544b76d | 166 | if ((to_fd = open(to_name, O_CREAT|O_WRONLY|O_TRUNC, 0)) < 0) { |
75e0e63a | 167 | PERROR("install: ", to_name); |
9daf6813 KB |
168 | exit(1); |
169 | } | |
a541407a KB |
170 | if (!devnull) { |
171 | if ((from_fd = open(from_name, O_RDONLY, 0)) < 0) { | |
172 | (void)unlink(to_name); | |
173 | PERROR("install: open: ", from_name); | |
174 | exit(1); | |
175 | } | |
176 | if (dostrip) | |
177 | strip(from_fd, from_name, to_fd, to_name); | |
178 | else | |
179 | copy(from_fd, from_name, to_fd, to_name); | |
180 | (void)close(from_fd); | |
181 | if (!docopy) | |
182 | (void)unlink(from_name); | |
183 | } | |
184 | /* set owner, group, mode for target */ | |
9daf6813 | 185 | if (fchmod(to_fd, mode)) { |
75e0e63a | 186 | PERROR("install: fchmod: ", to_name); |
5f10a190 | 187 | bad(); |
9daf6813 | 188 | } |
a541407a KB |
189 | if ((group || owner) && fchown(to_fd, owner ? pp->pw_uid : -1, |
190 | group ? gp->gr_gid : -1)) { | |
75e0e63a | 191 | PERROR("install: fchown: ", to_name); |
5f10a190 | 192 | bad(); |
9daf6813 | 193 | } |
6544b76d | 194 | (void)close(to_fd); |
9daf6813 KB |
195 | } |
196 | ||
197 | /* | |
198 | * strip -- | |
199 | * copy file, strip(1)'ing it at the same time | |
200 | */ | |
201 | static | |
6544b76d | 202 | strip(from_fd, from_name, to_fd, to_name) |
f31e9bdc KB |
203 | register int from_fd, to_fd; |
204 | char *from_name, *to_name; | |
9daf6813 | 205 | { |
f31e9bdc KB |
206 | typedef struct exec EXEC; |
207 | register long size; | |
208 | register int n; | |
209 | EXEC head; | |
210 | char buf[MAXBSIZE]; | |
211 | off_t lseek(); | |
9daf6813 | 212 | |
9daf6813 KB |
213 | if (read(from_fd, (char *)&head, sizeof(head)) < 0 || N_BADMAG(head)) { |
214 | fprintf(stderr, "install: %s not in a.out format.\n", from_name); | |
5f10a190 | 215 | bad(); |
9daf6813 KB |
216 | } |
217 | if (head.a_syms || head.a_trsize || head.a_drsize) { | |
218 | size = (long)head.a_text + head.a_data; | |
219 | head.a_syms = head.a_trsize = head.a_drsize = 0; | |
220 | if (head.a_magic == ZMAGIC) | |
221 | size += getpagesize() - sizeof(EXEC); | |
222 | if (write(to_fd, (char *)&head, sizeof(EXEC)) != sizeof(EXEC)) { | |
75e0e63a | 223 | PERROR("install: write: ", to_name); |
5f10a190 | 224 | bad(); |
9daf6813 KB |
225 | } |
226 | for (; size; size -= n) | |
a541407a | 227 | /* sizeof(buf) guaranteed to fit in an int */ |
9daf6813 KB |
228 | if ((n = read(from_fd, buf, (int)MIN(size, sizeof(buf)))) <= 0) |
229 | break; | |
230 | else if (write(to_fd, buf, n) != n) { | |
75e0e63a | 231 | PERROR("install: write: ", to_name); |
5f10a190 | 232 | bad(); |
9daf6813 | 233 | } |
5f10a190 KB |
234 | if (size) { |
235 | fprintf(stderr, "install: read: %s: premature EOF.\n", from_name); | |
236 | bad(); | |
237 | } | |
9daf6813 | 238 | if (n == -1) { |
75e0e63a | 239 | PERROR("install: read: ", from_name); |
5f10a190 | 240 | bad(); |
9daf6813 KB |
241 | } |
242 | } | |
6544b76d | 243 | else { |
cd03af1a | 244 | (void)lseek(from_fd, 0L, L_SET); |
6544b76d KB |
245 | copy(from_fd, from_name, to_fd, to_name); |
246 | } | |
247 | } | |
248 | ||
249 | /* | |
250 | * copy -- | |
251 | * copy from one file to another | |
252 | */ | |
253 | static | |
254 | copy(from_fd, from_name, to_fd, to_name) | |
f31e9bdc KB |
255 | register int from_fd, to_fd; |
256 | char *from_name, *to_name; | |
6544b76d | 257 | { |
f31e9bdc KB |
258 | register int n; |
259 | char buf[MAXBSIZE]; | |
6544b76d KB |
260 | |
261 | while ((n = read(from_fd, buf, sizeof(buf))) > 0) | |
262 | if (write(to_fd, buf, n) != n) { | |
75e0e63a | 263 | PERROR("install: write: ", to_name); |
6544b76d KB |
264 | bad(); |
265 | } | |
266 | if (n == -1) { | |
75e0e63a | 267 | PERROR("install: read: ", from_name); |
6544b76d KB |
268 | bad(); |
269 | } | |
9daf6813 KB |
270 | } |
271 | ||
272 | /* | |
273 | * atoo -- | |
274 | * octal string to int | |
275 | */ | |
276 | static | |
5f10a190 | 277 | atoo(str) |
f31e9bdc | 278 | register char *str; |
9daf6813 | 279 | { |
f31e9bdc | 280 | register int val; |
9daf6813 | 281 | |
5f10a190 KB |
282 | for (val = 0; isdigit(*str); ++str) |
283 | val = val * 8 + *str - '0'; | |
9daf6813 KB |
284 | return(val); |
285 | } | |
286 | ||
287 | /* | |
6544b76d KB |
288 | * bad -- |
289 | * remove created target and die | |
9daf6813 KB |
290 | */ |
291 | static | |
6544b76d | 292 | bad() |
9daf6813 | 293 | { |
6544b76d | 294 | (void)unlink(pathbuf); |
9daf6813 KB |
295 | exit(1); |
296 | } | |
5f10a190 KB |
297 | |
298 | /* | |
6544b76d KB |
299 | * usage -- |
300 | * print a usage message and die | |
5f10a190 KB |
301 | */ |
302 | static | |
6544b76d | 303 | usage() |
5f10a190 | 304 | { |
75e0e63a | 305 | fputs("usage: install [-cs] [-g group] [-m mode] [-o owner] file1 file2;\n\tor file1 ... fileN directory\n", stderr); |
5f10a190 KB |
306 | exit(1); |
307 | } |