xref: /illumos-gate/usr/src/ucbcmd/install.d/install.c (revision 8b80e8cb6855118d46f605e91b5ed4ce83417395)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 1996 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
28 /*	  All Rights Reserved  	*/
29 
30 /*
31  * University Copyright- Copyright (c) 1982, 1986, 1988
32  * The Regents of the University of California
33  * All Rights Reserved
34  *
35  * University Acknowledgment- Portions of this document are derived from
36  * software developed by the University of California, Berkeley, and its
37  * contributors.
38  */
39 
40 #pragma ident	"%Z%%M%	%I%	%E% SMI"
41 
42 #include <sys/param.h>
43 #include <sys/types.h>
44 #include <sys/stat.h>
45 #include <sys/file.h>
46 #include <fcntl.h>
47 #include <grp.h>
48 #include <pwd.h>
49 #include <stdio.h>
50 #include <ctype.h>
51 #include <errno.h>
52 #include <locale.h>
53 
54 #define	DEF_GROUP	"staff"		/* default group */
55 #define	DEF_OWNER	"root"		/* default owner */
56 #define	DEF_MODE	0755		/* default mode */
57 
58 char *group = DEF_GROUP;
59 char *owner = DEF_OWNER;
60 int mode    = DEF_MODE;
61 int sflag = 0;
62 struct passwd *pp;
63 struct group *gp;
64 extern int errno;
65 int copy();
66 void usage();
67 
68 int
69 main(int argc, char **argv)
70 {
71 	extern char	*optarg;
72 	extern int	optind;
73 	struct stat	stb;
74 	char	*dirname;
75 	int	ch;
76 	int	i;
77 	int	rc;
78 	int	dflag = 0;
79 	int	gflag = 0;
80 	int	oflag = 0;
81 	int	mflag = 0;
82 
83 	(void) setlocale(LC_ALL, "");
84 
85 #if !defined(TEXT_DOMAIN)
86 #define TEXT_DOMAIN "SYS_TEST"
87 #endif
88 	(void) textdomain(TEXT_DOMAIN);
89 
90 	while ((ch = getopt(argc, argv, "dcg:o:m:s")) != EOF)
91 		switch((char)ch) {
92 		case 'c':
93 			break;	/* always do "copy" */
94 		case 'd':
95 			dflag++;
96 			break;
97 		case 'g':
98 			gflag++;
99 			group = optarg;
100 			break;
101 		case 'm':
102 			mflag++;
103 			mode = atoo(optarg);
104 			break;
105 		case 'o':
106 			oflag++;
107 			owner = optarg;
108 			break;
109 		case 's':
110 			sflag++;
111 			break;
112 		case '?':
113 		default:
114 			usage();
115 		}
116 	argc -= optind;
117 	argv += optind;
118 
119 	/* get group and owner id's */
120 	if (!(gp = getgrnam(group))) {
121 		fprintf(stderr, gettext("install: unknown group %s.\n"), group);
122 		exit(1);
123 	}
124 	if (!(pp = getpwnam(owner))) {
125 		fprintf(stderr, gettext("install: unknown user %s.\n"), owner);
126 		exit(1);
127 	}
128 
129 	if (dflag) {		/* install a directory */
130 		int exists = 0;
131 
132 		if (argc != 1)
133 			usage();
134 		dirname = argv[0];
135 		if (mkdirp(dirname, 0777) < 0) {
136 			exists = errno == EEXIST;
137 			if (!exists) {
138 				fprintf(stderr, gettext("install: mkdir: %s: %s\n"), dirname, strerror(errno));
139 				exit(1);
140 			}
141 		}
142 		if (stat(dirname, &stb) < 0) {
143 			fprintf(stderr, gettext("install: stat: %s: %s\n"), dirname, strerror(errno));
144 			exit(1);
145 		}
146 		if ((stb.st_mode&S_IFMT) != S_IFDIR) {
147 			fprintf(stderr, gettext("install: %s is not a directory\n"), dirname);
148 		}
149 		/* make sure directory setgid bit is inherited */
150 		mode = (mode & ~S_ISGID) | (stb.st_mode & S_ISGID);
151 		if (mflag && chmod(dirname, mode)) {
152 			fprintf(stderr, gettext("install: chmod: %s: %s\n"), dirname, strerror(errno));
153 			if (!exists)
154 				(void) unlink(dirname);
155 			exit(1) ;
156 		}
157 		if (oflag && chown(dirname, pp->pw_uid, -1) && errno != EPERM) {
158 			fprintf(stderr, gettext("install: chown: %s: %s\n"), dirname, strerror(errno));
159 			if (!exists)
160 				(void) unlink(dirname);
161 			exit(1) ;
162 		}
163 		if (gflag && chown(dirname, -1, gp->gr_gid) && errno != EPERM) {
164 			fprintf(stderr, gettext("install: chgrp: %s: %s\n"), dirname, strerror(errno));
165 			if (!exists)
166 				(void) unlink(dirname);
167 			exit(1) ;
168 		}
169 		exit(0);
170 	}
171 
172 	if (argc < 2)
173 		usage();
174 
175         if (argc > 2) {		/* last arg must be a directory */
176                 if (stat(argv[argc-1], &stb) < 0)
177                         usage();
178                 if ((stb.st_mode&S_IFMT) != S_IFDIR)
179                         usage();
180         }
181         rc = 0;
182         for (i = 0; i < argc-1; i++)
183                 rc |= install(argv[i], argv[argc-1]);
184         return (rc);
185 }
186 
187 int
188 install(from, to)
189 	char *from, *to;
190 {
191 	int to_fd;
192 	int devnull;
193 	int status = 0;
194 	char *path;
195 	struct stat from_sb, to_sb;
196 	static char pbuf[MAXPATHLEN];
197 	char buf[MAXPATHLEN + 10];
198 
199 	/* check source */
200 	if (stat(from, &from_sb)) {
201 		fprintf(stderr, gettext("install: %s: %s\n"), from, strerror(errno));
202 		return (1);
203 	}
204 	/* special case for removing files */
205 	devnull = !strcmp(from, "/dev/null");
206 	if (!devnull && !((from_sb.st_mode&S_IFMT) == S_IFREG)) {
207 		fprintf(stderr, gettext("install: %s isn't a regular file.\n"), from);
208 		return (1);
209 	}
210 
211 	/* build target path, find out if target is same as source */
212 	if (!stat(path = to, &to_sb)) {
213 		if ((to_sb.st_mode&S_IFMT) == S_IFDIR) {
214 			char *C, *strrchr();
215 
216 			(void) sprintf(path = pbuf, "%s/%s", to, (C = strrchr(from, '/')) ? ++C : from);
217 			if (stat(path, &to_sb))
218 				goto nocompare;
219 		}
220 		if ((to_sb.st_mode&S_IFMT) != S_IFREG) {
221 			fprintf(stderr, gettext("install: %s isn't a regular file.\n"), path);
222 			return (1);
223 		}
224 		if (to_sb.st_dev == from_sb.st_dev && to_sb.st_ino == from_sb.st_ino) {
225 			fprintf(stderr, gettext("install: %s and %s are the same file.\n"), from, path);
226 			return (1);
227 		}
228 		/* unlink now... avoid ETXTBSY errors later */
229 		(void) unlink(path);
230 	}
231 
232 nocompare:
233 	/* open target, set mode, owner, group */
234 	if ((to_fd = open(path, O_CREAT|O_WRONLY|O_TRUNC, 0)) < 0) {
235 		fprintf(stderr, gettext("install: %s: %s\n"), path, strerror(errno));
236 		return (1);
237 	}
238 	if (fchmod(to_fd, mode)) {
239 		fprintf(stderr, gettext("install: chmod: %s: %s\n"), path, strerror(errno));
240 		status = 1;
241 		close(to_fd);
242 		goto inst_done;
243 	}
244 	if (!devnull) {
245 		status = copy(from, to_fd, path);  /* copy */
246 		close(to_fd);
247 	}
248 	if (sflag) {
249 		sprintf(buf, "strip %s", path);
250 		system(buf);
251 	}
252 	if (chown(path, pp->pw_uid, gp->gr_gid) && errno != EPERM) {
253 		fprintf(stderr, gettext("install: chown: %s: %s\n"), path, strerror(errno));
254 		status = 1;
255 	}
256 
257 inst_done:
258 	if (status)
259 		(void) unlink(path);
260 	return (status);
261 }
262 
263 /*
264  * copy --
265  *	copy from one file to another
266  */
267 int
268 copy(from_name, to_fd, to_name)
269 	int to_fd;
270 	char *from_name, *to_name;
271 {
272 	int n, from_fd;
273 	int status = 0;
274 	char buf[MAXBSIZE];
275 
276 	if ((from_fd = open(from_name, O_RDONLY, 0)) < 0) {
277 		fprintf(stderr, gettext("install: open: %s: %s\n"), from_name, strerror(errno));
278 		return (1);
279 	}
280 	while ((n = read(from_fd, buf, sizeof(buf))) > 0)
281 		if (write(to_fd, buf, n) != n) {
282 			fprintf(stderr, gettext("install: write: %s: %s\n"), to_name, strerror(errno));
283 		status = 1;
284 		goto copy_done;
285 		}
286 	if (n == -1) {
287 		fprintf(stderr, gettext("install: read: %s: %s\n"), from_name, strerror(errno));
288 		status = 1;
289 		goto copy_done;
290 	}
291 
292 copy_done:
293 	(void) close(from_fd);
294 	return (status);
295 }
296 
297 /*
298  * atoo --
299  *      octal string to int
300  */
301 int
302 atoo(str)
303         char   *str;
304 {
305         int    val;
306 
307         for (val = 0; isdigit(*str); ++str)
308                 val = val * 8 + *str - '0';
309         return(val);
310 }
311 
312 
313 /*
314  * usage --
315  *	print a usage message and die
316  */
317 void
318 usage()
319 {
320 	fputs(gettext("usage: install [-cs] [-g group] [-m mode] [-o owner] file ...  destination\n"), stderr);
321 	fputs(gettext("       install  -d   [-g group] [-m mode] [-o owner] dir\n"), stderr);
322 	exit(1);
323 }
324 
325 /*
326  * mkdirp --
327  *	make a directory and parents if needed
328  */
329 int
330 mkdirp(dir, mode)
331 	char *dir;
332 	int mode;
333 {
334 	int err;
335 	char *slash;
336 	char *strrchr();
337 	extern int errno;
338 
339 	if (mkdir(dir, mode) == 0)
340 		return (0);
341 	if (errno != ENOENT)
342 		return (-1);
343 	slash = strrchr(dir, '/');
344 	if (slash == NULL)
345 		return (-1);
346 	*slash = '\0';
347 	err = mkdirp(dir, 0777);
348 	*slash = '/';
349 	if (err)
350 		return (err);
351 	return mkdir(dir, mode);
352 }
353