1: /* 2: * Copyright (c) 1987, 1993 3: * The Regents of the University of California. 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: #if !defined(lint) && defined(DOSCCS) 35: static char copyright[] = 36: "@(#) Copyright (c) 1987, 1993\n\ 37: The Regents of the University of California. All rights reserved.\n"; 38: 39: static char sccsid[] = "@(#)xinstall.c 8.1.1 (2.11BSD) 1996/2/21"; 40: #endif /* not lint */ 41: 42: #include <sys/param.h> 43: #include <sys/wait.h> 44: #include <sys/stat.h> 45: 46: #include <ctype.h> 47: #include <errno.h> 48: #include <fcntl.h> 49: #include <grp.h> 50: #include <paths.h> 51: #include <pwd.h> 52: #include <stdio.h> 53: #include <stdlib.h> 54: #include <string.h> 55: #include <unistd.h> 56: 57: #include "pathnames.h" 58: 59: struct passwd *pp; 60: struct group *gp; 61: int docopy, dostrip; 62: int mode = S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH; 63: char *group, *owner, pathbuf[MAXPATHLEN]; 64: 65: #define DIRECTORY 0x01 /* Tell install it's a directory. */ 66: #define SETFLAGS 0x02 /* Tell install to set flags. */ 67: 68: void copy(); 69: void err(); 70: void install(); 71: u_short string_to_flags(); 72: void strip(); 73: void usage(); 74: 75: int 76: main(argc, argv) 77: int argc; 78: register char *argv[]; 79: { 80: struct stat from_sb, to_sb; 81: mode_t *set; 82: u_short fset; 83: u_int iflags; 84: int ch, no_target; 85: char *flags, *to_name; 86: 87: iflags = 0; 88: while ((ch = getopt(argc, argv, "cf:g:m:o:s")) != EOF) 89: switch((char)ch) { 90: case 'c': 91: docopy = 1; 92: break; 93: case 'f': 94: flags = optarg; 95: if (string_to_flags(&flags, &fset, NULL)) 96: err("%s: invalid flag", flags); 97: iflags |= SETFLAGS; 98: break; 99: case 'g': 100: group = optarg; 101: break; 102: case 'm': 103: if (!(set = (mode_t *)setmode(optarg))) 104: err("%s: invalid file mode", optarg); 105: mode = getmode(set, 0); 106: break; 107: case 'o': 108: owner = optarg; 109: break; 110: case 's': 111: dostrip = 1; 112: break; 113: case '?': 114: default: 115: usage(); 116: } 117: argc -= optind; 118: argv += optind; 119: if (argc < 2) 120: usage(); 121: 122: /* get group and owner id's */ 123: if (group && !(gp = getgrnam(group))) 124: err("unknown group %s", group); 125: if (owner && !(pp = getpwnam(owner))) 126: err("unknown user %s", owner); 127: 128: no_target = stat(to_name = argv[argc - 1], &to_sb); 129: if (!no_target && (to_sb.st_mode & S_IFMT) == S_IFDIR) { 130: for (; *argv != to_name; ++argv) 131: install(*argv, to_name, fset, iflags | DIRECTORY); 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: err("%s: %s", *argv, strerror(errno)); 142: if ((to_sb.st_mode & S_IFMT) != S_IFREG) 143: err("%s: %s", to_name, strerror(EFTYPE)); 144: if (to_sb.st_dev == from_sb.st_dev && 145: to_sb.st_ino == from_sb.st_ino) 146: err("%s and %s are the same file", *argv, to_name); 147: /* 148: * Unlink now... avoid ETXTBSY errors later. Try and turn 149: * off the append/immutable bits -- if we fail, go ahead, 150: * it might work. 151: */ 152: #define NOCHANGEBITS (UF_IMMUTABLE | UF_APPEND | SF_IMMUTABLE | SF_APPEND) 153: if (to_sb.st_flags & NOCHANGEBITS) 154: (void)chflags(to_name, 155: to_sb.st_flags & ~(NOCHANGEBITS)); 156: (void)unlink(to_name); 157: } 158: install(*argv, to_name, fset, iflags); 159: exit(0); 160: } 161: 162: /* 163: * install -- 164: * build a path name and install the file 165: */ 166: void 167: install(from_name, to_name, fset, flags) 168: register char *from_name, *to_name; 169: u_short fset; 170: u_int flags; 171: { 172: struct stat from_sb, to_sb; 173: int devnull, from_fd, to_fd, serrno; 174: register char *p; 175: 176: /* If try to install NULL file to a directory, fails. */ 177: if (flags & DIRECTORY || strcmp(from_name, _PATH_DEVNULL)) { 178: if (stat(from_name, &from_sb)) 179: err("%s: %s", from_name, strerror(errno)); 180: if ((from_sb.st_mode & S_IFMT) != S_IFREG) 181: err("%s: %s", from_name, strerror(EFTYPE)); 182: /* Build the target path. */ 183: if (flags & DIRECTORY) { 184: (void)sprintf(pathbuf, "%s/%s", to_name, 185: (p = rindex(from_name, '/')) ? ++p : from_name); 186: to_name = pathbuf; 187: } 188: devnull = 0; 189: } else { 190: from_sb.st_flags = 0; /* XXX */ 191: devnull = 1; 192: } 193: 194: /* 195: * Unlink now... avoid ETXTBSY errors later. Try and turn 196: * off the append/immutable bits -- if we fail, go ahead, 197: * it might work. 198: */ 199: if (stat(to_name, &to_sb) == 0 && 200: to_sb.st_flags & (NOCHANGEBITS)) 201: (void)chflags(to_name, to_sb.st_flags & ~(NOCHANGEBITS)); 202: (void)unlink(to_name); 203: 204: /* Create target. */ 205: if ((to_fd = open(to_name, 206: O_CREAT | O_WRONLY | O_TRUNC, S_IRUSR | S_IWUSR)) < 0) 207: err("%s: %s", to_name, strerror(errno)); 208: if (!devnull) { 209: if ((from_fd = open(from_name, O_RDONLY, 0)) < 0) { 210: (void)unlink(to_name); 211: err("%s: %s", from_name, strerror(errno)); 212: } 213: copy(from_fd, from_name, to_fd, to_name, from_sb.st_size); 214: (void)close(from_fd); 215: } 216: if (dostrip) 217: strip(to_name); 218: /* 219: * Set owner, group, mode for target; do the chown first, 220: * chown may lose the setuid bits. 221: */ 222: if ((group || owner) && 223: fchown(to_fd, owner ? pp->pw_uid : -1, group ? gp->gr_gid : -1)) { 224: serrno = errno; 225: (void)unlink(to_name); 226: err("%s: chown/chgrp: %s", to_name, strerror(serrno)); 227: } 228: if (fchmod(to_fd, mode)) { 229: serrno = errno; 230: (void)unlink(to_name); 231: err("%s: chmod: %s", to_name, strerror(serrno)); 232: } 233: 234: /* 235: * If provided a set of flags, set them, otherwise, preserve the 236: * flags, except for the dump flag. 237: */ 238: if (fchflags(to_fd, 239: flags & SETFLAGS ? fset : from_sb.st_flags & ~UF_NODUMP)) { 240: serrno = errno; 241: (void)unlink(to_name); 242: err("%s: chflags: %s", to_name, strerror(serrno)); 243: } 244: 245: (void)close(to_fd); 246: if (!docopy && !devnull && unlink(from_name)) 247: err("%s: %s", from_name, strerror(errno)); 248: } 249: 250: /* 251: * copy -- 252: * copy from one file to another 253: */ 254: void 255: copy(from_fd, from_name, to_fd, to_name, size) 256: register int from_fd, to_fd; 257: char *from_name, *to_name; 258: off_t size; 259: { 260: register int nr, nw; 261: int serrno; 262: char buf[MAXBSIZE]; 263: 264: while ((nr = read(from_fd, buf, sizeof(buf))) > 0) 265: if ((nw = write(to_fd, buf, nr)) != nr) { 266: serrno = errno; 267: (void)unlink(to_name); 268: err("%s: %s", 269: to_name, strerror(nw > 0 ? EIO : serrno)); 270: } 271: if (nr != 0) { 272: serrno = errno; 273: (void)unlink(to_name); 274: err("%s: %s", from_name, strerror(serrno)); 275: } 276: } 277: 278: /* 279: * strip -- 280: * use strip(1) to strip the target file 281: */ 282: void 283: strip(to_name) 284: register char *to_name; 285: { 286: register int serrno; 287: int status; 288: 289: switch (vfork()) { 290: case -1: 291: serrno = errno; 292: (void)unlink(to_name); 293: err("forks: %s", strerror(errno)); 294: case 0: 295: execl(_PATH_STRIP, "strip", to_name, NULL); 296: err("%s: %s", _PATH_STRIP, strerror(errno)); 297: default: 298: if (wait(&status) == -1 || status) 299: (void)unlink(to_name); 300: } 301: } 302: 303: /* 304: * usage -- 305: * print a usage message and die 306: */ 307: void 308: usage() 309: { 310: (void)fprintf(stderr, 311: "usage: install [-cs] [-f flags] [-g group] [-m mode] [-o owner] file1 file2;\n\tor file1 ... fileN directory\n"); 312: exit(1); 313: } 314: 315: #if __STDC__ 316: #include <stdarg.h> 317: #else 318: #include <varargs.h> 319: #endif 320: 321: void 322: #if __STDC__ 323: err(const char *fmt, ...) 324: #else 325: err(fmt, va_alist) 326: char *fmt; 327: va_dcl 328: #endif 329: { 330: va_list ap; 331: #if __STDC__ 332: va_start(ap, fmt); 333: #else 334: va_start(ap); 335: #endif 336: (void)fprintf(stderr, "install: "); 337: (void)vfprintf(stderr, fmt, ap); 338: va_end(ap); 339: (void)fprintf(stderr, "\n"); 340: exit(1); 341: /* NOTREACHED */ 342: }