[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.17

1.17    ! millert     1: /*     $OpenBSD: xinstall.c,v 1.16 1998/09/26 09:04:43 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.17    ! millert    47: static char rcsid[] = "$OpenBSD: xinstall.c,v 1.16 1998/09/26 09:04:43 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:
1.17    ! millert    83: void   copy __P((int, char *, int, char *, off_t, int));
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.17    ! millert    92: int    file_write __P((int, char *, register int, int *, int *, int));
1.1       deraadt    93:
                     94: int
                     95: main(argc, argv)
                     96:        int argc;
                     97:        char *argv[];
                     98: {
                     99:        struct stat from_sb, to_sb;
                    100:        mode_t *set;
                    101:        u_long fset;
                    102:        u_int iflags;
                    103:        int ch, no_target;
                    104:        char *flags, *to_name, *group = NULL, *owner = NULL;
                    105:
                    106:        iflags = 0;
1.10      millert   107:        while ((ch = getopt(argc, argv, "Ccdf:g:m:o:pSs")) != -1)
1.1       deraadt   108:                switch((char)ch) {
1.4       millert   109:                case 'C':
                    110:                        docompare = 1;
                    111:                        break;
1.1       deraadt   112:                case 'c':
1.4       millert   113:                        /* For backwards compatibility. */
1.1       deraadt   114:                        break;
                    115:                case 'f':
                    116:                        flags = optarg;
                    117:                        if (string_to_flags(&flags, &fset, NULL))
1.4       millert   118:                                errx(EX_USAGE, "%s: invalid flag", flags);
1.1       deraadt   119:                        iflags |= SETFLAGS;
                    120:                        break;
                    121:                case 'g':
                    122:                        group = optarg;
                    123:                        break;
                    124:                case 'm':
                    125:                        if (!(set = setmode(optarg)))
1.4       millert   126:                                errx(EX_USAGE, "%s: invalid file mode", optarg);
1.1       deraadt   127:                        mode = getmode(set, 0);
1.16      deraadt   128:                        free(set);
1.1       deraadt   129:                        break;
                    130:                case 'o':
                    131:                        owner = optarg;
                    132:                        break;
1.4       millert   133:                case 'p':
                    134:                        docompare = dopreserve = 1;
                    135:                        break;
                    136:                case 'S':
                    137:                        safecopy = 1;
                    138:                        break;
1.1       deraadt   139:                case 's':
                    140:                        dostrip = 1;
                    141:                        break;
                    142:                case 'd':
                    143:                        dodir = 1;
                    144:                        break;
                    145:                case '?':
                    146:                default:
                    147:                        usage();
                    148:                }
                    149:        argc -= optind;
                    150:        argv += optind;
                    151:
1.4       millert   152:        /* some options make no sense when creating directories */
                    153:        if ((safecopy || docompare || dostrip) && dodir)
1.1       deraadt   154:                usage();
                    155:
                    156:        /* must have at least two arguments, except when creating directories */
                    157:        if (argc < 2 && !dodir)
                    158:                usage();
                    159:
1.4       millert   160:        /* need to make a temp copy so we can compare stripped version */
                    161:        if (docompare && dostrip)
                    162:                safecopy = 1;
                    163:
1.1       deraadt   164:        /* get group and owner id's */
                    165:        if (group && !(gp = getgrnam(group)) && !isdigit(*group))
1.4       millert   166:                errx(EX_NOUSER, "unknown group %s", group);
                    167:        gid = (group) ? ((gp) ? gp->gr_gid : (gid_t)strtoul(group, NULL, 10)) : (gid_t)-1;
1.1       deraadt   168:        if (owner && !(pp = getpwnam(owner)) && !isdigit(*owner))
1.4       millert   169:                errx(EX_NOUSER, "unknown user %s", owner);
                    170:        uid = (owner) ? ((pp) ? pp->pw_uid : (uid_t)strtoul(owner, NULL, 10)) : (uid_t)-1;
1.1       deraadt   171:
                    172:        if (dodir) {
                    173:                for (; *argv != NULL; ++argv)
                    174:                        install_dir(*argv);
1.4       millert   175:                exit(EX_OK);
1.1       deraadt   176:                /* NOTREACHED */
                    177:        }
                    178:
                    179:        no_target = stat(to_name = argv[argc - 1], &to_sb);
                    180:        if (!no_target && S_ISDIR(to_sb.st_mode)) {
                    181:                for (; *argv != to_name; ++argv)
                    182:                        install(*argv, to_name, fset, iflags | DIRECTORY);
1.4       millert   183:                exit(EX_OK);
                    184:                /* NOTREACHED */
1.1       deraadt   185:        }
                    186:
                    187:        /* can't do file1 file2 directory/file */
                    188:        if (argc != 2)
                    189:                usage();
                    190:
                    191:        if (!no_target) {
                    192:                if (stat(*argv, &from_sb))
1.4       millert   193:                        err(EX_OSERR, "%s", *argv);
1.1       deraadt   194:                if (!S_ISREG(to_sb.st_mode))
1.4       millert   195:                        errx(EX_OSERR, "%s: %s", to_name, strerror(EFTYPE));
1.1       deraadt   196:                if (to_sb.st_dev == from_sb.st_dev &&
                    197:                    to_sb.st_ino == from_sb.st_ino)
1.4       millert   198:                        errx(EX_USAGE, "%s and %s are the same file", *argv, to_name);
1.1       deraadt   199:        }
                    200:        install(*argv, to_name, fset, iflags);
1.4       millert   201:        exit(EX_OK);
                    202:        /* NOTREACHED */
1.1       deraadt   203: }
                    204:
                    205: /*
                    206:  * install --
                    207:  *     build a path name and install the file
                    208:  */
                    209: void
                    210: install(from_name, to_name, fset, flags)
                    211:        char *from_name, *to_name;
                    212:        u_long fset;
                    213:        u_int flags;
                    214: {
                    215:        struct stat from_sb, to_sb;
1.4       millert   216:        struct utimbuf utb;
                    217:        int devnull, from_fd, to_fd, serrno, files_match = 0;
1.1       deraadt   218:        char *p;
                    219:
1.4       millert   220:        (void)memset((void *)&from_sb, 0, sizeof(from_sb));
                    221:        (void)memset((void *)&to_sb, 0, sizeof(to_sb));
                    222:
1.1       deraadt   223:        /* If try to install NULL file to a directory, fails. */
                    224:        if (flags & DIRECTORY || strcmp(from_name, _PATH_DEVNULL)) {
                    225:                if (stat(from_name, &from_sb))
1.4       millert   226:                        err(EX_OSERR, "%s", from_name);
1.1       deraadt   227:                if (!S_ISREG(from_sb.st_mode))
1.4       millert   228:                        errx(EX_OSERR, "%s: %s", from_name, strerror(EFTYPE));
1.1       deraadt   229:                /* Build the target path. */
                    230:                if (flags & DIRECTORY) {
                    231:                        (void)snprintf(pathbuf, sizeof(pathbuf), "%s/%s",
                    232:                            to_name,
1.11      millert   233:                            (p = strrchr(from_name, '/')) ? ++p : from_name);
1.1       deraadt   234:                        to_name = pathbuf;
                    235:                }
                    236:                devnull = 0;
                    237:        } else {
                    238:                devnull = 1;
                    239:        }
                    240:
1.4       millert   241:        if (stat(to_name, &to_sb) == 0) {
                    242:                /* Only compare against regular files. */
                    243:                if (docompare && !S_ISREG(to_sb.st_mode)) {
                    244:                        docompare = 0;
                    245:                        warnx("%s: %s", to_name, strerror(EFTYPE));
                    246:                }
                    247:        } else if (docompare) {
                    248:                /* File does not exist so silently ignore compare flag. */
                    249:                docompare = 0;
                    250:        }
                    251:
                    252:        if (safecopy) {
                    253:                to_fd = create_tempfile(to_name, tempfile, sizeof(tempfile));
                    254:                if (to_fd < 0)
                    255:                        err(EX_OSERR, "%s", tempfile);
                    256:        } else if (docompare && !dostrip) {
                    257:                if ((to_fd = open(to_name, O_RDONLY, 0)) < 0)
                    258:                        err(EX_OSERR, "%s", to_name);
                    259:        } else {
                    260:                if ((to_fd = create_newfile(to_name, &to_sb)) < 0)
                    261:                        err(EX_OSERR, "%s", to_name);
                    262:        }
                    263:
1.1       deraadt   264:        if (!devnull) {
                    265:                if ((from_fd = open(from_name, O_RDONLY, 0)) < 0) {
1.4       millert   266:                        serrno = errno;
                    267:                        (void)unlink(safecopy ? tempfile : to_name);
                    268:                        errx(EX_OSERR, "%s: %s", from_name, strerror(serrno));
                    269:                }
                    270:
                    271:                if (docompare && !safecopy) {
                    272:                        files_match = !(compare(from_fd, from_name,
                    273:                                        (size_t)from_sb.st_size, to_fd,
                    274:                                        to_name, (size_t)to_sb.st_size));
                    275:
                    276:                        /* Truncate "to" file for copy unless we match */
                    277:                        if (!files_match) {
                    278:                                (void)close(to_fd);
                    279:                                if ((to_fd = create_newfile(to_name, &to_sb)) < 0)
                    280:                                        err(EX_OSERR, "%s", to_name);
                    281:                        }
1.1       deraadt   282:                }
1.4       millert   283:                if (!files_match)
                    284:                        copy(from_fd, from_name, to_fd,
1.17    ! millert   285:                             safecopy ? tempfile : to_name, from_sb.st_size,
        !           286:                             ((off_t)from_sb.st_blocks * S_BLKSIZE < from_sb.st_size));
1.1       deraadt   287:        }
1.2       deraadt   288:
                    289:        if (dostrip) {
1.4       millert   290:                strip(safecopy ? tempfile : to_name);
1.2       deraadt   291:
                    292:                /*
                    293:                 * Re-open our fd on the target, in case we used a strip
                    294:                 *  that does not work in-place -- like gnu binutils strip.
                    295:                 */
                    296:                close(to_fd);
1.4       millert   297:                if ((to_fd = open(safecopy ? tempfile : to_name, O_RDONLY,
                    298:                     0)) < 0)
                    299:                        err(EX_OSERR, "stripping %s", to_name);
                    300:        }
                    301:
                    302:        /*
                    303:         * Compare the (possibly stripped) temp file to the target.
                    304:         */
                    305:        if (safecopy && docompare) {
                    306:                int temp_fd = to_fd;
                    307:                struct stat temp_sb;
                    308:
                    309:                /* Re-open to_fd using the real target name. */
                    310:                if ((to_fd = open(to_name, O_RDONLY, 0)) < 0)
                    311:                        err(EX_OSERR, "%s", to_name);
                    312:
                    313:                if (fstat(temp_fd, &temp_sb)) {
                    314:                        serrno = errno;
                    315:                        (void)unlink(tempfile);
                    316:                        errx(EX_OSERR, "%s: %s", tempfile, strerror(serrno));
                    317:                }
                    318:
                    319:                if (compare(temp_fd, tempfile, (size_t)temp_sb.st_size, to_fd,
                    320:                            to_name, (size_t)to_sb.st_size) == 0) {
                    321:                        /*
                    322:                         * If target has more than one link we need to
                    323:                         * replace it in order to snap the extra links.
                    324:                         * Need to preserve target file times, though.
                    325:                         */
                    326:                        if (to_sb.st_nlink != 1) {
                    327:                                utb.actime = to_sb.st_atime;
                    328:                                utb.modtime = to_sb.st_mtime;
                    329:                                (void)utime(tempfile, &utb);
                    330:                        } else {
                    331:                                files_match = 1;
                    332:                                (void)unlink(tempfile);
                    333:                        }
                    334:                        (void) close(temp_fd);
                    335:                }
                    336:        }
                    337:
                    338:        /*
                    339:         * Move the new file into place if doing a safe copy
                    340:         * and the files are different (or just not compared).
                    341:         */
                    342:        if (safecopy && !files_match) {
                    343:                /* Try to turn off the immutable bits. */
                    344:                if (to_sb.st_flags & (NOCHANGEBITS))
                    345:                        (void)chflags(to_name, to_sb.st_flags & ~(NOCHANGEBITS));
                    346:                if (rename(tempfile, to_name) < 0 ) {
                    347:                        serrno = errno;
                    348:                        unlink(tempfile);
                    349:                        errx(EX_OSERR, "rename: %s to %s: %s", tempfile,
                    350:                             to_name, strerror(serrno));
                    351:                }
                    352:
                    353:                /* Re-open to_fd so we aren't hosed by the rename(2). */
                    354:                (void) close(to_fd);
                    355:                if ((to_fd = open(to_name, O_RDONLY, 0)) < 0)
                    356:                        err(EX_OSERR, "%s", to_name);
                    357:        }
                    358:
                    359:        /*
                    360:         * Preserve the timestamp of the source file if necesary.
                    361:         */
                    362:        if (dopreserve && !files_match) {
                    363:                utb.actime = from_sb.st_atime;
                    364:                utb.modtime = from_sb.st_mtime;
                    365:                (void)utime(to_name, &utb);
1.2       deraadt   366:        }
                    367:
1.1       deraadt   368:        /*
                    369:         * Set owner, group, mode for target; do the chown first,
                    370:         * chown may lose the setuid bits.
                    371:         */
1.4       millert   372:        if ((gid != (gid_t)-1 || uid != (uid_t)-1) && fchown(to_fd, uid, gid)) {
1.1       deraadt   373:                serrno = errno;
                    374:                (void)unlink(to_name);
1.4       millert   375:                errx(EX_OSERR, "%s: chown/chgrp: %s", to_name, strerror(serrno));
1.1       deraadt   376:        }
                    377:        if (fchmod(to_fd, mode)) {
                    378:                serrno = errno;
                    379:                (void)unlink(to_name);
1.4       millert   380:                errx(EX_OSERR, "%s: chmod: %s", to_name, strerror(serrno));
1.1       deraadt   381:        }
                    382:
                    383:        /*
                    384:         * If provided a set of flags, set them, otherwise, preserve the
                    385:         * flags, except for the dump flag.
                    386:         */
                    387:        if (fchflags(to_fd,
                    388:            flags & SETFLAGS ? fset : from_sb.st_flags & ~UF_NODUMP)) {
1.12      millert   389:                if (errno != EOPNOTSUPP || (from_sb.st_flags & ~UF_NODUMP) != 0)
                    390:                        warnx("%s: chflags: %s", to_name, strerror(errno));
1.1       deraadt   391:        }
                    392:
                    393:        (void)close(to_fd);
1.4       millert   394:        (void)close(from_fd);
1.1       deraadt   395: }
                    396:
                    397: /*
                    398:  * copy --
                    399:  *     copy from one file to another
                    400:  */
                    401: void
1.17    ! millert   402: copy(from_fd, from_name, to_fd, to_name, size, sparse)
1.1       deraadt   403:        register int from_fd, to_fd;
                    404:        char *from_name, *to_name;
                    405:        off_t size;
1.17    ! millert   406:        int sparse;
1.1       deraadt   407: {
                    408:        register int nr, nw;
                    409:        int serrno;
                    410:        char *p, buf[MAXBSIZE];
                    411:
1.7       millert   412:        /* Rewind file descriptors. */
                    413:        if (lseek(from_fd, (off_t)0, SEEK_SET) == (off_t)-1)
                    414:                err(EX_OSERR, "lseek: %s", from_name);
                    415:        if (lseek(to_fd, (off_t)0, SEEK_SET) == (off_t)-1)
                    416:                err(EX_OSERR, "lseek: %s", to_name);
                    417:
1.1       deraadt   418:        /*
                    419:         * Mmap and write if less than 8M (the limit is so we don't totally
                    420:         * trash memory on big files.  This is really a minor hack, but it
1.17    ! millert   421:         * wins some CPU back.  Sparse files need special treatment.
1.1       deraadt   422:         */
1.17    ! millert   423:        if (!sparse && size <= 8 * 1048576) {
        !           424:                volatile size_t siz;
        !           425:
1.1       deraadt   426:                if ((p = mmap(NULL, (size_t)size, PROT_READ,
1.15      chuck     427:                    MAP_PRIVATE, from_fd, (off_t)0)) == (char *)-1) {
1.6       millert   428:                        serrno = errno;
                    429:                        (void)unlink(to_name);
                    430:                        errx(EX_OSERR, "%s: %s", from_name, strerror(serrno));
                    431:                }
1.3       deraadt   432:                siz = (size_t)size;
1.6       millert   433:                if ((nw = write(to_fd, p, siz)) != siz) {
                    434:                        serrno = errno;
                    435:                        (void)unlink(to_name);
                    436:                        errx(EX_OSERR, "%s: %s",
                    437:                            to_name, strerror(nw > 0 ? EIO : serrno));
                    438:                }
1.4       millert   439:                (void) munmap(p, (size_t)size);
1.1       deraadt   440:        } else {
1.17    ! millert   441:                int sz, rem, isem = 1;
        !           442:                struct stat sb;
        !           443:
        !           444:                /*
        !           445:                 * Pass the blocksize of the file being written to the write
        !           446:                 * routine.  if the size is zero, use the default S_BLKSIZE.
        !           447:                 */
        !           448:                if (fstat(to_fd, &sb) != 0 || sb.st_blksize == 0)
        !           449:                        sz = S_BLKSIZE;
        !           450:                else
        !           451:                        sz = sb.st_blksize;
        !           452:
        !           453:                while ((nr = read(from_fd, buf, sizeof(buf))) > 0) {
        !           454:                        if (sparse)
        !           455:                                nw = file_write(to_fd, buf, nr, &rem, &isem, sz);
        !           456:                        else
        !           457:                                nw = write(to_fd, buf, nr);
        !           458:                        if (nw != nr) {
1.1       deraadt   459:                                serrno = errno;
                    460:                                (void)unlink(to_name);
1.4       millert   461:                                errx(EX_OSERR, "%s: %s",
1.1       deraadt   462:                                    to_name, strerror(nw > 0 ? EIO : serrno));
                    463:                        }
1.17    ! millert   464:                }
1.1       deraadt   465:                if (nr != 0) {
                    466:                        serrno = errno;
                    467:                        (void)unlink(to_name);
1.4       millert   468:                        errx(EX_OSERR, "%s: %s", from_name, strerror(serrno));
1.1       deraadt   469:                }
                    470:        }
                    471: }
                    472:
                    473: /*
1.4       millert   474:  * compare --
                    475:  *     compare two files; non-zero means files differ
                    476:  */
                    477: int
                    478: compare(from_fd, from_name, from_len, to_fd, to_name, to_len)
                    479:        int from_fd;
                    480:        const char *from_name;
                    481:        size_t from_len;
                    482:        int to_fd;
                    483:        const char *to_name;
                    484:        size_t to_len;
                    485: {
                    486:        caddr_t p1, p2;
                    487:        register size_t length, remainder;
                    488:        int dfound;
                    489:
                    490:        if (from_len != to_len)
                    491:                return(1);
                    492:
                    493:        /* Rewind file descriptors. */
                    494:        if (lseek(from_fd, (off_t)0, SEEK_SET) == (off_t)-1)
                    495:                err(EX_OSERR, "lseek: %s", from_name);
                    496:        if (lseek(to_fd, (off_t)0, SEEK_SET) == (off_t)-1)
                    497:                err(EX_OSERR, "lseek: %s", to_name);
                    498:
                    499:        /*
                    500:         * Compare the two files being careful not to mmap
                    501:         * more than 8M at a time.
                    502:         */
                    503:        remainder = from_len;
                    504:        do {
                    505:                length = MIN(remainder, 8 * 1048576);
                    506:                remainder -= length;
                    507:
                    508:                if ((p1 = mmap(NULL, length, PROT_READ, 0, from_fd, (off_t)0))
                    509:                     == (caddr_t)-1)
                    510:                        err(EX_OSERR, "%s", from_name);
                    511:                if ((p2 = mmap(NULL, length, PROT_READ, 0, to_fd, (off_t)0))
                    512:                     == (caddr_t)-1)
                    513:                        err(EX_OSERR, "%s", to_name);
                    514:
                    515:                dfound = memcmp(p1, p2, length);
                    516:
                    517:                (void) munmap(p1, length);
                    518:                (void) munmap(p2, length);
                    519:
1.7       millert   520:        } while (!dfound && remainder > 0);
1.4       millert   521:
                    522:        return(dfound);
                    523: }
                    524:
                    525: /*
1.1       deraadt   526:  * strip --
                    527:  *     use strip(1) to strip the target file
                    528:  */
                    529: void
                    530: strip(to_name)
                    531:        char *to_name;
                    532: {
                    533:        int serrno, status;
1.13      millert   534:        char *path_strip;
                    535:
                    536:        if (issetugid() || (path_strip = getenv("STRIP")) == NULL)
                    537:                path_strip = _PATH_STRIP;
1.1       deraadt   538:
                    539:        switch (vfork()) {
                    540:        case -1:
                    541:                serrno = errno;
                    542:                (void)unlink(to_name);
1.4       millert   543:                errx(EX_TEMPFAIL, "forks: %s", strerror(serrno));
1.1       deraadt   544:        case 0:
1.13      millert   545:                execl(path_strip, "strip", to_name, NULL);
                    546:                warn("%s", path_strip);
1.9       deraadt   547:                _exit(EX_OSERR);
1.1       deraadt   548:        default:
1.14      millert   549:                if (wait(&status) == -1 || !WIFEXITED(status))
1.1       deraadt   550:                        (void)unlink(to_name);
                    551:        }
                    552: }
                    553:
                    554: /*
                    555:  * install_dir --
                    556:  *     build directory heirarchy
                    557:  */
                    558: void
                    559: install_dir(path)
                    560:         char *path;
                    561: {
1.8       imp       562:        register char *p;
                    563:        struct stat sb;
                    564:        int ch;
                    565:
                    566:        for (p = path;; ++p)
                    567:                if (!*p || (p != path && *p  == '/')) {
                    568:                        ch = *p;
                    569:                        *p = '\0';
                    570:                        if (stat(path, &sb)) {
                    571:                                if (errno != ENOENT || mkdir(path, 0777) < 0) {
1.4       millert   572:                                        err(EX_OSERR, "%s", path);
1.1       deraadt   573:                                        /* NOTREACHED */
1.8       imp       574:                                }
                    575:                        }
                    576:                        if (!(*p = ch))
1.1       deraadt   577:                                break;
1.8       imp       578:                }
1.1       deraadt   579:
1.4       millert   580:        if (((gid != (gid_t)-1 || uid != (uid_t)-1) && chown(path, uid, gid)) ||
1.8       imp       581:            chmod(path, mode)) {
                    582:                warn("%s", path);
                    583:        }
1.1       deraadt   584: }
                    585:
                    586: /*
                    587:  * usage --
                    588:  *     print a usage message and die
                    589:  */
                    590: void
                    591: usage()
                    592: {
                    593:        (void)fprintf(stderr, "\
1.5       millert   594: usage: install [-CcpSs] [-f flags] [-g group] [-m mode] [-o owner] file1 file2\n\
                    595:        install [-CcpSs] [-f flags] [-g group] [-m mode] [-o owner] file1 ... fileN directory\n\
1.1       deraadt   596:        install  -d   [-g group] [-m mode] [-o owner] directory ...\n");
1.4       millert   597:        exit(EX_USAGE);
                    598:        /* NOTREACHED */
                    599: }
                    600:
                    601: /*
                    602:  * create_tempfile --
                    603:  *     create a temporary file based on path and open it
                    604:  */
                    605: int
                    606: create_tempfile(path, temp, tsize)
                    607:         char *path;
                    608:         char *temp;
                    609:        size_t tsize;
                    610: {
                    611:        char *p;
                    612:
                    613:        (void)strncpy(temp, path, tsize);
                    614:        temp[tsize - 1] = '\0';
                    615:        if ((p = strrchr(temp, '/')))
                    616:                p++;
                    617:        else
                    618:                p = temp;
                    619:        (void)strncpy(p, "INS@XXXXXX", &temp[tsize - 1] - p);
                    620:        temp[tsize - 1] = '\0';
                    621:
                    622:        return(mkstemp(temp));
                    623: }
                    624:
                    625: /*
                    626:  * create_newfile --
                    627:  *     create a new file, overwriting an existing one if necesary
                    628:  */
                    629: int
                    630: create_newfile(path, sbp)
                    631:         char *path;
                    632:        struct stat *sbp;
                    633: {
                    634:        /*
                    635:         * Unlink now... avoid ETXTBSY errors later.  Try and turn
                    636:         * off the append/immutable bits -- if we fail, go ahead,
                    637:         * it might work.
                    638:         */
                    639:        if (sbp->st_flags & (NOCHANGEBITS))
                    640:                (void)chflags(path, sbp->st_flags & ~(NOCHANGEBITS));
                    641:
                    642:        (void)unlink(path);
                    643:
                    644:        return(open(path, O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR));
1.17    ! millert   645: }
        !           646:
        !           647: /*
        !           648:  * file_write()
        !           649:  *     Write/copy a file (during copy or archive extract). This routine knows
        !           650:  *     how to copy files with lseek holes in it. (Which are read as file
        !           651:  *     blocks containing all 0's but do not have any file blocks associated
        !           652:  *     with the data). Typical examples of these are files created by dbm
        !           653:  *     variants (.pag files). While the file size of these files are huge, the
        !           654:  *     actual storage is quite small (the files are sparse). The problem is
        !           655:  *     the holes read as all zeros so are probably stored on the archive that
        !           656:  *     way (there is no way to determine if the file block is really a hole,
        !           657:  *     we only know that a file block of all zero's can be a hole).
        !           658:  *     At this writing, no major archive format knows how to archive files
        !           659:  *     with holes. However, on extraction (or during copy, -rw) we have to
        !           660:  *     deal with these files. Without detecting the holes, the files can
        !           661:  *     consume a lot of file space if just written to disk. This replacement
        !           662:  *     for write when passed the basic allocation size of a file system block,
        !           663:  *     uses lseek whenever it detects the input data is all 0 within that
        !           664:  *     file block. In more detail, the strategy is as follows:
        !           665:  *     While the input is all zero keep doing an lseek. Keep track of when we
        !           666:  *     pass over file block boundries. Only write when we hit a non zero
        !           667:  *     input. once we have written a file block, we continue to write it to
        !           668:  *     the end (we stop looking at the input). When we reach the start of the
        !           669:  *     next file block, start checking for zero blocks again. Working on file
        !           670:  *     block boundries significantly reduces the overhead when copying files
        !           671:  *     that are NOT very sparse. This overhead (when compared to a write) is
        !           672:  *     almost below the measurement resolution on many systems. Without it,
        !           673:  *     files with holes cannot be safely copied. It does has a side effect as
        !           674:  *     it can put holes into files that did not have them before, but that is
        !           675:  *     not a problem since the file contents are unchanged (in fact it saves
        !           676:  *     file space). (Except on paging files for diskless clients. But since we
        !           677:  *     cannot determine one of those file from here, we ignore them). If this
        !           678:  *     ever ends up on a system where CTG files are supported and the holes
        !           679:  *     are not desired, just do a conditional test in those routines that
        !           680:  *     call file_write() and have it call write() instead. BEFORE CLOSING THE
        !           681:  *     FILE, make sure to call file_flush() when the last write finishes with
        !           682:  *     an empty block. A lot of file systems will not create an lseek hole at
        !           683:  *     the end. In this case we drop a single 0 at the end to force the
        !           684:  *     trailing 0's in the file.
        !           685:  *     ---Parameters---
        !           686:  *     rem: how many bytes left in this file system block
        !           687:  *     isempt: have we written to the file block yet (is it empty)
        !           688:  *     sz: basic file block allocation size
        !           689:  *     cnt: number of bytes on this write
        !           690:  *     str: buffer to write
        !           691:  * Return:
        !           692:  *     number of bytes written, -1 on write (or lseek) error.
        !           693:  */
        !           694:
        !           695: int
        !           696: file_write(fd, str, cnt, rem, isempt, sz)
        !           697:        int fd;
        !           698:        char *str;
        !           699:        register int cnt;
        !           700:        int *rem;
        !           701:        int *isempt;
        !           702:        int sz;
        !           703: {
        !           704:        register char *pt;
        !           705:        register char *end;
        !           706:        register int wcnt;
        !           707:        register char *st = str;
        !           708:
        !           709:        /*
        !           710:         * while we have data to process
        !           711:         */
        !           712:        while (cnt) {
        !           713:                if (!*rem) {
        !           714:                        /*
        !           715:                         * We are now at the start of file system block again
        !           716:                         * (or what we think one is...). start looking for
        !           717:                         * empty blocks again
        !           718:                         */
        !           719:                        *isempt = 1;
        !           720:                        *rem = sz;
        !           721:                }
        !           722:
        !           723:                /*
        !           724:                 * only examine up to the end of the current file block or
        !           725:                 * remaining characters to write, whatever is smaller
        !           726:                 */
        !           727:                wcnt = MIN(cnt, *rem);
        !           728:                cnt -= wcnt;
        !           729:                *rem -= wcnt;
        !           730:                if (*isempt) {
        !           731:                        /*
        !           732:                         * have not written to this block yet, so we keep
        !           733:                         * looking for zero's
        !           734:                         */
        !           735:                        pt = st;
        !           736:                        end = st + wcnt;
        !           737:
        !           738:                        /*
        !           739:                         * look for a zero filled buffer
        !           740:                         */
        !           741:                        while ((pt < end) && (*pt == '\0'))
        !           742:                                ++pt;
        !           743:
        !           744:                        if (pt == end) {
        !           745:                                /*
        !           746:                                 * skip, buf is empty so far
        !           747:                                 */
        !           748:                                if (lseek(fd, (off_t)wcnt, SEEK_CUR) < 0) {
        !           749:                                        warn("lseek");
        !           750:                                        return(-1);
        !           751:                                }
        !           752:                                st = pt;
        !           753:                                continue;
        !           754:                        }
        !           755:                        /*
        !           756:                         * drat, the buf is not zero filled
        !           757:                         */
        !           758:                        *isempt = 0;
        !           759:                }
        !           760:
        !           761:                /*
        !           762:                 * have non-zero data in this file system block, have to write
        !           763:                 */
        !           764:                if (write(fd, st, wcnt) != wcnt) {
        !           765:                        warn("write");
        !           766:                        return(-1);
        !           767:                }
        !           768:                st += wcnt;
        !           769:        }
        !           770:        return(st - str);
1.1       deraadt   771: }