Annotation of src/usr.bin/xinstall/xinstall.c, Revision 1.47
1.47 ! jsg 1: /* $OpenBSD: xinstall.c,v 1.46 2007/08/06 19:16:06 sobrado 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.
1.34 millert 16: * 3. Neither the name of the University nor the names of its contributors
1.1 deraadt 17: * may be used to endorse or promote products derived from this software
18: * without specific prior written permission.
19: *
20: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30: * SUCH DAMAGE.
31: */
32:
33: #ifndef lint
34: static char copyright[] =
35: "@(#) Copyright (c) 1987, 1993\n\
36: The Regents of the University of California. All rights reserved.\n";
37: #endif /* not lint */
38:
39: #ifndef lint
40: #if 0
41: static char sccsid[] = "@(#)xinstall.c 8.1 (Berkeley) 7/21/93";
42: #endif
1.47 ! jsg 43: static char rcsid[] = "$OpenBSD: xinstall.c,v 1.46 2007/08/06 19:16:06 sobrado Exp $";
1.1 deraadt 44: #endif /* not lint */
45:
46: #include <sys/param.h>
47: #include <sys/wait.h>
48: #include <sys/mman.h>
49: #include <sys/stat.h>
50:
51: #include <ctype.h>
1.4 millert 52: #include <err.h>
1.1 deraadt 53: #include <errno.h>
54: #include <fcntl.h>
55: #include <grp.h>
56: #include <paths.h>
57: #include <pwd.h>
58: #include <stdio.h>
59: #include <stdlib.h>
60: #include <string.h>
61: #include <unistd.h>
1.4 millert 62: #include <sysexits.h>
63: #include <utime.h>
1.1 deraadt 64:
65: #include "pathnames.h"
66:
1.19 millert 67: #define DIRECTORY 0x01 /* Tell install it's a directory. */
68: #define SETFLAGS 0x02 /* Tell install to set flags. */
69: #define NOCHANGEBITS (UF_IMMUTABLE | UF_APPEND | SF_IMMUTABLE | SF_APPEND)
70: #define BACKUP_SUFFIX ".old"
71:
1.1 deraadt 72: struct passwd *pp;
73: struct group *gp;
1.19 millert 74: int dobackup, docompare, dodir, dopreserve, dostrip, safecopy;
1.1 deraadt 75: int mode = S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH;
1.4 millert 76: char pathbuf[MAXPATHLEN], tempfile[MAXPATHLEN];
1.19 millert 77: char *suffix = BACKUP_SUFFIX;
1.1 deraadt 78: uid_t uid;
79: gid_t gid;
80:
1.31 millert 81: void copy(int, char *, int, char *, off_t, int);
82: int compare(int, const char *, size_t, int, const char *, size_t);
83: void install(char *, char *, u_long, u_int);
84: void install_dir(char *);
85: void strip(char *);
86: void usage(void);
87: int create_newfile(char *, struct stat *);
88: int create_tempfile(char *, char *, size_t);
89: int file_write(int, char *, size_t, int *, int *, int);
1.33 tedu 90: void file_flush(int, int);
1.1 deraadt 91:
92: int
1.35 deraadt 93: main(int argc, char *argv[])
1.1 deraadt 94: {
95: struct stat from_sb, to_sb;
1.41 otto 96: void *set;
1.23 mickey 97: u_int32_t fset;
1.1 deraadt 98: u_int iflags;
99: int ch, no_target;
100: char *flags, *to_name, *group = NULL, *owner = NULL;
101:
102: iflags = 0;
1.47 ! jsg 103: while ((ch = getopt(argc, argv, "B:bCcdf:g:m:o:pSs")) != -1)
1.1 deraadt 104: switch((char)ch) {
1.4 millert 105: case 'C':
106: docompare = 1;
107: break;
1.19 millert 108: case 'B':
109: suffix = optarg;
110: /* fall through; -B implies -b */
111: case 'b':
112: dobackup = 1;
113: break;
1.1 deraadt 114: case 'c':
1.4 millert 115: /* For backwards compatibility. */
1.1 deraadt 116: break;
117: case 'f':
118: flags = optarg;
1.23 mickey 119: if (strtofflags(&flags, &fset, NULL))
1.4 millert 120: errx(EX_USAGE, "%s: invalid flag", flags);
1.1 deraadt 121: iflags |= SETFLAGS;
122: break;
123: case 'g':
124: group = optarg;
125: break;
126: case 'm':
127: if (!(set = setmode(optarg)))
1.4 millert 128: errx(EX_USAGE, "%s: invalid file mode", optarg);
1.1 deraadt 129: mode = getmode(set, 0);
1.16 deraadt 130: free(set);
1.1 deraadt 131: break;
132: case 'o':
133: owner = optarg;
134: break;
1.4 millert 135: case 'p':
136: docompare = dopreserve = 1;
137: break;
138: case 'S':
139: safecopy = 1;
140: break;
1.1 deraadt 141: case 's':
142: dostrip = 1;
143: break;
144: case 'd':
145: dodir = 1;
146: break;
147: case '?':
148: default:
149: usage();
150: }
151: argc -= optind;
152: argv += optind;
153:
1.4 millert 154: /* some options make no sense when creating directories */
155: if ((safecopy || docompare || dostrip) && dodir)
1.1 deraadt 156: usage();
157:
158: /* must have at least two arguments, except when creating directories */
159: if (argc < 2 && !dodir)
160: usage();
161:
1.4 millert 162: /* need to make a temp copy so we can compare stripped version */
163: if (docompare && dostrip)
164: safecopy = 1;
165:
1.1 deraadt 166: /* get group and owner id's */
167: if (group && !(gp = getgrnam(group)) && !isdigit(*group))
1.4 millert 168: errx(EX_NOUSER, "unknown group %s", group);
169: gid = (group) ? ((gp) ? gp->gr_gid : (gid_t)strtoul(group, NULL, 10)) : (gid_t)-1;
1.1 deraadt 170: if (owner && !(pp = getpwnam(owner)) && !isdigit(*owner))
1.4 millert 171: errx(EX_NOUSER, "unknown user %s", owner);
172: uid = (owner) ? ((pp) ? pp->pw_uid : (uid_t)strtoul(owner, NULL, 10)) : (uid_t)-1;
1.1 deraadt 173:
174: if (dodir) {
175: for (; *argv != NULL; ++argv)
176: install_dir(*argv);
1.4 millert 177: exit(EX_OK);
1.1 deraadt 178: /* NOTREACHED */
179: }
180:
181: no_target = stat(to_name = argv[argc - 1], &to_sb);
182: if (!no_target && S_ISDIR(to_sb.st_mode)) {
183: for (; *argv != to_name; ++argv)
184: install(*argv, to_name, fset, iflags | DIRECTORY);
1.4 millert 185: exit(EX_OK);
186: /* NOTREACHED */
1.1 deraadt 187: }
188:
189: /* can't do file1 file2 directory/file */
190: if (argc != 2)
1.32 millert 191: errx(EX_OSERR, "Target: %s", argv[argc-1]);
1.1 deraadt 192:
193: if (!no_target) {
194: if (stat(*argv, &from_sb))
1.4 millert 195: err(EX_OSERR, "%s", *argv);
1.1 deraadt 196: if (!S_ISREG(to_sb.st_mode))
1.4 millert 197: errx(EX_OSERR, "%s: %s", to_name, strerror(EFTYPE));
1.1 deraadt 198: if (to_sb.st_dev == from_sb.st_dev &&
199: to_sb.st_ino == from_sb.st_ino)
1.4 millert 200: errx(EX_USAGE, "%s and %s are the same file", *argv, to_name);
1.1 deraadt 201: }
202: install(*argv, to_name, fset, iflags);
1.4 millert 203: exit(EX_OK);
204: /* NOTREACHED */
1.1 deraadt 205: }
206:
207: /*
208: * install --
209: * build a path name and install the file
210: */
211: void
1.35 deraadt 212: install(char *from_name, char *to_name, u_long fset, u_int flags)
1.1 deraadt 213: {
214: struct stat from_sb, to_sb;
1.4 millert 215: struct utimbuf utb;
216: int devnull, from_fd, to_fd, serrno, files_match = 0;
1.1 deraadt 217: char *p;
218:
1.4 millert 219: (void)memset((void *)&from_sb, 0, sizeof(from_sb));
220: (void)memset((void *)&to_sb, 0, sizeof(to_sb));
221:
1.1 deraadt 222: /* If try to install NULL file to a directory, fails. */
223: if (flags & DIRECTORY || strcmp(from_name, _PATH_DEVNULL)) {
224: if (stat(from_name, &from_sb))
1.4 millert 225: err(EX_OSERR, "%s", from_name);
1.1 deraadt 226: if (!S_ISREG(from_sb.st_mode))
1.4 millert 227: errx(EX_OSERR, "%s: %s", from_name, strerror(EFTYPE));
1.1 deraadt 228: /* Build the target path. */
229: if (flags & DIRECTORY) {
230: (void)snprintf(pathbuf, sizeof(pathbuf), "%s/%s",
231: to_name,
1.11 millert 232: (p = strrchr(from_name, '/')) ? ++p : from_name);
1.1 deraadt 233: to_name = pathbuf;
234: }
235: devnull = 0;
236: } else {
237: devnull = 1;
238: }
239:
1.4 millert 240: if (stat(to_name, &to_sb) == 0) {
241: /* Only compare against regular files. */
242: if (docompare && !S_ISREG(to_sb.st_mode)) {
243: docompare = 0;
244: warnx("%s: %s", to_name, strerror(EFTYPE));
245: }
246: } else if (docompare) {
247: /* File does not exist so silently ignore compare flag. */
248: docompare = 0;
249: }
250:
251: if (safecopy) {
252: to_fd = create_tempfile(to_name, tempfile, sizeof(tempfile));
253: if (to_fd < 0)
254: err(EX_OSERR, "%s", tempfile);
255: } else if (docompare && !dostrip) {
256: if ((to_fd = open(to_name, O_RDONLY, 0)) < 0)
257: err(EX_OSERR, "%s", to_name);
258: } else {
259: if ((to_fd = create_newfile(to_name, &to_sb)) < 0)
260: err(EX_OSERR, "%s", to_name);
261: }
262:
1.1 deraadt 263: if (!devnull) {
264: if ((from_fd = open(from_name, O_RDONLY, 0)) < 0) {
1.4 millert 265: serrno = errno;
266: (void)unlink(safecopy ? tempfile : to_name);
267: errx(EX_OSERR, "%s: %s", from_name, strerror(serrno));
268: }
269:
270: if (docompare && !safecopy) {
271: files_match = !(compare(from_fd, from_name,
272: (size_t)from_sb.st_size, to_fd,
273: to_name, (size_t)to_sb.st_size));
274:
275: /* Truncate "to" file for copy unless we match */
276: if (!files_match) {
277: (void)close(to_fd);
278: if ((to_fd = create_newfile(to_name, &to_sb)) < 0)
279: err(EX_OSERR, "%s", to_name);
280: }
1.1 deraadt 281: }
1.4 millert 282: if (!files_match)
283: copy(from_fd, from_name, to_fd,
1.17 millert 284: safecopy ? tempfile : to_name, from_sb.st_size,
285: ((off_t)from_sb.st_blocks * S_BLKSIZE < from_sb.st_size));
1.1 deraadt 286: }
1.2 deraadt 287:
288: if (dostrip) {
1.4 millert 289: strip(safecopy ? tempfile : to_name);
1.2 deraadt 290:
291: /*
292: * Re-open our fd on the target, in case we used a strip
293: * that does not work in-place -- like gnu binutils strip.
294: */
295: close(to_fd);
1.4 millert 296: if ((to_fd = open(safecopy ? tempfile : to_name, O_RDONLY,
297: 0)) < 0)
298: err(EX_OSERR, "stripping %s", to_name);
299: }
300:
301: /*
302: * Compare the (possibly stripped) temp file to the target.
303: */
304: if (safecopy && docompare) {
305: int temp_fd = to_fd;
306: struct stat temp_sb;
307:
308: /* Re-open to_fd using the real target name. */
309: if ((to_fd = open(to_name, O_RDONLY, 0)) < 0)
310: err(EX_OSERR, "%s", to_name);
311:
312: if (fstat(temp_fd, &temp_sb)) {
313: serrno = errno;
314: (void)unlink(tempfile);
315: errx(EX_OSERR, "%s: %s", tempfile, strerror(serrno));
316: }
317:
318: if (compare(temp_fd, tempfile, (size_t)temp_sb.st_size, to_fd,
319: to_name, (size_t)to_sb.st_size) == 0) {
320: /*
321: * If target has more than one link we need to
322: * replace it in order to snap the extra links.
323: * Need to preserve target file times, though.
324: */
325: if (to_sb.st_nlink != 1) {
326: utb.actime = to_sb.st_atime;
327: utb.modtime = to_sb.st_mtime;
328: (void)utime(tempfile, &utb);
329: } else {
330: files_match = 1;
331: (void)unlink(tempfile);
332: }
333: (void) close(temp_fd);
334: }
335: }
336:
337: /*
338: * Move the new file into place if doing a safe copy
339: * and the files are different (or just not compared).
340: */
341: if (safecopy && !files_match) {
342: /* Try to turn off the immutable bits. */
343: if (to_sb.st_flags & (NOCHANGEBITS))
344: (void)chflags(to_name, to_sb.st_flags & ~(NOCHANGEBITS));
1.19 millert 345: if (dobackup) {
346: char backup[MAXPATHLEN];
347: (void)snprintf(backup, MAXPATHLEN, "%s%s", to_name,
348: suffix);
1.28 heko 349: /* It is ok for the target file not to exist. */
350: if (rename(to_name, backup) < 0 && errno != ENOENT) {
1.19 millert 351: serrno = errno;
352: unlink(tempfile);
353: errx(EX_OSERR, "rename: %s to %s: %s", to_name,
354: backup, strerror(serrno));
355: }
356: }
1.4 millert 357: if (rename(tempfile, to_name) < 0 ) {
358: serrno = errno;
359: unlink(tempfile);
360: errx(EX_OSERR, "rename: %s to %s: %s", tempfile,
361: to_name, strerror(serrno));
362: }
363:
364: /* Re-open to_fd so we aren't hosed by the rename(2). */
365: (void) close(to_fd);
366: if ((to_fd = open(to_name, O_RDONLY, 0)) < 0)
367: err(EX_OSERR, "%s", to_name);
368: }
369:
370: /*
1.30 millert 371: * Preserve the timestamp of the source file if necessary.
1.4 millert 372: */
373: if (dopreserve && !files_match) {
374: utb.actime = from_sb.st_atime;
375: utb.modtime = from_sb.st_mtime;
376: (void)utime(to_name, &utb);
1.2 deraadt 377: }
378:
1.1 deraadt 379: /*
380: * Set owner, group, mode for target; do the chown first,
381: * chown may lose the setuid bits.
382: */
1.4 millert 383: if ((gid != (gid_t)-1 || uid != (uid_t)-1) && fchown(to_fd, uid, gid)) {
1.1 deraadt 384: serrno = errno;
385: (void)unlink(to_name);
1.4 millert 386: errx(EX_OSERR, "%s: chown/chgrp: %s", to_name, strerror(serrno));
1.1 deraadt 387: }
388: if (fchmod(to_fd, mode)) {
389: serrno = errno;
390: (void)unlink(to_name);
1.4 millert 391: errx(EX_OSERR, "%s: chmod: %s", to_name, strerror(serrno));
1.1 deraadt 392: }
393:
394: /*
395: * If provided a set of flags, set them, otherwise, preserve the
396: * flags, except for the dump flag.
397: */
398: if (fchflags(to_fd,
399: flags & SETFLAGS ? fset : from_sb.st_flags & ~UF_NODUMP)) {
1.12 millert 400: if (errno != EOPNOTSUPP || (from_sb.st_flags & ~UF_NODUMP) != 0)
401: warnx("%s: chflags: %s", to_name, strerror(errno));
1.1 deraadt 402: }
403:
404: (void)close(to_fd);
1.18 millert 405: if (!devnull)
406: (void)close(from_fd);
1.1 deraadt 407: }
408:
409: /*
410: * copy --
411: * copy from one file to another
412: */
413: void
1.35 deraadt 414: copy(int from_fd, char *from_name, int to_fd, char *to_name, off_t size,
415: int sparse)
1.1 deraadt 416: {
1.29 mpech 417: ssize_t nr, nw;
1.1 deraadt 418: int serrno;
419: char *p, buf[MAXBSIZE];
420:
1.7 millert 421: /* Rewind file descriptors. */
422: if (lseek(from_fd, (off_t)0, SEEK_SET) == (off_t)-1)
423: err(EX_OSERR, "lseek: %s", from_name);
424: if (lseek(to_fd, (off_t)0, SEEK_SET) == (off_t)-1)
425: err(EX_OSERR, "lseek: %s", to_name);
426:
1.1 deraadt 427: /*
428: * Mmap and write if less than 8M (the limit is so we don't totally
429: * trash memory on big files. This is really a minor hack, but it
1.17 millert 430: * wins some CPU back. Sparse files need special treatment.
1.1 deraadt 431: */
1.17 millert 432: if (!sparse && size <= 8 * 1048576) {
433: volatile size_t siz;
434:
1.19 millert 435: if ((p = mmap(NULL, (size_t)size, PROT_READ, MAP_PRIVATE,
1.38 grange 436: from_fd, (off_t)0)) == MAP_FAILED) {
1.6 millert 437: serrno = errno;
438: (void)unlink(to_name);
439: errx(EX_OSERR, "%s: %s", from_name, strerror(serrno));
440: }
1.39 mickey 441: if (size)
442: madvise(p, size, MADV_SEQUENTIAL);
1.3 deraadt 443: siz = (size_t)size;
1.6 millert 444: if ((nw = write(to_fd, p, siz)) != siz) {
445: serrno = errno;
446: (void)unlink(to_name);
447: errx(EX_OSERR, "%s: %s",
448: to_name, strerror(nw > 0 ? EIO : serrno));
449: }
1.4 millert 450: (void) munmap(p, (size_t)size);
1.1 deraadt 451: } else {
1.17 millert 452: int sz, rem, isem = 1;
453: struct stat sb;
454:
455: /*
456: * Pass the blocksize of the file being written to the write
457: * routine. if the size is zero, use the default S_BLKSIZE.
458: */
459: if (fstat(to_fd, &sb) != 0 || sb.st_blksize == 0)
460: sz = S_BLKSIZE;
461: else
462: sz = sb.st_blksize;
1.20 millert 463: rem = sz;
1.17 millert 464:
465: while ((nr = read(from_fd, buf, sizeof(buf))) > 0) {
466: if (sparse)
467: nw = file_write(to_fd, buf, nr, &rem, &isem, sz);
468: else
469: nw = write(to_fd, buf, nr);
470: if (nw != nr) {
1.1 deraadt 471: serrno = errno;
472: (void)unlink(to_name);
1.4 millert 473: errx(EX_OSERR, "%s: %s",
1.1 deraadt 474: to_name, strerror(nw > 0 ? EIO : serrno));
475: }
1.17 millert 476: }
1.33 tedu 477: if (sparse)
478: file_flush(to_fd, isem);
1.1 deraadt 479: if (nr != 0) {
480: serrno = errno;
481: (void)unlink(to_name);
1.4 millert 482: errx(EX_OSERR, "%s: %s", from_name, strerror(serrno));
1.1 deraadt 483: }
484: }
485: }
486:
487: /*
1.4 millert 488: * compare --
489: * compare two files; non-zero means files differ
490: */
491: int
1.35 deraadt 492: compare(int from_fd, const char *from_name, size_t from_len, int to_fd,
493: const char *to_name, size_t to_len)
1.4 millert 494: {
495: caddr_t p1, p2;
1.21 millert 496: size_t length, remainder;
497: off_t from_off, to_off;
1.4 millert 498: int dfound;
499:
500: if (from_len != to_len)
501: return(1);
502:
503: /*
504: * Compare the two files being careful not to mmap
505: * more than 8M at a time.
506: */
1.21 millert 507: from_off = to_off = (off_t)0;
1.4 millert 508: remainder = from_len;
509: do {
510: length = MIN(remainder, 8 * 1048576);
511: remainder -= length;
512:
1.22 mickey 513: if ((p1 = mmap(NULL, length, PROT_READ, MAP_PRIVATE,
1.38 grange 514: from_fd, from_off)) == MAP_FAILED)
1.4 millert 515: err(EX_OSERR, "%s", from_name);
1.22 mickey 516: if ((p2 = mmap(NULL, length, PROT_READ, MAP_PRIVATE,
1.38 grange 517: to_fd, to_off)) == MAP_FAILED)
1.4 millert 518: err(EX_OSERR, "%s", to_name);
1.39 mickey 519: if (length) {
520: madvise(p1, length, MADV_SEQUENTIAL);
521: madvise(p2, length, MADV_SEQUENTIAL);
522: }
1.4 millert 523:
524: dfound = memcmp(p1, p2, length);
525:
526: (void) munmap(p1, length);
527: (void) munmap(p2, length);
1.21 millert 528:
529: from_off += length;
530: to_off += length;
1.4 millert 531:
1.7 millert 532: } while (!dfound && remainder > 0);
1.4 millert 533:
534: return(dfound);
535: }
536:
537: /*
1.1 deraadt 538: * strip --
539: * use strip(1) to strip the target file
540: */
541: void
1.35 deraadt 542: strip(char *to_name)
1.1 deraadt 543: {
544: int serrno, status;
1.26 millert 545: char * volatile path_strip;
1.18 millert 546:
1.13 millert 547: if (issetugid() || (path_strip = getenv("STRIP")) == NULL)
548: path_strip = _PATH_STRIP;
1.1 deraadt 549:
550: switch (vfork()) {
551: case -1:
552: serrno = errno;
553: (void)unlink(to_name);
1.4 millert 554: errx(EX_TEMPFAIL, "forks: %s", strerror(serrno));
1.1 deraadt 555: case 0:
1.44 moritz 556: execl(path_strip, "strip", "--", to_name, (char *)NULL);
1.13 millert 557: warn("%s", path_strip);
1.9 deraadt 558: _exit(EX_OSERR);
1.1 deraadt 559: default:
1.14 millert 560: if (wait(&status) == -1 || !WIFEXITED(status))
1.1 deraadt 561: (void)unlink(to_name);
562: }
563: }
564:
565: /*
566: * install_dir --
1.42 jsg 567: * build directory hierarchy
1.1 deraadt 568: */
569: void
1.35 deraadt 570: install_dir(char *path)
1.1 deraadt 571: {
1.29 mpech 572: char *p;
1.8 imp 573: struct stat sb;
574: int ch;
575:
576: for (p = path;; ++p)
577: if (!*p || (p != path && *p == '/')) {
578: ch = *p;
579: *p = '\0';
580: if (stat(path, &sb)) {
581: if (errno != ENOENT || mkdir(path, 0777) < 0) {
1.4 millert 582: err(EX_OSERR, "%s", path);
1.1 deraadt 583: /* NOTREACHED */
1.8 imp 584: }
585: }
586: if (!(*p = ch))
1.1 deraadt 587: break;
1.8 imp 588: }
1.1 deraadt 589:
1.4 millert 590: if (((gid != (gid_t)-1 || uid != (uid_t)-1) && chown(path, uid, gid)) ||
1.8 imp 591: chmod(path, mode)) {
592: warn("%s", path);
593: }
1.1 deraadt 594: }
595:
596: /*
597: * usage --
598: * print a usage message and die
599: */
600: void
1.35 deraadt 601: usage(void)
1.1 deraadt 602: {
603: (void)fprintf(stderr, "\
1.46 sobrado 604: usage: install [-bCcdpSs] [-B suffix] [-f flags] [-g group] [-m mode] [-o owner]\n source ... target ...\n");
1.4 millert 605: exit(EX_USAGE);
606: /* NOTREACHED */
607: }
608:
609: /*
610: * create_tempfile --
611: * create a temporary file based on path and open it
612: */
613: int
1.35 deraadt 614: create_tempfile(char *path, char *temp, size_t tsize)
1.4 millert 615: {
616: char *p;
617:
1.43 millert 618: strlcpy(temp, path, tsize);
619: if ((p = strrchr(temp, '/')) != NULL)
1.4 millert 620: p++;
621: else
622: p = temp;
1.43 millert 623: *p = '\0';
624: strlcat(p, "INS@XXXXXXXXXX", tsize);
1.4 millert 625:
626: return(mkstemp(temp));
627: }
628:
629: /*
630: * create_newfile --
1.30 millert 631: * create a new file, overwriting an existing one if necessary
1.4 millert 632: */
633: int
1.35 deraadt 634: create_newfile(char *path, struct stat *sbp)
1.4 millert 635: {
1.19 millert 636: char backup[MAXPATHLEN];
637:
1.4 millert 638: /*
639: * Unlink now... avoid ETXTBSY errors later. Try and turn
640: * off the append/immutable bits -- if we fail, go ahead,
641: * it might work.
642: */
643: if (sbp->st_flags & (NOCHANGEBITS))
644: (void)chflags(path, sbp->st_flags & ~(NOCHANGEBITS));
645:
1.19 millert 646: if (dobackup) {
647: (void)snprintf(backup, MAXPATHLEN, "%s%s", path, suffix);
1.28 heko 648: /* It is ok for the target file not to exist. */
649: if (rename(path, backup) < 0 && errno != ENOENT)
650: err(EX_OSERR, "rename: %s to %s (errno %d)", path, backup, errno);
1.19 millert 651: } else
652: (void)unlink(path);
1.4 millert 653:
654: return(open(path, O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR));
1.17 millert 655: }
656:
657: /*
658: * file_write()
659: * Write/copy a file (during copy or archive extract). This routine knows
660: * how to copy files with lseek holes in it. (Which are read as file
661: * blocks containing all 0's but do not have any file blocks associated
662: * with the data). Typical examples of these are files created by dbm
663: * variants (.pag files). While the file size of these files are huge, the
664: * actual storage is quite small (the files are sparse). The problem is
665: * the holes read as all zeros so are probably stored on the archive that
666: * way (there is no way to determine if the file block is really a hole,
667: * we only know that a file block of all zero's can be a hole).
668: * At this writing, no major archive format knows how to archive files
669: * with holes. However, on extraction (or during copy, -rw) we have to
670: * deal with these files. Without detecting the holes, the files can
671: * consume a lot of file space if just written to disk. This replacement
672: * for write when passed the basic allocation size of a file system block,
673: * uses lseek whenever it detects the input data is all 0 within that
674: * file block. In more detail, the strategy is as follows:
675: * While the input is all zero keep doing an lseek. Keep track of when we
1.45 krw 676: * pass over file block boundaries. Only write when we hit a non zero
1.17 millert 677: * input. once we have written a file block, we continue to write it to
678: * the end (we stop looking at the input). When we reach the start of the
679: * next file block, start checking for zero blocks again. Working on file
1.45 krw 680: * block boundaries significantly reduces the overhead when copying files
1.17 millert 681: * that are NOT very sparse. This overhead (when compared to a write) is
682: * almost below the measurement resolution on many systems. Without it,
683: * files with holes cannot be safely copied. It does has a side effect as
684: * it can put holes into files that did not have them before, but that is
685: * not a problem since the file contents are unchanged (in fact it saves
686: * file space). (Except on paging files for diskless clients. But since we
687: * cannot determine one of those file from here, we ignore them). If this
688: * ever ends up on a system where CTG files are supported and the holes
689: * are not desired, just do a conditional test in those routines that
690: * call file_write() and have it call write() instead. BEFORE CLOSING THE
691: * FILE, make sure to call file_flush() when the last write finishes with
692: * an empty block. A lot of file systems will not create an lseek hole at
693: * the end. In this case we drop a single 0 at the end to force the
694: * trailing 0's in the file.
695: * ---Parameters---
696: * rem: how many bytes left in this file system block
697: * isempt: have we written to the file block yet (is it empty)
698: * sz: basic file block allocation size
699: * cnt: number of bytes on this write
700: * str: buffer to write
701: * Return:
702: * number of bytes written, -1 on write (or lseek) error.
703: */
704:
705: int
1.35 deraadt 706: file_write(int fd, char *str, size_t cnt, int *rem, int *isempt, int sz)
1.17 millert 707: {
1.29 mpech 708: char *pt;
709: char *end;
710: size_t wcnt;
711: char *st = str;
1.17 millert 712:
713: /*
714: * while we have data to process
715: */
716: while (cnt) {
717: if (!*rem) {
718: /*
719: * We are now at the start of file system block again
720: * (or what we think one is...). start looking for
721: * empty blocks again
722: */
723: *isempt = 1;
724: *rem = sz;
725: }
726:
727: /*
728: * only examine up to the end of the current file block or
729: * remaining characters to write, whatever is smaller
730: */
731: wcnt = MIN(cnt, *rem);
732: cnt -= wcnt;
733: *rem -= wcnt;
734: if (*isempt) {
735: /*
736: * have not written to this block yet, so we keep
737: * looking for zero's
738: */
739: pt = st;
740: end = st + wcnt;
741:
742: /*
743: * look for a zero filled buffer
744: */
745: while ((pt < end) && (*pt == '\0'))
746: ++pt;
747:
748: if (pt == end) {
749: /*
750: * skip, buf is empty so far
751: */
752: if (lseek(fd, (off_t)wcnt, SEEK_CUR) < 0) {
753: warn("lseek");
754: return(-1);
755: }
756: st = pt;
757: continue;
758: }
759: /*
760: * drat, the buf is not zero filled
761: */
762: *isempt = 0;
763: }
764:
765: /*
766: * have non-zero data in this file system block, have to write
767: */
768: if (write(fd, st, wcnt) != wcnt) {
769: warn("write");
770: return(-1);
771: }
772: st += wcnt;
773: }
774: return(st - str);
1.33 tedu 775: }
776:
777: /*
778: * file_flush()
779: * when the last file block in a file is zero, many file systems will not
780: * let us create a hole at the end. To get the last block with zeros, we
781: * write the last BYTE with a zero (back up one byte and write a zero).
782: */
783: void
784: file_flush(int fd, int isempt)
785: {
786: static char blnk[] = "\0";
787:
788: /*
789: * silly test, but make sure we are only called when the last block is
790: * filled with all zeros.
791: */
792: if (!isempt)
793: return;
794:
795: /*
796: * move back one byte and write a zero
797: */
798: if (lseek(fd, (off_t)-1, SEEK_CUR) < 0) {
799: warn("Failed seek on file");
800: return;
801: }
802:
803: if (write(fd, blnk, 1) < 0)
804: warn("Failed write to file");
805: return;
1.1 deraadt 806: }