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
43static int suppress = 0;
44
45static void usage(void);
46static void file_copy(char *src_file, char *dest_file);
47static void chown_file(const char *file, const char *group, const char *owner);
48static void formclosed(char *root, char *closedroot);
49static char *find_basename(const char *str);
50static int creatdir(char *fn);
51
52
53void
54usage(void)
55{
56	(void) fprintf(stderr,
57	    "usage: install [-sdO][-m mode][-g group][-u owner] "
58	    "-f dir file ...\n");
59}
60
61void
62file_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
99void
100chown_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
128void
129formclosed(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
145char *
146find_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
159int
160creatdir(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
174int
175main(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