Commit | Line | Data |
---|---|---|
9daf6813 KB |
1 | /* |
2 | * Copyright (c) 1987 Regents of the University of California. | |
3 | * All rights reserved. The Berkeley software License Agreement | |
4 | * specifies the terms and conditions for redistribution. | |
5 | */ | |
6 | ||
7 | #ifndef lint | |
8 | char copyright[] = | |
9 | "@(#) Copyright (c) 1987 Regents of the University of California.\n\ | |
10 | All rights reserved.\n"; | |
11 | #endif not lint | |
12 | ||
13 | #ifndef lint | |
ee0a9579 | 14 | static char sccsid[] = "@(#)xinstall.c 5.5 (Berkeley) %G%"; |
9daf6813 KB |
15 | #endif not lint |
16 | ||
17 | #include <sys/param.h> | |
18 | #include <sys/stat.h> | |
19 | #include <sys/file.h> | |
20 | #include <a.out.h> | |
21 | #include <grp.h> | |
22 | #include <pwd.h> | |
23 | #include <stdio.h> | |
24 | #include <ctype.h> | |
25 | ||
26 | #define YES 1 /* yes/true */ | |
5f10a190 KB |
27 | #define DEF_GROUP "staff" /* default group */ |
28 | #define DEF_OWNER "root" /* default owner */ | |
9daf6813 KB |
29 | |
30 | static int docopy, dostrip, | |
31 | mode = 0755; | |
32 | static char *group = DEF_GROUP, | |
5f10a190 KB |
33 | *owner = DEF_OWNER, |
34 | *path; | |
99f379a7 KB |
35 | extern int errno; |
36 | extern char *sys_errlist[]; | |
9daf6813 KB |
37 | |
38 | main(argc, argv) | |
39 | int argc; | |
40 | char **argv; | |
41 | { | |
99f379a7 KB |
42 | extern char *optarg; |
43 | extern int optind; | |
9daf6813 KB |
44 | register int to_fd; |
45 | struct stat from_sb, to_sb; | |
46 | struct passwd *pp; | |
47 | struct group *gp; | |
426871e1 | 48 | int ch, devnull; |
5f10a190 | 49 | char pbuf[MAXPATHLEN]; |
9daf6813 KB |
50 | |
51 | while ((ch = getopt(argc, argv, "cg:m:o:s")) != EOF) | |
52 | switch((char)ch) { | |
53 | case 'c': | |
54 | docopy = YES; | |
55 | break; | |
56 | case 'g': | |
57 | group = optarg; | |
58 | break; | |
59 | case 'm': | |
60 | mode = atoo(optarg); | |
61 | break; | |
62 | case 'o': | |
63 | owner = optarg; | |
64 | break; | |
65 | case 's': | |
66 | dostrip = YES; | |
67 | break; | |
68 | case '?': | |
69 | default: | |
70 | usage(); | |
71 | } | |
72 | argc -= optind; | |
73 | argv += optind; | |
74 | if (argc != 2) | |
75 | usage(); | |
76 | ||
5f10a190 KB |
77 | /* get group and owner id's */ |
78 | if (!(gp = getgrnam(group))) { | |
79 | fprintf(stderr, "install: unknown group %s.\n", group); | |
80 | exit(1); | |
81 | } | |
82 | if (!(pp = getpwnam(owner))) { | |
83 | fprintf(stderr, "install: unknown user %s.\n", owner); | |
84 | exit(1); | |
85 | } | |
86 | ||
9daf6813 KB |
87 | /* check source */ |
88 | if (stat(argv[0], &from_sb)) { | |
89 | fprintf(stderr, "install: fstat: %s: %s\n", argv[0], sys_errlist[errno]); | |
90 | exit(1); | |
91 | } | |
426871e1 KB |
92 | /* special case for removing files */ |
93 | devnull = !strcmp(argv[0], "/dev/null"); | |
94 | if (!devnull && !(from_sb.st_mode & S_IFREG)) { | |
9daf6813 KB |
95 | fprintf(stderr, "install: %s isn't a regular file.\n", argv[0]); |
96 | exit(1); | |
97 | } | |
98 | ||
99 | /* build target path, find out if target is same as source */ | |
100 | if (!stat(path = argv[1], &to_sb)) { | |
101 | if (to_sb.st_mode & S_IFDIR) { | |
426871e1 KB |
102 | char *C, *rindex(); |
103 | ||
104 | (void)sprintf(path = pbuf, "%s/%s", argv[1], (C = rindex(argv[0], '/')) ? ++C : argv[0]); | |
9daf6813 KB |
105 | if (stat(path, &to_sb)) |
106 | goto nocompare; | |
426871e1 KB |
107 | } |
108 | if (!(to_sb.st_mode & S_IFREG)) { | |
109 | fprintf(stderr, "install: %s isn't a regular file.\n", path); | |
110 | exit(1); | |
9daf6813 KB |
111 | } |
112 | if (to_sb.st_dev == from_sb.st_dev && to_sb.st_ino == from_sb.st_ino) { | |
113 | fprintf(stderr, "install: %s and %s are the same file.\n", argv[0], path); | |
114 | exit(1); | |
115 | } | |
116 | /* unlink now... avoid ETXTBSY errors later */ | |
117 | (void)unlink(path); | |
118 | } | |
119 | ||
120 | nocompare: | |
9daf6813 KB |
121 | /* open target, set mode, owner, group */ |
122 | if ((to_fd = open(path, O_CREAT|O_WRONLY|O_TRUNC, 0)) < 0) { | |
123 | fprintf(stderr, "install: %s: %s\n", path, sys_errlist[errno]); | |
124 | exit(1); | |
125 | } | |
126 | if (fchmod(to_fd, mode)) { | |
127 | fprintf(stderr, "install: fchmod: %s: %s\n", path, sys_errlist[errno]); | |
5f10a190 | 128 | bad(); |
9daf6813 KB |
129 | } |
130 | if (fchown(to_fd, pp->pw_uid, gp->gr_gid)) { | |
131 | fprintf(stderr, "install: fchown: %s: %s\n", path, sys_errlist[errno]); | |
5f10a190 | 132 | bad(); |
9daf6813 KB |
133 | } |
134 | ||
426871e1 KB |
135 | if (devnull) |
136 | exit(0); | |
137 | ||
9daf6813 KB |
138 | if (dostrip) { |
139 | strip(to_fd, argv[0], path); | |
140 | if (docopy) | |
141 | exit(0); | |
142 | } | |
143 | else if (docopy) { | |
144 | copy(argv[0], to_fd, path); | |
145 | exit(0); | |
146 | } | |
147 | else if (rename(argv[0], path)) | |
148 | copy(argv[0], to_fd, path); | |
149 | (void)unlink(argv[0]); | |
150 | exit(0); | |
151 | } | |
152 | ||
153 | /* | |
154 | * copy -- | |
155 | * copy from one file to another | |
156 | */ | |
157 | static | |
158 | copy(from_name, to_fd, to_name) | |
159 | register int to_fd; | |
160 | char *from_name, *to_name; | |
161 | { | |
162 | register int n, from_fd; | |
163 | char buf[MAXBSIZE]; | |
164 | ||
165 | if ((from_fd = open(from_name, O_RDONLY, 0)) < 0) { | |
166 | fprintf(stderr, "install: open: %s: %s\n", from_name, sys_errlist[errno]); | |
5f10a190 | 167 | bad(); |
9daf6813 KB |
168 | } |
169 | while ((n = read(from_fd, buf, sizeof(buf))) > 0) | |
170 | if (write(to_fd, buf, n) != n) { | |
171 | fprintf(stderr, "install: write: %s: %s\n", to_name, sys_errlist[errno]); | |
5f10a190 | 172 | bad(); |
9daf6813 KB |
173 | } |
174 | if (n == -1) { | |
5f10a190 KB |
175 | fprintf(stderr, "install: read: %s: %s\n", from_name, sys_errlist[errno]); |
176 | bad(); | |
9daf6813 KB |
177 | } |
178 | } | |
179 | ||
180 | /* | |
181 | * strip -- | |
182 | * copy file, strip(1)'ing it at the same time | |
183 | */ | |
184 | static | |
185 | strip(to_fd, from_name, to_name) | |
186 | register int to_fd; | |
187 | char *from_name, *to_name; | |
188 | { | |
189 | typedef struct exec EXEC; | |
190 | register long size; | |
191 | register int n, from_fd; | |
192 | EXEC head; | |
193 | char buf[MAXBSIZE]; | |
194 | ||
195 | if ((from_fd = open(from_name, O_RDONLY, 0)) < 0) { | |
196 | fprintf(stderr, "install: open: %s: %s\n", from_name, sys_errlist[errno]); | |
5f10a190 | 197 | bad(); |
9daf6813 KB |
198 | } |
199 | if (read(from_fd, (char *)&head, sizeof(head)) < 0 || N_BADMAG(head)) { | |
200 | fprintf(stderr, "install: %s not in a.out format.\n", from_name); | |
5f10a190 | 201 | bad(); |
9daf6813 KB |
202 | } |
203 | if (head.a_syms || head.a_trsize || head.a_drsize) { | |
204 | size = (long)head.a_text + head.a_data; | |
205 | head.a_syms = head.a_trsize = head.a_drsize = 0; | |
206 | if (head.a_magic == ZMAGIC) | |
207 | size += getpagesize() - sizeof(EXEC); | |
208 | if (write(to_fd, (char *)&head, sizeof(EXEC)) != sizeof(EXEC)) { | |
209 | fprintf(stderr, "install: write: %s: %s\n", to_name, sys_errlist[errno]); | |
5f10a190 | 210 | bad(); |
9daf6813 KB |
211 | } |
212 | for (; size; size -= n) | |
213 | if ((n = read(from_fd, buf, (int)MIN(size, sizeof(buf)))) <= 0) | |
214 | break; | |
215 | else if (write(to_fd, buf, n) != n) { | |
216 | fprintf(stderr, "install: write: %s: %s\n", to_name, sys_errlist[errno]); | |
5f10a190 | 217 | bad(); |
9daf6813 | 218 | } |
5f10a190 KB |
219 | if (size) { |
220 | fprintf(stderr, "install: read: %s: premature EOF.\n", from_name); | |
221 | bad(); | |
222 | } | |
9daf6813 KB |
223 | if (n == -1) { |
224 | fprintf(stderr, "install: read: %s: %s\n", from_name, sys_errlist[errno]); | |
5f10a190 | 225 | bad(); |
9daf6813 KB |
226 | } |
227 | } | |
228 | } | |
229 | ||
230 | /* | |
231 | * atoo -- | |
232 | * octal string to int | |
233 | */ | |
234 | static | |
5f10a190 KB |
235 | atoo(str) |
236 | register char *str; | |
9daf6813 | 237 | { |
5f10a190 | 238 | register int val; |
9daf6813 | 239 | |
5f10a190 KB |
240 | for (val = 0; isdigit(*str); ++str) |
241 | val = val * 8 + *str - '0'; | |
9daf6813 KB |
242 | return(val); |
243 | } | |
244 | ||
245 | /* | |
246 | * usage -- | |
247 | * print a usage message and die | |
248 | */ | |
249 | static | |
250 | usage() | |
251 | { | |
252 | fputs("usage: install [-cs] [-g group] [-m mode] [-o owner] source destination\n", stderr); | |
253 | exit(1); | |
254 | } | |
5f10a190 KB |
255 | |
256 | /* | |
257 | * bad -- | |
258 | * remove created target and die | |
259 | */ | |
260 | static | |
261 | bad() | |
262 | { | |
263 | (void)unlink(path); | |
264 | exit(1); | |
265 | } |