xref: /illumos-gate/usr/src/ucbcmd/install.d/install.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
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 main(argc, argv)
69 	int	argc;
70 	char	**argv;
71 {
72 	extern char	*optarg;
73 	extern int	optind;
74 	struct stat	stb;
75 	char	*dirname;
76 	int	ch;
77 	int	i;
78 	int	rc;
79 	int	dflag = 0;
80 	int	gflag = 0;
81 	int	oflag = 0;
82 	int	mflag = 0;
83 
84 	(void) setlocale(LC_ALL, "");
85 
86 #if !defined(TEXT_DOMAIN)
87 #define TEXT_DOMAIN "SYS_TEST"
88 #endif
89 	(void) textdomain(TEXT_DOMAIN);
90 
91 	while ((ch = getopt(argc, argv, "dcg:o:m:s")) != EOF)
92 		switch((char)ch) {
93 		case 'c':
94 			break;	/* always do "copy" */
95 		case 'd':
96 			dflag++;
97 			break;
98 		case 'g':
99 			gflag++;
100 			group = optarg;
101 			break;
102 		case 'm':
103 			mflag++;
104 			mode = atoo(optarg);
105 			break;
106 		case 'o':
107 			oflag++;
108 			owner = optarg;
109 			break;
110 		case 's':
111 			sflag++;
112 			break;
113 		case '?':
114 		default:
115 			usage();
116 		}
117 	argc -= optind;
118 	argv += optind;
119 
120 	/* get group and owner id's */
121 	if (!(gp = getgrnam(group))) {
122 		fprintf(stderr, gettext("install: unknown group %s.\n"), group);
123 		exit(1);
124 	}
125 	if (!(pp = getpwnam(owner))) {
126 		fprintf(stderr, gettext("install: unknown user %s.\n"), owner);
127 		exit(1);
128 	}
129 
130 	if (dflag) {		/* install a directory */
131 		int exists = 0;
132 
133 		if (argc != 1)
134 			usage();
135 		dirname = argv[0];
136 		if (mkdirp(dirname, 0777) < 0) {
137 			exists = errno == EEXIST;
138 			if (!exists) {
139 				fprintf(stderr, gettext("install: mkdir: %s: %s\n"), dirname, strerror(errno));
140 				exit(1);
141 			}
142 		}
143 		if (stat(dirname, &stb) < 0) {
144 			fprintf(stderr, gettext("install: stat: %s: %s\n"), dirname, strerror(errno));
145 			exit(1);
146 		}
147 		if ((stb.st_mode&S_IFMT) != S_IFDIR) {
148 			fprintf(stderr, gettext("install: %s is not a directory\n"), dirname);
149 		}
150 		/* make sure directory setgid bit is inherited */
151 		mode = (mode & ~S_ISGID) | (stb.st_mode & S_ISGID);
152 		if (mflag && chmod(dirname, mode)) {
153 			fprintf(stderr, gettext("install: chmod: %s: %s\n"), dirname, strerror(errno));
154 			if (!exists)
155 				(void) unlink(dirname);
156 			exit(1) ;
157 		}
158 		if (oflag && chown(dirname, pp->pw_uid, -1) && errno != EPERM) {
159 			fprintf(stderr, gettext("install: chown: %s: %s\n"), dirname, strerror(errno));
160 			if (!exists)
161 				(void) unlink(dirname);
162 			exit(1) ;
163 		}
164 		if (gflag && chown(dirname, -1, gp->gr_gid) && errno != EPERM) {
165 			fprintf(stderr, gettext("install: chgrp: %s: %s\n"), dirname, strerror(errno));
166 			if (!exists)
167 				(void) unlink(dirname);
168 			exit(1) ;
169 		}
170 		exit(0);
171 	}
172 
173 	if (argc < 2)
174 		usage();
175 
176         if (argc > 2) {		/* last arg must be a directory */
177                 if (stat(argv[argc-1], &stb) < 0)
178                         usage();
179                 if ((stb.st_mode&S_IFMT) != S_IFDIR)
180                         usage();
181         }
182         rc = 0;
183         for (i = 0; i < argc-1; i++)
184                 rc |= install(argv[i], argv[argc-1]);
185         exit(rc);
186 	/* NOTREACHED */
187 }
188 
189 int
190 install(from, to)
191 	char *from, *to;
192 {
193 	int to_fd;
194 	int devnull;
195 	int status = 0;
196 	char *path;
197 	struct stat from_sb, to_sb;
198 	static char pbuf[MAXPATHLEN];
199 	char buf[MAXPATHLEN + 10];
200 
201 	/* check source */
202 	if (stat(from, &from_sb)) {
203 		fprintf(stderr, gettext("install: %s: %s\n"), from, strerror(errno));
204 		return (1);
205 	}
206 	/* special case for removing files */
207 	devnull = !strcmp(from, "/dev/null");
208 	if (!devnull && !((from_sb.st_mode&S_IFMT) == S_IFREG)) {
209 		fprintf(stderr, gettext("install: %s isn't a regular file.\n"), from);
210 		return (1);
211 	}
212 
213 	/* build target path, find out if target is same as source */
214 	if (!stat(path = to, &to_sb)) {
215 		if ((to_sb.st_mode&S_IFMT) == S_IFDIR) {
216 			char *C, *strrchr();
217 
218 			(void) sprintf(path = pbuf, "%s/%s", to, (C = strrchr(from, '/')) ? ++C : from);
219 			if (stat(path, &to_sb))
220 				goto nocompare;
221 		}
222 		if ((to_sb.st_mode&S_IFMT) != S_IFREG) {
223 			fprintf(stderr, gettext("install: %s isn't a regular file.\n"), path);
224 			return (1);
225 		}
226 		if (to_sb.st_dev == from_sb.st_dev && to_sb.st_ino == from_sb.st_ino) {
227 			fprintf(stderr, gettext("install: %s and %s are the same file.\n"), from, path);
228 			return (1);
229 		}
230 		/* unlink now... avoid ETXTBSY errors later */
231 		(void) unlink(path);
232 	}
233 
234 nocompare:
235 	/* open target, set mode, owner, group */
236 	if ((to_fd = open(path, O_CREAT|O_WRONLY|O_TRUNC, 0)) < 0) {
237 		fprintf(stderr, gettext("install: %s: %s\n"), path, strerror(errno));
238 		return (1);
239 	}
240 	if (fchmod(to_fd, mode)) {
241 		fprintf(stderr, gettext("install: chmod: %s: %s\n"), path, strerror(errno));
242 		status = 1;
243 		close(to_fd);
244 		goto inst_done;
245 	}
246 	if (!devnull) {
247 		status = copy(from, to_fd, path);  /* copy */
248 		close(to_fd);
249 	}
250 	if (sflag) {
251 		sprintf(buf, "strip %s", path);
252 		system(buf);
253 	}
254 	if (chown(path, pp->pw_uid, gp->gr_gid) && errno != EPERM) {
255 		fprintf(stderr, gettext("install: chown: %s: %s\n"), path, strerror(errno));
256 		status = 1;
257 	}
258 
259 inst_done:
260 	if (status)
261 		(void) unlink(path);
262 	return (status);
263 }
264 
265 /*
266  * copy --
267  *	copy from one file to another
268  */
269 int
270 copy(from_name, to_fd, to_name)
271 	int to_fd;
272 	char *from_name, *to_name;
273 {
274 	int n, from_fd;
275 	int status = 0;
276 	char buf[MAXBSIZE];
277 
278 	if ((from_fd = open(from_name, O_RDONLY, 0)) < 0) {
279 		fprintf(stderr, gettext("install: open: %s: %s\n"), from_name, strerror(errno));
280 		return (1);
281 	}
282 	while ((n = read(from_fd, buf, sizeof(buf))) > 0)
283 		if (write(to_fd, buf, n) != n) {
284 			fprintf(stderr, gettext("install: write: %s: %s\n"), to_name, strerror(errno));
285 		status = 1;
286 		goto copy_done;
287 		}
288 	if (n == -1) {
289 		fprintf(stderr, gettext("install: read: %s: %s\n"), from_name, strerror(errno));
290 		status = 1;
291 		goto copy_done;
292 	}
293 
294 copy_done:
295 	(void) close(from_fd);
296 	return (status);
297 }
298 
299 /*
300  * atoo --
301  *      octal string to int
302  */
303 int
304 atoo(str)
305         register char   *str;
306 {
307         register int    val;
308 
309         for (val = 0; isdigit(*str); ++str)
310                 val = val * 8 + *str - '0';
311         return(val);
312 }
313 
314 
315 /*
316  * usage --
317  *	print a usage message and die
318  */
319 void
320 usage()
321 {
322 	fputs(gettext("usage: install [-cs] [-g group] [-m mode] [-o owner] file ...  destination\n"), stderr);
323 	fputs(gettext("       install  -d   [-g group] [-m mode] [-o owner] dir\n"), stderr);
324 	exit(1);
325 }
326 
327 /*
328  * mkdirp --
329  *	make a directory and parents if needed
330  */
331 int
332 mkdirp(dir, mode)
333 	char *dir;
334 	int mode;
335 {
336 	int err;
337 	char *slash;
338 	char *strrchr();
339 	extern int errno;
340 
341 	if (mkdir(dir, mode) == 0)
342 		return (0);
343 	if (errno != ENOENT)
344 		return (-1);
345 	slash = strrchr(dir, '/');
346 	if (slash == NULL)
347 		return (-1);
348 	*slash = '\0';
349 	err = mkdirp(dir, 0777);
350 	*slash = '/';
351 	if (err)
352 		return (err);
353 	return mkdir(dir, mode);
354 }
355