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