add Berkeley specific copyright
[unix-history] / usr / src / usr.bin / xinstall / xinstall.c
CommitLineData
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
19char 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 25static 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
45static struct passwd *pp;
46static struct group *gp;
47static int docopy, dostrip,
48 mode = 0755;
cd03af1a
KB
49static char *group, *owner,
50 pathbuf[MAXPATHLEN];
6544b76d 51
9daf6813 52main(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 */
133static
134install(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 */
201static
6544b76d 202strip(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 */
253static
254copy(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 */
276static
5f10a190 277atoo(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 */
291static
6544b76d 292bad()
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 */
302static
6544b76d 303usage()
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}