[BACK]Return to xinstall.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / xinstall

Annotation of src/usr.bin/xinstall/xinstall.c, Revision 1.4

1.4     ! millert     1: /*     $OpenBSD: xinstall.c,v 1.3 1996/06/26 05:44:05 deraadt Exp $    */
1.2       deraadt     2: /*     $NetBSD: xinstall.c,v 1.9 1995/12/20 10:25:17 jonathan Exp $    */
1.1       deraadt     3:
                      4: /*
                      5:  * Copyright (c) 1987, 1993
                      6:  *     The Regents of the University of California.  All rights reserved.
                      7:  *
                      8:  * Redistribution and use in source and binary forms, with or without
                      9:  * modification, are permitted provided that the following conditions
                     10:  * are met:
                     11:  * 1. Redistributions of source code must retain the above copyright
                     12:  *    notice, this list of conditions and the following disclaimer.
                     13:  * 2. Redistributions in binary form must reproduce the above copyright
                     14:  *    notice, this list of conditions and the following disclaimer in the
                     15:  *    documentation and/or other materials provided with the distribution.
                     16:  * 3. All advertising materials mentioning features or use of this software
                     17:  *    must display the following acknowledgement:
                     18:  *     This product includes software developed by the University of
                     19:  *     California, Berkeley and its contributors.
                     20:  * 4. Neither the name of the University nor the names of its contributors
                     21:  *    may be used to endorse or promote products derived from this software
                     22:  *    without specific prior written permission.
                     23:  *
                     24:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     25:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     26:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     27:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     28:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     29:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     30:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     31:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     32:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     33:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     34:  * SUCH DAMAGE.
                     35:  */
                     36:
                     37: #ifndef lint
                     38: static char copyright[] =
                     39: "@(#) Copyright (c) 1987, 1993\n\
                     40:        The Regents of the University of California.  All rights reserved.\n";
                     41: #endif /* not lint */
                     42:
                     43: #ifndef lint
                     44: #if 0
                     45: static char sccsid[] = "@(#)xinstall.c 8.1 (Berkeley) 7/21/93";
                     46: #endif
1.4     ! millert    47: static char rcsid[] = "$OpenBSD: xinstall.c,v 1.3 1996/06/26 05:44:05 deraadt Exp $";
1.1       deraadt    48: #endif /* not lint */
                     49:
                     50: #include <sys/param.h>
                     51: #include <sys/wait.h>
                     52: #include <sys/mman.h>
                     53: #include <sys/stat.h>
                     54:
                     55: #include <ctype.h>
1.4     ! millert    56: #include <err.h>
1.1       deraadt    57: #include <errno.h>
                     58: #include <fcntl.h>
                     59: #include <grp.h>
                     60: #include <paths.h>
                     61: #include <pwd.h>
                     62: #include <stdio.h>
                     63: #include <stdlib.h>
                     64: #include <string.h>
                     65: #include <unistd.h>
1.4     ! millert    66: #include <sysexits.h>
        !            67: #include <utime.h>
1.1       deraadt    68:
                     69: #include "pathnames.h"
                     70:
                     71: struct passwd *pp;
                     72: struct group *gp;
1.4     ! millert    73: int docompare, dodir, dopreserve, dostrip, safecopy;
1.1       deraadt    74: int mode = S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH;
1.4     ! millert    75: char pathbuf[MAXPATHLEN], tempfile[MAXPATHLEN];
1.1       deraadt    76: uid_t uid;
                     77: gid_t gid;
                     78:
                     79: #define        DIRECTORY       0x01            /* Tell install it's a directory. */
                     80: #define        SETFLAGS        0x02            /* Tell install to set flags. */
1.4     ! millert    81: #define NOCHANGEBITS   (UF_IMMUTABLE | UF_APPEND | SF_IMMUTABLE | SF_APPEND)
1.1       deraadt    82:
                     83: void   copy __P((int, char *, int, char *, off_t));
1.4     ! millert    84: int    compare __P((int, const char *, size_t, int, const char *, size_t));
1.1       deraadt    85: void   install __P((char *, char *, u_long, u_int));
                     86: void   install_dir __P((char *));
                     87: u_long string_to_flags __P((char **, u_long *, u_long *));
                     88: void   strip __P((char *));
                     89: void   usage __P((void));
1.4     ! millert    90: int    create_newfile __P((char *, struct stat *));
        !            91: int    create_tempfile __P((char *, char *, size_t));
1.1       deraadt    92:
                     93: int
                     94: main(argc, argv)
                     95:        int argc;
                     96:        char *argv[];
                     97: {
                     98:        struct stat from_sb, to_sb;
                     99:        mode_t *set;
                    100:        u_long fset;
                    101:        u_int iflags;
                    102:        int ch, no_target;
                    103:        char *flags, *to_name, *group = NULL, *owner = NULL;
                    104:
                    105:        iflags = 0;
1.4     ! millert   106:        while ((ch = getopt(argc, argv, "Ccdf:g:m:o:pSs")) != EOF)
1.1       deraadt   107:                switch((char)ch) {
1.4     ! millert   108:                case 'C':
        !           109:                        docompare = 1;
        !           110:                        break;
1.1       deraadt   111:                case 'c':
1.4     ! millert   112:                        /* For backwards compatibility. */
1.1       deraadt   113:                        break;
                    114:                case 'f':
                    115:                        flags = optarg;
                    116:                        if (string_to_flags(&flags, &fset, NULL))
1.4     ! millert   117:                                errx(EX_USAGE, "%s: invalid flag", flags);
1.1       deraadt   118:                        iflags |= SETFLAGS;
                    119:                        break;
                    120:                case 'g':
                    121:                        group = optarg;
                    122:                        break;
                    123:                case 'm':
                    124:                        if (!(set = setmode(optarg)))
1.4     ! millert   125:                                errx(EX_USAGE, "%s: invalid file mode", optarg);
1.1       deraadt   126:                        mode = getmode(set, 0);
                    127:                        break;
                    128:                case 'o':
                    129:                        owner = optarg;
                    130:                        break;
1.4     ! millert   131:                case 'p':
        !           132:                        docompare = dopreserve = 1;
        !           133:                        break;
        !           134:                case 'S':
        !           135:                        safecopy = 1;
        !           136:                        break;
1.1       deraadt   137:                case 's':
                    138:                        dostrip = 1;
                    139:                        break;
                    140:                case 'd':
                    141:                        dodir = 1;
                    142:                        break;
                    143:                case '?':
                    144:                default:
                    145:                        usage();
                    146:                }
                    147:        argc -= optind;
                    148:        argv += optind;
                    149:
1.4     ! millert   150:        /* some options make no sense when creating directories */
        !           151:        if ((safecopy || docompare || dostrip) && dodir)
1.1       deraadt   152:                usage();
                    153:
                    154:        /* must have at least two arguments, except when creating directories */
                    155:        if (argc < 2 && !dodir)
                    156:                usage();
                    157:
1.4     ! millert   158:        /* need to make a temp copy so we can compare stripped version */
        !           159:        if (docompare && dostrip)
        !           160:                safecopy = 1;
        !           161:
1.1       deraadt   162:        /* get group and owner id's */
                    163:        if (group && !(gp = getgrnam(group)) && !isdigit(*group))
1.4     ! millert   164:                errx(EX_NOUSER, "unknown group %s", group);
        !           165:        gid = (group) ? ((gp) ? gp->gr_gid : (gid_t)strtoul(group, NULL, 10)) : (gid_t)-1;
1.1       deraadt   166:        if (owner && !(pp = getpwnam(owner)) && !isdigit(*owner))
1.4     ! millert   167:                errx(EX_NOUSER, "unknown user %s", owner);
        !           168:        uid = (owner) ? ((pp) ? pp->pw_uid : (uid_t)strtoul(owner, NULL, 10)) : (uid_t)-1;
1.1       deraadt   169:
                    170:        if (dodir) {
                    171:                for (; *argv != NULL; ++argv)
                    172:                        install_dir(*argv);
1.4     ! millert   173:                exit(EX_OK);
1.1       deraadt   174:                /* NOTREACHED */
                    175:        }
                    176:
                    177:        no_target = stat(to_name = argv[argc - 1], &to_sb);
                    178:        if (!no_target && S_ISDIR(to_sb.st_mode)) {
                    179:                for (; *argv != to_name; ++argv)
                    180:                        install(*argv, to_name, fset, iflags | DIRECTORY);
1.4     ! millert   181:                exit(EX_OK);
        !           182:                /* NOTREACHED */
1.1       deraadt   183:        }
                    184:
                    185:        /* can't do file1 file2 directory/file */
                    186:        if (argc != 2)
                    187:                usage();
                    188:
                    189:        if (!no_target) {
                    190:                if (stat(*argv, &from_sb))
1.4     ! millert   191:                        err(EX_OSERR, "%s", *argv);
1.1       deraadt   192:                if (!S_ISREG(to_sb.st_mode))
1.4     ! millert   193:                        errx(EX_OSERR, "%s: %s", to_name, strerror(EFTYPE));
1.1       deraadt   194:                if (to_sb.st_dev == from_sb.st_dev &&
                    195:                    to_sb.st_ino == from_sb.st_ino)
1.4     ! millert   196:                        errx(EX_USAGE, "%s and %s are the same file", *argv, to_name);
1.1       deraadt   197:        }
                    198:        install(*argv, to_name, fset, iflags);
1.4     ! millert   199:        exit(EX_OK);
        !           200:        /* NOTREACHED */
1.1       deraadt   201: }
                    202:
                    203: /*
                    204:  * install --
                    205:  *     build a path name and install the file
                    206:  */
                    207: void
                    208: install(from_name, to_name, fset, flags)
                    209:        char *from_name, *to_name;
                    210:        u_long fset;
                    211:        u_int flags;
                    212: {
                    213:        struct stat from_sb, to_sb;
1.4     ! millert   214:        struct utimbuf utb;
        !           215:        int devnull, from_fd, to_fd, serrno, files_match = 0;
1.1       deraadt   216:        char *p;
                    217:
1.4     ! millert   218:        (void)memset((void *)&from_sb, 0, sizeof(from_sb));
        !           219:        (void)memset((void *)&to_sb, 0, sizeof(to_sb));
        !           220:
1.1       deraadt   221:        /* If try to install NULL file to a directory, fails. */
                    222:        if (flags & DIRECTORY || strcmp(from_name, _PATH_DEVNULL)) {
                    223:                if (stat(from_name, &from_sb))
1.4     ! millert   224:                        err(EX_OSERR, "%s", from_name);
1.1       deraadt   225:                if (!S_ISREG(from_sb.st_mode))
1.4     ! millert   226:                        errx(EX_OSERR, "%s: %s", from_name, strerror(EFTYPE));
1.1       deraadt   227:                /* Build the target path. */
                    228:                if (flags & DIRECTORY) {
                    229:                        (void)snprintf(pathbuf, sizeof(pathbuf), "%s/%s",
                    230:                            to_name,
                    231:                            (p = rindex(from_name, '/')) ? ++p : from_name);
                    232:                        to_name = pathbuf;
                    233:                }
                    234:                devnull = 0;
                    235:        } else {
                    236:                devnull = 1;
                    237:        }
                    238:
1.4     ! millert   239:        if (stat(to_name, &to_sb) == 0) {
        !           240:                /* Only compare against regular files. */
        !           241:                if (docompare && !S_ISREG(to_sb.st_mode)) {
        !           242:                        docompare = 0;
        !           243:                        warnx("%s: %s", to_name, strerror(EFTYPE));
        !           244:                }
        !           245:        } else if (docompare) {
        !           246:                /* File does not exist so silently ignore compare flag. */
        !           247:                docompare = 0;
        !           248:        }
        !           249:
        !           250:        if (safecopy) {
        !           251:                to_fd = create_tempfile(to_name, tempfile, sizeof(tempfile));
        !           252:                if (to_fd < 0)
        !           253:                        err(EX_OSERR, "%s", tempfile);
        !           254:        } else if (docompare && !dostrip) {
        !           255:                if ((to_fd = open(to_name, O_RDONLY, 0)) < 0)
        !           256:                        err(EX_OSERR, "%s", to_name);
        !           257:        } else {
        !           258:                if ((to_fd = create_newfile(to_name, &to_sb)) < 0)
        !           259:                        err(EX_OSERR, "%s", to_name);
        !           260:        }
        !           261:
1.1       deraadt   262:        if (!devnull) {
                    263:                if ((from_fd = open(from_name, O_RDONLY, 0)) < 0) {
1.4     ! millert   264:                        serrno = errno;
        !           265:                        (void)unlink(safecopy ? tempfile : to_name);
        !           266:                        errx(EX_OSERR, "%s: %s", from_name, strerror(serrno));
        !           267:                }
        !           268:
        !           269:                if (docompare && !safecopy) {
        !           270:                        files_match = !(compare(from_fd, from_name,
        !           271:                                        (size_t)from_sb.st_size, to_fd,
        !           272:                                        to_name, (size_t)to_sb.st_size));
        !           273:
        !           274:                        /* Truncate "to" file for copy unless we match */
        !           275:                        if (!files_match) {
        !           276:                                (void)close(to_fd);
        !           277:                                if ((to_fd = create_newfile(to_name, &to_sb)) < 0)
        !           278:                                        err(EX_OSERR, "%s", to_name);
        !           279:                        }
1.1       deraadt   280:                }
1.4     ! millert   281:                if (!files_match)
        !           282:                        copy(from_fd, from_name, to_fd,
        !           283:                             safecopy ? tempfile : to_name, from_sb.st_size);
1.1       deraadt   284:        }
1.2       deraadt   285:
                    286:        if (dostrip) {
1.4     ! millert   287:                strip(safecopy ? tempfile : to_name);
1.2       deraadt   288:
                    289:                /*
                    290:                 * Re-open our fd on the target, in case we used a strip
                    291:                 *  that does not work in-place -- like gnu binutils strip.
                    292:                 */
                    293:                close(to_fd);
1.4     ! millert   294:                if ((to_fd = open(safecopy ? tempfile : to_name, O_RDONLY,
        !           295:                     0)) < 0)
        !           296:                        err(EX_OSERR, "stripping %s", to_name);
        !           297:        }
        !           298:
        !           299:        /*
        !           300:         * Compare the (possibly stripped) temp file to the target.
        !           301:         */
        !           302:        if (safecopy && docompare) {
        !           303:                int temp_fd = to_fd;
        !           304:                struct stat temp_sb;
        !           305:
        !           306:                /* Re-open to_fd using the real target name. */
        !           307:                if ((to_fd = open(to_name, O_RDONLY, 0)) < 0)
        !           308:                        err(EX_OSERR, "%s", to_name);
        !           309:
        !           310:                if (fstat(temp_fd, &temp_sb)) {
        !           311:                        serrno = errno;
        !           312:                        (void)unlink(tempfile);
        !           313:                        errx(EX_OSERR, "%s: %s", tempfile, strerror(serrno));
        !           314:                }
        !           315:
        !           316:                if (compare(temp_fd, tempfile, (size_t)temp_sb.st_size, to_fd,
        !           317:                            to_name, (size_t)to_sb.st_size) == 0) {
        !           318:                        /*
        !           319:                         * If target has more than one link we need to
        !           320:                         * replace it in order to snap the extra links.
        !           321:                         * Need to preserve target file times, though.
        !           322:                         */
        !           323:                        if (to_sb.st_nlink != 1) {
        !           324:                                utb.actime = to_sb.st_atime;
        !           325:                                utb.modtime = to_sb.st_mtime;
        !           326:                                (void)utime(tempfile, &utb);
        !           327:                        } else {
        !           328:                                files_match = 1;
        !           329:                                (void)unlink(tempfile);
        !           330:                        }
        !           331:                        (void) close(temp_fd);
        !           332:                }
        !           333:        }
        !           334:
        !           335:        /*
        !           336:         * Move the new file into place if doing a safe copy
        !           337:         * and the files are different (or just not compared).
        !           338:         */
        !           339:        if (safecopy && !files_match) {
        !           340:                /* Try to turn off the immutable bits. */
        !           341:                if (to_sb.st_flags & (NOCHANGEBITS))
        !           342:                        (void)chflags(to_name, to_sb.st_flags & ~(NOCHANGEBITS));
        !           343:                if (rename(tempfile, to_name) < 0 ) {
        !           344:                        serrno = errno;
        !           345:                        unlink(tempfile);
        !           346:                        errx(EX_OSERR, "rename: %s to %s: %s", tempfile,
        !           347:                             to_name, strerror(serrno));
        !           348:                }
        !           349:
        !           350:                /* Re-open to_fd so we aren't hosed by the rename(2). */
        !           351:                (void) close(to_fd);
        !           352:                if ((to_fd = open(to_name, O_RDONLY, 0)) < 0)
        !           353:                        err(EX_OSERR, "%s", to_name);
        !           354:        }
        !           355:
        !           356:        /*
        !           357:         * Preserve the timestamp of the source file if necesary.
        !           358:         */
        !           359:        if (dopreserve && !files_match) {
        !           360:                utb.actime = from_sb.st_atime;
        !           361:                utb.modtime = from_sb.st_mtime;
        !           362:                (void)utime(to_name, &utb);
1.2       deraadt   363:        }
                    364:
1.1       deraadt   365:        /*
                    366:         * Set owner, group, mode for target; do the chown first,
                    367:         * chown may lose the setuid bits.
                    368:         */
1.4     ! millert   369:        if ((gid != (gid_t)-1 || uid != (uid_t)-1) && fchown(to_fd, uid, gid)) {
1.1       deraadt   370:                serrno = errno;
                    371:                (void)unlink(to_name);
1.4     ! millert   372:                errx(EX_OSERR, "%s: chown/chgrp: %s", to_name, strerror(serrno));
1.1       deraadt   373:        }
                    374:        if (fchmod(to_fd, mode)) {
                    375:                serrno = errno;
                    376:                (void)unlink(to_name);
1.4     ! millert   377:                errx(EX_OSERR, "%s: chmod: %s", to_name, strerror(serrno));
1.1       deraadt   378:        }
                    379:
                    380:        /*
                    381:         * If provided a set of flags, set them, otherwise, preserve the
                    382:         * flags, except for the dump flag.
                    383:         */
                    384:        if (fchflags(to_fd,
                    385:            flags & SETFLAGS ? fset : from_sb.st_flags & ~UF_NODUMP)) {
                    386:                serrno = errno;
                    387:                (void)unlink(to_name);
1.4     ! millert   388:                errx(EX_OSERR, "%s: chflags: %s", to_name, strerror(serrno));
1.1       deraadt   389:        }
                    390:
                    391:        (void)close(to_fd);
1.4     ! millert   392:        (void)close(from_fd);
1.1       deraadt   393: }
                    394:
                    395: /*
                    396:  * copy --
                    397:  *     copy from one file to another
                    398:  */
                    399: void
                    400: copy(from_fd, from_name, to_fd, to_name, size)
                    401:        register int from_fd, to_fd;
                    402:        char *from_name, *to_name;
                    403:        off_t size;
                    404: {
                    405:        register int nr, nw;
                    406:        int serrno;
                    407:        char *p, buf[MAXBSIZE];
1.3       deraadt   408:        volatile size_t siz;
1.1       deraadt   409:
                    410:        /*
                    411:         * Mmap and write if less than 8M (the limit is so we don't totally
                    412:         * trash memory on big files.  This is really a minor hack, but it
                    413:         * wins some CPU back.
                    414:         */
                    415:        if (size <= 8 * 1048576) {
                    416:                if ((p = mmap(NULL, (size_t)size, PROT_READ,
                    417:                    0, from_fd, (off_t)0)) == (char *)-1)
1.4     ! millert   418:                        err(EX_OSERR, "%s", from_name);
1.3       deraadt   419:                siz = (size_t)size;
                    420:                if (write(to_fd, p, siz) != siz)
1.4     ! millert   421:                        err(EX_OSERR, "%s", to_name);
        !           422:                (void) munmap(p, (size_t)size);
1.1       deraadt   423:        } else {
                    424:                while ((nr = read(from_fd, buf, sizeof(buf))) > 0)
                    425:                        if ((nw = write(to_fd, buf, nr)) != nr) {
                    426:                                serrno = errno;
                    427:                                (void)unlink(to_name);
1.4     ! millert   428:                                errx(EX_OSERR, "%s: %s",
1.1       deraadt   429:                                    to_name, strerror(nw > 0 ? EIO : serrno));
                    430:                        }
                    431:                if (nr != 0) {
                    432:                        serrno = errno;
                    433:                        (void)unlink(to_name);
1.4     ! millert   434:                        errx(EX_OSERR, "%s: %s", from_name, strerror(serrno));
1.1       deraadt   435:                }
                    436:        }
                    437: }
                    438:
                    439: /*
1.4     ! millert   440:  * compare --
        !           441:  *     compare two files; non-zero means files differ
        !           442:  */
        !           443: int
        !           444: compare(from_fd, from_name, from_len, to_fd, to_name, to_len)
        !           445:        int from_fd;
        !           446:        const char *from_name;
        !           447:        size_t from_len;
        !           448:        int to_fd;
        !           449:        const char *to_name;
        !           450:        size_t to_len;
        !           451: {
        !           452:        caddr_t p1, p2;
        !           453:        register size_t length, remainder;
        !           454:        int dfound;
        !           455:
        !           456:        if (from_len != to_len)
        !           457:                return(1);
        !           458:
        !           459:        /* Rewind file descriptors. */
        !           460:        if (lseek(from_fd, (off_t)0, SEEK_SET) == (off_t)-1)
        !           461:                err(EX_OSERR, "lseek: %s", from_name);
        !           462:        if (lseek(to_fd, (off_t)0, SEEK_SET) == (off_t)-1)
        !           463:                err(EX_OSERR, "lseek: %s", to_name);
        !           464:
        !           465:        /*
        !           466:         * Compare the two files being careful not to mmap
        !           467:         * more than 8M at a time.
        !           468:         */
        !           469:        remainder = from_len;
        !           470:        do {
        !           471:                length = MIN(remainder, 8 * 1048576);
        !           472:                remainder -= length;
        !           473:
        !           474:                if ((p1 = mmap(NULL, length, PROT_READ, 0, from_fd, (off_t)0))
        !           475:                     == (caddr_t)-1)
        !           476:                        err(EX_OSERR, "%s", from_name);
        !           477:                if ((p2 = mmap(NULL, length, PROT_READ, 0, to_fd, (off_t)0))
        !           478:                     == (caddr_t)-1)
        !           479:                        err(EX_OSERR, "%s", to_name);
        !           480:
        !           481:                dfound = memcmp(p1, p2, length);
        !           482:
        !           483:                (void) munmap(p1, length);
        !           484:                (void) munmap(p2, length);
        !           485:
        !           486:                if (dfound)
        !           487:                        break;
        !           488:
        !           489:        } while (remainder > 0);
        !           490:
        !           491:        return(dfound);
        !           492: }
        !           493:
        !           494: /*
1.1       deraadt   495:  * strip --
                    496:  *     use strip(1) to strip the target file
                    497:  */
                    498: void
                    499: strip(to_name)
                    500:        char *to_name;
                    501: {
                    502:        int serrno, status;
                    503:
                    504:        switch (vfork()) {
                    505:        case -1:
                    506:                serrno = errno;
                    507:                (void)unlink(to_name);
1.4     ! millert   508:                errx(EX_TEMPFAIL, "forks: %s", strerror(serrno));
1.1       deraadt   509:        case 0:
                    510:                execl(_PATH_STRIP, "strip", to_name, NULL);
1.4     ! millert   511:                err(EX_OSERR, "%s", _PATH_STRIP);
1.1       deraadt   512:        default:
                    513:                if (wait(&status) == -1 || status)
                    514:                        (void)unlink(to_name);
                    515:        }
                    516: }
                    517:
                    518: /*
                    519:  * install_dir --
                    520:  *     build directory heirarchy
                    521:  */
                    522: void
                    523: install_dir(path)
                    524:         char *path;
                    525: {
                    526:         register char *p;
                    527:         struct stat sb;
                    528:         int ch;
                    529:
                    530:         for (p = path;; ++p)
                    531:                 if (!*p || (p != path && *p  == '/')) {
                    532:                         ch = *p;
                    533:                         *p = '\0';
                    534:                         if (stat(path, &sb)) {
                    535:                                 if (errno != ENOENT || mkdir(path, 0777) < 0) {
1.4     ! millert   536:                                        err(EX_OSERR, "%s", path);
1.1       deraadt   537:                                        /* NOTREACHED */
                    538:                                 }
                    539:                         }
                    540:                         if (!(*p = ch))
                    541:                                break;
                    542:                 }
                    543:
1.4     ! millert   544:        if (((gid != (gid_t)-1 || uid != (uid_t)-1) && chown(path, uid, gid)) ||
1.1       deraadt   545:             chmod(path, mode)) {
                    546:                 warn("%s", path);
                    547:         }
                    548: }
                    549:
                    550: /*
                    551:  * usage --
                    552:  *     print a usage message and die
                    553:  */
                    554: void
                    555: usage()
                    556: {
                    557:        (void)fprintf(stderr, "\
                    558: usage: install [-cs] [-f flags] [-g group] [-m mode] [-o owner] file1 file2\n\
                    559:        install [-cs] [-f flags] [-g group] [-m mode] [-o owner] file1 ... fileN directory\n\
                    560:        install  -d   [-g group] [-m mode] [-o owner] directory ...\n");
1.4     ! millert   561:        exit(EX_USAGE);
        !           562:        /* NOTREACHED */
        !           563: }
        !           564:
        !           565: /*
        !           566:  * create_tempfile --
        !           567:  *     create a temporary file based on path and open it
        !           568:  */
        !           569: int
        !           570: create_tempfile(path, temp, tsize)
        !           571:         char *path;
        !           572:         char *temp;
        !           573:        size_t tsize;
        !           574: {
        !           575:        char *p;
        !           576:
        !           577:        (void)strncpy(temp, path, tsize);
        !           578:        temp[tsize - 1] = '\0';
        !           579:        if ((p = strrchr(temp, '/')))
        !           580:                p++;
        !           581:        else
        !           582:                p = temp;
        !           583:        (void)strncpy(p, "INS@XXXXXX", &temp[tsize - 1] - p);
        !           584:        temp[tsize - 1] = '\0';
        !           585:
        !           586:        return(mkstemp(temp));
        !           587: }
        !           588:
        !           589: /*
        !           590:  * create_newfile --
        !           591:  *     create a new file, overwriting an existing one if necesary
        !           592:  */
        !           593: int
        !           594: create_newfile(path, sbp)
        !           595:         char *path;
        !           596:        struct stat *sbp;
        !           597: {
        !           598:        /*
        !           599:         * Unlink now... avoid ETXTBSY errors later.  Try and turn
        !           600:         * off the append/immutable bits -- if we fail, go ahead,
        !           601:         * it might work.
        !           602:         */
        !           603:        if (sbp->st_flags & (NOCHANGEBITS))
        !           604:                (void)chflags(path, sbp->st_flags & ~(NOCHANGEBITS));
        !           605:
        !           606:        (void)unlink(path);
        !           607:
        !           608:        return(open(path, O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR));
1.1       deraadt   609: }