date and time created 88/10/21 11:13:20 by bostic
[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
57d64e93 25static char sccsid[] = "@(#)xinstall.c 5.13 (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
57d64e93
KB
45static struct passwd *pp;
46static struct group *gp;
47static int docopy, dostrip, mode = 0755;
48static char *group, *owner, pathbuf[MAXPATHLEN];
6544b76d 49
9daf6813 50main(argc, argv)
f31e9bdc
KB
51 int argc;
52 char **argv;
9daf6813 53{
f31e9bdc
KB
54 extern char *optarg;
55 extern int optind;
56 struct stat from_sb, to_sb;
57 int ch, no_target;
58 char *to_name;
9daf6813
KB
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;
6544b76d 83 if (argc < 2)
9daf6813
KB
84 usage();
85
5f10a190 86 /* get group and owner id's */
cd03af1a 87 if (group && !(gp = getgrnam(group))) {
5f10a190
KB
88 fprintf(stderr, "install: unknown group %s.\n", group);
89 exit(1);
90 }
cd03af1a 91 if (owner && !(pp = getpwnam(owner))) {
5f10a190
KB
92 fprintf(stderr, "install: unknown user %s.\n", owner);
93 exit(1);
94 }
95
6544b76d 96 no_target = stat(to_name = argv[argc - 1], &to_sb);
20264d07 97 if (!no_target && (to_sb.st_mode & S_IFMT) == S_IFDIR) {
6544b76d
KB
98 for (; *argv != to_name; ++argv)
99 install(*argv, to_name, YES);
100 exit(0);
9daf6813
KB
101 }
102
6544b76d
KB
103 /* can't do file1 file2 directory/file */
104 if (argc != 2)
105 usage();
426871e1 106
6544b76d
KB
107 if (!no_target) {
108 if (stat(*argv, &from_sb)) {
109 fprintf(stderr, "install: can't find %s.\n", *argv);
110 exit(1);
426871e1 111 }
20264d07 112 if ((to_sb.st_mode & S_IFMT) != S_IFREG) {
6544b76d 113 fprintf(stderr, "install: %s isn't a regular file.\n", to_name);
426871e1 114 exit(1);
9daf6813
KB
115 }
116 if (to_sb.st_dev == from_sb.st_dev && to_sb.st_ino == from_sb.st_ino) {
6544b76d 117 fprintf(stderr, "install: %s and %s are the same file.\n", *argv, to_name);
9daf6813
KB
118 exit(1);
119 }
120 /* unlink now... avoid ETXTBSY errors later */
6544b76d
KB
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 */
6544b76d 131install(from_name, to_name, isdir)
f31e9bdc
KB
132 char *from_name, *to_name;
133 int isdir;
6544b76d 134{
f31e9bdc
KB
135 struct stat from_sb;
136 int devnull, from_fd, to_fd;
137 char *C, *rindex();
6544b76d
KB
138
139 /* if try to install "/dev/null" to a directory, fails */
a541407a
KB
140 if (isdir || strcmp(from_name, "/dev/null")) {
141 if (stat(from_name, &from_sb)) {
6544b76d
KB
142 fprintf(stderr, "install: can't find %s.\n", from_name);
143 exit(1);
144 }
20264d07 145 if ((from_sb.st_mode & S_IFMT) != S_IFREG) {
6544b76d
KB
146 fprintf(stderr, "install: %s isn't a regular file.\n", from_name);
147 exit(1);
148 }
a541407a
KB
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;
9daf6813 155 }
a541407a
KB
156 else
157 devnull = YES;
6544b76d
KB
158
159 /* unlink now... avoid ETXTBSY errors later */
160 (void)unlink(to_name);
161
a541407a 162 /* create target */
6544b76d 163 if ((to_fd = open(to_name, O_CREAT|O_WRONLY|O_TRUNC, 0)) < 0) {
75e0e63a 164 PERROR("install: ", to_name);
9daf6813
KB
165 exit(1);
166 }
a541407a
KB
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 */
9daf6813 182 if (fchmod(to_fd, mode)) {
75e0e63a 183 PERROR("install: fchmod: ", to_name);
5f10a190 184 bad();
9daf6813 185 }
a541407a
KB
186 if ((group || owner) && fchown(to_fd, owner ? pp->pw_uid : -1,
187 group ? gp->gr_gid : -1)) {
75e0e63a 188 PERROR("install: fchown: ", to_name);
5f10a190 189 bad();
9daf6813 190 }
6544b76d 191 (void)close(to_fd);
9daf6813
KB
192}
193
194/*
195 * strip --
196 * copy file, strip(1)'ing it at the same time
197 */
6544b76d 198strip(from_fd, from_name, to_fd, to_name)
f31e9bdc
KB
199 register int from_fd, to_fd;
200 char *from_name, *to_name;
9daf6813 201{
f31e9bdc
KB
202 typedef struct exec EXEC;
203 register long size;
204 register int n;
205 EXEC head;
206 char buf[MAXBSIZE];
207 off_t lseek();
9daf6813 208
9daf6813
KB
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);
5f10a190 211 bad();
9daf6813
KB
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)) {
75e0e63a 219 PERROR("install: write: ", to_name);
5f10a190 220 bad();
9daf6813
KB
221 }
222 for (; size; size -= n)
a541407a 223 /* sizeof(buf) guaranteed to fit in an int */
9daf6813
KB
224 if ((n = read(from_fd, buf, (int)MIN(size, sizeof(buf)))) <= 0)
225 break;
226 else if (write(to_fd, buf, n) != n) {
75e0e63a 227 PERROR("install: write: ", to_name);
5f10a190 228 bad();
9daf6813 229 }
5f10a190
KB
230 if (size) {
231 fprintf(stderr, "install: read: %s: premature EOF.\n", from_name);
232 bad();
233 }
9daf6813 234 if (n == -1) {
75e0e63a 235 PERROR("install: read: ", from_name);
5f10a190 236 bad();
9daf6813
KB
237 }
238 }
6544b76d 239 else {
cd03af1a 240 (void)lseek(from_fd, 0L, L_SET);
6544b76d
KB
241 copy(from_fd, from_name, to_fd, to_name);
242 }
243}
244
245/*
246 * copy --
247 * copy from one file to another
248 */
6544b76d 249copy(from_fd, from_name, to_fd, to_name)
f31e9bdc
KB
250 register int from_fd, to_fd;
251 char *from_name, *to_name;
6544b76d 252{
f31e9bdc
KB
253 register int n;
254 char buf[MAXBSIZE];
6544b76d
KB
255
256 while ((n = read(from_fd, buf, sizeof(buf))) > 0)
257 if (write(to_fd, buf, n) != n) {
75e0e63a 258 PERROR("install: write: ", to_name);
6544b76d
KB
259 bad();
260 }
261 if (n == -1) {
75e0e63a 262 PERROR("install: read: ", from_name);
6544b76d
KB
263 bad();
264 }
9daf6813
KB
265}
266
267/*
268 * atoo --
269 * octal string to int
270 */
5f10a190 271atoo(str)
f31e9bdc 272 register char *str;
9daf6813 273{
f31e9bdc 274 register int val;
9daf6813 275
5f10a190
KB
276 for (val = 0; isdigit(*str); ++str)
277 val = val * 8 + *str - '0';
9daf6813
KB
278 return(val);
279}
280
281/*
6544b76d
KB
282 * bad --
283 * remove created target and die
9daf6813 284 */
6544b76d 285bad()
9daf6813 286{
6544b76d 287 (void)unlink(pathbuf);
9daf6813
KB
288 exit(1);
289}
5f10a190
KB
290
291/*
6544b76d
KB
292 * usage --
293 * print a usage message and die
5f10a190 294 */
6544b76d 295usage()
5f10a190 296{
75e0e63a 297 fputs("usage: install [-cs] [-g group] [-m mode] [-o owner] file1 file2;\n\tor file1 ... fileN directory\n", stderr);
5f10a190
KB
298 exit(1);
299}