xref: /illumos-gate/usr/src/tools/install.bin/install.bin.c (revision d0698e0d179f97729cacdbc2f13446a6b0a3f22a)
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 (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
23  */
24 
25 
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <strings.h>
29 #include <sys/param.h>
30 #include <fcntl.h>
31 #include <sys/errno.h>
32 #include <sys/types.h>
33 #include <sys/uio.h>
34 #include <unistd.h>
35 #include <sys/stat.h>
36 #include <errno.h>
37 #include <libgen.h>
38 #include "stdusers.h"
39 
40 
41 #define	FILE_BUFF	40960
42 
43 static int suppress = 0;
44 
45 static void usage(void);
46 static void file_copy(char *src_file, char *dest_file);
47 static void chown_file(const char *file, const char *group, const char *owner);
48 static void formclosed(char *root, char *closedroot);
49 static char *find_basename(const char *str);
50 static int creatdir(char *fn);
51 
52 
53 void
54 usage(void)
55 {
56 	(void) fprintf(stderr,
57 	    "usage: install [-sdO][-m mode][-g group][-u owner] "
58 	    "-f dir file ...\n");
59 }
60 
61 void
62 file_copy(char *src_file, char *dest_file)
63 {
64 	int	src_fd;
65 	int	dest_fd;
66 	int	count;
67 	static char file_buff[FILE_BUFF];
68 
69 	if ((src_fd = open(src_file, O_RDONLY))  == -1) {
70 		(void) fprintf(stderr, "install:file_copy: %s failed "
71 		    "(%d): %s\n", src_file, errno, strerror(errno));
72 		exit(1);
73 	}
74 
75 	if ((dest_fd = open(dest_file, O_CREAT|O_WRONLY|O_TRUNC, 0755)) == -1) {
76 		(void) fprintf(stderr, "install:file_copy: %s failed "
77 		    "(%d): %s\n", dest_file, errno, strerror(errno));
78 		exit(1);
79 	}
80 
81 	while ((count = read(src_fd, file_buff, FILE_BUFF)) > 0) {
82 		(void) write(dest_fd, file_buff, count);
83 	}
84 
85 	if (count == -1) {
86 		(void) fprintf(stderr, "install:file_copy:read failed "
87 		    "(%d): %s\n", errno, strerror(errno));
88 		exit(1);
89 	}
90 
91 	if (!suppress)
92 		(void) printf("%s installed as %s\n", src_file, dest_file);
93 
94 	(void) close(src_fd);
95 	(void) close(dest_fd);
96 }
97 
98 
99 void
100 chown_file(const char *file, const char *group, const char *owner)
101 {
102 	gid_t	grp = (gid_t)-1;
103 	uid_t	own = (uid_t)-1;
104 
105 	if (group) {
106 		grp = stdfind(group, groupnames);
107 		if (grp < 0)
108 			(void) fprintf(stderr, "unknown group(%s)\n", group);
109 	}
110 
111 	if (owner) {
112 		own = stdfind(owner, usernames);
113 		if (own < 0) {
114 			(void) fprintf(stderr, "unknown owner(%s)\n", owner);
115 			exit(1);
116 		}
117 
118 	}
119 
120 	if (chown(file, own, grp) == -1) {
121 		(void) fprintf(stderr, "install:chown_file: failed "
122 		    "(%d): %s\n", errno, strerror(errno));
123 		exit(1);
124 	}
125 }
126 
127 
128 void
129 formclosed(char *root, char *closedroot)
130 {
131 	int wholelen, residlen;
132 	char *temp;
133 
134 	wholelen = strlen(root);
135 	temp = strstr(strstr(root, "proto/root_"), "/");
136 	temp++;
137 	temp = strstr(temp, "/");
138 	residlen = strlen(temp);
139 	(void) strlcpy(closedroot, root, wholelen - residlen + 1);
140 	(void) strlcat(closedroot, "-closed", MAXPATHLEN);
141 	(void) strlcat(closedroot, temp, MAXPATHLEN);
142 }
143 
144 
145 char *
146 find_basename(const char *str)
147 {
148 	int	i;
149 	int	len;
150 
151 	len = strlen(str);
152 
153 	for (i = len-1; i >= 0; i--)
154 		if (str[i] == '/')
155 			return ((char *)(str + i + 1));
156 	return ((char *)str);
157 }
158 
159 int
160 creatdir(char *fn) {
161 
162 	errno = 0;
163 
164 	if (mkdirp(fn, 0755) == -1) {
165 		if (errno != EEXIST)
166 			return (errno);
167 	} else if (!suppress) {
168 		(void) printf("directory %s created\n", fn);
169 	}
170 	return (0);
171 }
172 
173 
174 int
175 main(int argc, char **argv)
176 {
177 	int	c;
178 	int	errflg = 0;
179 	int	dirflg = 0;
180 	char	*group = NULL;
181 	char	*owner = NULL;
182 	char	*dirb = NULL;
183 	char	*ins_file = NULL;
184 	int	mode = -1;
185 	char	dest_file[MAXPATHLEN];
186 	char    shadow_dest[MAXPATHLEN];
187 	char	shadow_dirb[MAXPATHLEN];
188 	int	tonic = 0;
189 	int	rv = 0;
190 
191 	while ((c = getopt(argc, argv, "f:sm:du:g:O")) != EOF) {
192 		switch (c) {
193 		case 'f':
194 			dirb = optarg;
195 			break;
196 		case 'g':
197 			group = optarg;
198 			break;
199 		case 'u':
200 			owner = optarg;
201 			break;
202 		case 'd':
203 			dirflg = 1;
204 			break;
205 		case 'm':
206 			mode = strtol(optarg, NULL, 8);
207 			break;
208 		case 's':
209 			suppress = 1;
210 			break;
211 		case 'O':
212 			tonic = 1;
213 			break;
214 		case '?':
215 			errflg++;
216 			break;
217 		}
218 	}
219 
220 	if (errflg) {
221 		usage();
222 		return (1);
223 	}
224 
225 	if (argc == optind) {
226 		usage();
227 		return (1);
228 	}
229 
230 	if (!dirflg && (dirb == NULL)) {
231 		(void) fprintf(stderr,
232 		    "install: no destination directory specified.\n");
233 		return (1);
234 	}
235 
236 	for (c = optind; c < argc; c++) {
237 		ins_file = argv[c];
238 
239 		if (dirflg) {
240 			if (tonic) {
241 				formclosed(ins_file, shadow_dest);
242 				rv = creatdir(shadow_dest);
243 				if (rv) {
244 					(void) fprintf(stderr,
245 					    "install: tonic creatdir "
246 					    "%s (%d): (%s)\n",
247 					    shadow_dest, errno,
248 					    strerror(errno));
249 					return (rv);
250 				}
251 			}
252 			rv = creatdir(ins_file);
253 			if (rv) {
254 				(void) fprintf(stderr,
255 				    "install: creatdir %s (%d): %s\n",
256 				    ins_file, errno, strerror(errno));
257 				return (rv);
258 			}
259 			(void) strlcpy(dest_file, ins_file, MAXPATHLEN);
260 
261 		} else {
262 			(void) strcat(strcat(strcpy(dest_file, dirb), "/"),
263 			    find_basename(ins_file));
264 			file_copy(ins_file, dest_file);
265 
266 			if (tonic) {
267 				formclosed(dirb, shadow_dirb);
268 				/*
269 				 * The standard directories in the proto
270 				 * area are created as part of "make setup",
271 				 * but that doesn't create them in the
272 				 * closed proto area. So if the target
273 				 * directory doesn't exist, we need to
274 				 * create it now.
275 				 */
276 				rv = creatdir(shadow_dirb);
277 				if (rv) {
278 					(void) fprintf(stderr,
279 					    "install: tonic creatdir(f) "
280 					    "%s (%d): %s\n",
281 					    shadow_dirb, errno,
282 					    strerror(errno));
283 					return (rv);
284 				}
285 				(void) strcat(strcat(strcpy(shadow_dest,
286 				    shadow_dirb), "/"),
287 				    find_basename(ins_file));
288 				file_copy(ins_file, shadow_dest);
289 			}
290 		}
291 
292 		if (group || owner) {
293 			chown_file(dest_file, group, owner);
294 			if (tonic)
295 				chown_file(shadow_dest, group, owner);
296 		}
297 		if (mode != -1) {
298 			(void) umask(0);
299 			if (chmod(dest_file, mode) == -1) {
300 				(void) fprintf(stderr,
301 				    "install: chmod of %s to mode %o failed "
302 				    "(%d): %s\n",
303 				    dest_file, mode, errno, strerror(errno));
304 				return (1);
305 			}
306 			if (tonic) {
307 				if (chmod(shadow_dest, mode) == -1) {
308 					(void) fprintf(stderr,
309 					    "install: tonic chmod of %s "
310 					    "to mode %o failed (%d): %s\n",
311 					    shadow_dest, mode,
312 					    errno, strerror(errno));
313 					return (1);
314 				}
315 			}
316 		}
317 	}
318 	return (0);
319 }
320