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  * Copyright (c) 2018, Joyent, Inc.
27  */
28 
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <strings.h>
32 #include <sys/param.h>
33 #include <fcntl.h>
34 #include <sys/errno.h>
35 #include <sys/types.h>
36 #include <sys/uio.h>
37 #include <unistd.h>
38 #include <sys/stat.h>
39 #include <errno.h>
40 #include <libgen.h>
41 #include "stdusers.h"
42 
43 
44 #define	FILE_BUFF	40960
45 
46 static int suppress = 0;
47 
48 static void usage(void);
49 static void file_copy(char *src_file, char *dest_file);
50 static void chown_file(const char *file, const char *group, const char *owner);
51 static char *find_basename(const char *str);
52 static int creatdir(char *fn);
53 
54 
55 void
usage(void)56 usage(void)
57 {
58 	(void) fprintf(stderr,
59 	    "usage: install [-sd][-m mode][-g group][-u owner] "
60 	    "-f dir file ...\n");
61 }
62 
63 void
file_copy(char * src_file,char * dest_file)64 file_copy(char *src_file, char *dest_file)
65 {
66 	int	src_fd;
67 	int	dest_fd;
68 	int	count;
69 	static char file_buff[FILE_BUFF];
70 
71 	if ((src_fd = open(src_file, O_RDONLY))  == -1) {
72 		(void) fprintf(stderr, "install:file_copy: %s failed "
73 		    "(%d): %s\n", src_file, errno, strerror(errno));
74 		exit(1);
75 	}
76 
77 	if ((dest_fd = open(dest_file, O_CREAT|O_WRONLY|O_TRUNC, 0755)) == -1) {
78 		(void) fprintf(stderr, "install:file_copy: %s failed "
79 		    "(%d): %s\n", dest_file, errno, strerror(errno));
80 		exit(1);
81 	}
82 
83 	while ((count = read(src_fd, file_buff, FILE_BUFF)) > 0) {
84 		(void) write(dest_fd, file_buff, count);
85 	}
86 
87 	if (count == -1) {
88 		(void) fprintf(stderr, "install:file_copy:read failed "
89 		    "(%d): %s\n", errno, strerror(errno));
90 		exit(1);
91 	}
92 
93 	if (!suppress)
94 		(void) printf("%s installed as %s\n", src_file, dest_file);
95 
96 	(void) close(src_fd);
97 	(void) close(dest_fd);
98 }
99 
100 
101 void
chown_file(const char * file,const char * group,const char * owner)102 chown_file(const char *file, const char *group, const char *owner)
103 {
104 	gid_t	grp = (gid_t)-1;
105 	uid_t	own = (uid_t)-1;
106 
107 	if (group) {
108 		grp = stdfind(group, groupnames);
109 		if (grp == (gid_t)-1)
110 			(void) fprintf(stderr, "unknown group(%s)\n", group);
111 	}
112 
113 	if (owner) {
114 		own = stdfind(owner, usernames);
115 		if (own == (uid_t)-1) {
116 			(void) fprintf(stderr, "unknown owner(%s)\n", owner);
117 			exit(1);
118 		}
119 
120 	}
121 
122 	if (chown(file, own, grp) == -1) {
123 		(void) fprintf(stderr, "install:chown_file: failed "
124 		    "(%d): %s\n", errno, strerror(errno));
125 		exit(1);
126 	}
127 }
128 
129 
130 char *
find_basename(const char * str)131 find_basename(const char *str)
132 {
133 	int	i;
134 	int	len;
135 
136 	len = strlen(str);
137 
138 	for (i = len-1; i >= 0; i--)
139 		if (str[i] == '/')
140 			return ((char *)(str + i + 1));
141 	return ((char *)str);
142 }
143 
144 int
creatdir(char * fn)145 creatdir(char *fn) {
146 
147 	errno = 0;
148 
149 	if (mkdirp(fn, 0755) == -1) {
150 		if (errno != EEXIST)
151 			return (errno);
152 	} else if (!suppress) {
153 		(void) printf("directory %s created\n", fn);
154 	}
155 	return (0);
156 }
157 
158 
159 int
main(int argc,char ** argv)160 main(int argc, char **argv)
161 {
162 	int	c;
163 	int	errflg = 0;
164 	int	dirflg = 0;
165 	char	*group = NULL;
166 	char	*owner = NULL;
167 	char	*dirb = NULL;
168 	char	*ins_file = NULL;
169 	int	mode = -1;
170 	char	dest_file[MAXPATHLEN];
171 	int	rv = 0;
172 
173 	while ((c = getopt(argc, argv, "f:sm:du:g:")) != EOF) {
174 		switch (c) {
175 		case 'f':
176 			dirb = optarg;
177 			break;
178 		case 'g':
179 			group = optarg;
180 			break;
181 		case 'u':
182 			owner = optarg;
183 			break;
184 		case 'd':
185 			dirflg = 1;
186 			break;
187 		case 'm':
188 			mode = strtol(optarg, NULL, 8);
189 			break;
190 		case 's':
191 			suppress = 1;
192 			break;
193 		case '?':
194 			errflg++;
195 			break;
196 		}
197 	}
198 
199 	if (errflg) {
200 		usage();
201 		return (1);
202 	}
203 
204 	if (argc == optind) {
205 		usage();
206 		return (1);
207 	}
208 
209 	if (!dirflg && (dirb == NULL)) {
210 		(void) fprintf(stderr,
211 		    "install: no destination directory specified.\n");
212 		return (1);
213 	}
214 
215 	for (c = optind; c < argc; c++) {
216 		ins_file = argv[c];
217 
218 		if (dirflg) {
219 			rv = creatdir(ins_file);
220 			if (rv) {
221 				(void) fprintf(stderr,
222 				    "install: creatdir %s (%d): %s\n",
223 				    ins_file, errno, strerror(errno));
224 				return (rv);
225 			}
226 			(void) strlcpy(dest_file, ins_file, MAXPATHLEN);
227 
228 		} else {
229 			(void) strcat(strcat(strcpy(dest_file, dirb), "/"),
230 			    find_basename(ins_file));
231 			file_copy(ins_file, dest_file);
232 		}
233 
234 		if (group || owner)
235 			chown_file(dest_file, group, owner);
236 
237 		if (mode != -1) {
238 			(void) umask(0);
239 			if (chmod(dest_file, mode) == -1) {
240 				(void) fprintf(stderr,
241 				    "install: chmod of %s to mode %o failed "
242 				    "(%d): %s\n",
243 				    dest_file, mode, errno, strerror(errno));
244 				return (1);
245 			}
246 		}
247 	}
248 	return (0);
249 }
250