1 /* 2 * Copyright (c) 1987 Regents of the University of California. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34 #ifndef lint 35 char copyright[] = 36 "@(#) Copyright (c) 1987 Regents of the University of California.\n\ 37 All rights reserved.\n"; 38 #endif /* not lint */ 39 40 #ifndef lint 41 static char sccsid[] = "@(#)xinstall.c 5.24 (Berkeley) 7/1/90"; 42 #endif /* not lint */ 43 44 #include <sys/param.h> 45 #include <sys/stat.h> 46 #include <sys/file.h> 47 #include <grp.h> 48 #include <pwd.h> 49 #include <stdio.h> 50 #include <ctype.h> 51 #include <errno.h> 52 #include <paths.h> 53 #include "pathnames.h" 54 55 static struct passwd *pp; 56 static struct group *gp; 57 static int docopy, dostrip, dodir, mode = 0755; 58 static char *group, *owner, pathbuf[MAXPATHLEN]; 59 60 main(argc, argv) 61 int argc; 62 char **argv; 63 { 64 extern char *optarg; 65 extern int optind; 66 struct stat from_sb, to_sb; 67 mode_t *set, *setmode(); 68 int ch, no_target; 69 char *to_name; 70 71 while ((ch = getopt(argc, argv, "cg:m:o:sd")) != EOF) 72 switch((char)ch) { 73 case 'c': 74 docopy = 1; 75 break; 76 case 'g': 77 group = optarg; 78 break; 79 case 'm': 80 if (!(set = setmode(optarg))) { 81 (void)fprintf(stderr, 82 "install: invalid file mode.\n"); 83 exit(1); 84 } 85 mode = getmode(set, 0); 86 break; 87 case 'o': 88 owner = optarg; 89 break; 90 case 's': 91 dostrip = 1; 92 break; 93 case 'd': 94 dodir = 1; 95 break; 96 case '?': 97 default: 98 usage(); 99 } 100 argc -= optind; 101 argv += optind; 102 103 /* copy and strip options make no sense when creating directories */ 104 if ((docopy || dostrip) && dodir) 105 usage(); 106 107 /* must have at least two arguments, except when creating directories */ 108 if (argc < 2 && !dodir) 109 usage(); 110 111 /* get group and owner id's */ 112 if (group && !(gp = getgrnam(group))) { 113 fprintf(stderr, "install: unknown group %s.\n", group); 114 exit(1); 115 } 116 if (owner && !(pp = getpwnam(owner))) { 117 fprintf(stderr, "install: unknown user %s.\n", owner); 118 exit(1); 119 } 120 121 if (dodir) { 122 for (; *argv != NULL; ++argv) 123 build(*argv); 124 exit (0); 125 /* NOTREACHED */ 126 } 127 128 no_target = stat(to_name = argv[argc - 1], &to_sb); 129 if (!no_target && S_ISDIR(to_sb.st_mode)) { 130 for (; *argv != to_name; ++argv) 131 install(*argv, to_name, 1); 132 exit(0); 133 } 134 135 /* can't do file1 file2 directory/file */ 136 if (argc != 2) 137 usage(); 138 139 if (!no_target) { 140 if (stat(*argv, &from_sb)) { 141 fprintf(stderr, "install: can't find %s.\n", *argv); 142 exit(1); 143 } 144 if (!S_ISREG(to_sb.st_mode)) { 145 fprintf(stderr, "install: %s isn't a regular file.\n", to_name); 146 exit(1); 147 } 148 if (to_sb.st_dev == from_sb.st_dev && to_sb.st_ino == from_sb.st_ino) { 149 fprintf(stderr, "install: %s and %s are the same file.\n", *argv, to_name); 150 exit(1); 151 } 152 /* unlink now... avoid ETXTBSY errors later */ 153 (void)unlink(to_name); 154 } 155 install(*argv, to_name, 0); 156 exit(0); 157 } 158 159 /* 160 * install -- 161 * build a path name and install the file 162 */ 163 install(from_name, to_name, isdir) 164 char *from_name, *to_name; 165 int isdir; 166 { 167 struct stat from_sb; 168 int devnull, from_fd, to_fd; 169 char *C, *rindex(); 170 171 /* if try to install NULL file to a directory, fails */ 172 if (isdir || strcmp(from_name, _PATH_DEVNULL)) { 173 if (stat(from_name, &from_sb)) { 174 fprintf(stderr, "install: can't find %s.\n", from_name); 175 exit(1); 176 } 177 if (!S_ISREG(from_sb.st_mode)) { 178 fprintf(stderr, "install: %s isn't a regular file.\n", from_name); 179 exit(1); 180 } 181 /* build the target path */ 182 if (isdir) { 183 (void)sprintf(pathbuf, "%s/%s", to_name, (C = rindex(from_name, '/')) ? ++C : from_name); 184 to_name = pathbuf; 185 } 186 devnull = 0; 187 } else 188 devnull = 1; 189 190 /* unlink now... avoid ETXTBSY errors later */ 191 (void)unlink(to_name); 192 193 /* create target */ 194 if ((to_fd = open(to_name, O_CREAT|O_WRONLY|O_TRUNC, 0600)) < 0) { 195 error(to_name); 196 exit(1); 197 } 198 if (!devnull) { 199 if ((from_fd = open(from_name, O_RDONLY, 0)) < 0) { 200 (void)unlink(to_name); 201 error(from_name); 202 exit(1); 203 } 204 copy(from_fd, from_name, to_fd, to_name); 205 (void)close(from_fd); 206 } 207 if (dostrip) 208 strip(to_name); 209 /* 210 * set owner, group, mode for target; do the chown first, 211 * chown may lose the setuid bits. 212 */ 213 if ((group || owner) && 214 fchown(to_fd, owner ? pp->pw_uid : -1, group ? gp->gr_gid : -1) || 215 fchmod(to_fd, mode)) { 216 error(to_name); 217 bad(to_name); 218 } 219 (void)close(to_fd); 220 if (!docopy && !devnull && unlink(from_name)) { 221 error(from_name); 222 exit(1); 223 } 224 } 225 226 /* 227 * copy -- 228 * copy from one file to another 229 */ 230 copy(from_fd, from_name, to_fd, to_name) 231 register int from_fd, to_fd; 232 char *from_name, *to_name; 233 { 234 register int n; 235 char buf[MAXBSIZE]; 236 237 while ((n = read(from_fd, buf, sizeof(buf))) > 0) 238 if (write(to_fd, buf, n) != n) { 239 error(to_name); 240 bad(to_name); 241 } 242 if (n == -1) { 243 error(from_name); 244 bad(to_name); 245 } 246 } 247 248 /* 249 * strip -- 250 * use strip(1) to strip the target file 251 */ 252 strip(to_name) 253 char *to_name; 254 { 255 int status; 256 257 switch (vfork()) { 258 case -1: 259 error("fork"); 260 bad(to_name); 261 case 0: 262 execl(_PATH_STRIP, "strip", to_name, (char *)NULL); 263 error(_PATH_STRIP); 264 _exit(1); 265 default: 266 if (wait(&status) == -1 || status) 267 bad(to_name); 268 } 269 } 270 271 /* 272 * build -- 273 * build directory heirarchy 274 */ 275 build(path) 276 char *path; 277 { 278 register char *p; 279 struct stat sb; 280 int create, ch; 281 282 for (create = 0, p = path;; ++p) 283 if (!*p || *p == '/') { 284 ch = *p; 285 *p = '\0'; 286 if (stat(path, &sb)) { 287 if (errno != ENOENT || mkdir(path, 0777) < 0) { 288 error(path); 289 return(1); 290 } 291 create = 1; 292 } 293 if (!(*p = ch)) 294 break; 295 } 296 297 if ((group || owner) && 298 chown(path, owner ? pp->pw_uid : -1, group ? gp->gr_gid : -1) || 299 chmod(path, mode)) { 300 error(path); 301 } 302 303 return(0); 304 } 305 306 /* 307 * error -- 308 * print out an error message 309 */ 310 error(s) 311 char *s; 312 { 313 extern int errno; 314 char *strerror(); 315 316 (void)fprintf(stderr, "install: %s: %s\n", s, strerror(errno)); 317 } 318 319 /* 320 * bad -- 321 * remove created target and die 322 */ 323 bad(fname) 324 char *fname; 325 { 326 (void)unlink(fname); 327 exit(1); 328 } 329 330 /* 331 * usage -- 332 * print a usage message and die 333 */ 334 usage() 335 { 336 (void)fprintf(stderr, "\ 337 usage: install [-cs] [-g group] [-m mode] [-o owner] file1 file2\n\ 338 install [-cs] [-g group] [-m mode] [-o owner] file1 ... fileN directory\n\ 339 install -d [-g group] [-m mode] [-o owner] directory ...\n"); 340 exit(1); 341 } 342