1 /* $OpenBSD: xinstall.c,v 1.65 2016/05/13 17:51:15 jmc Exp $ */
2 /* $NetBSD: xinstall.c,v 1.9 1995/12/20 10:25:17 jonathan Exp $ */
5 * Copyright (c) 1987, 1993
6 * The Regents of the University of California. All rights reserved.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
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. Neither the name of the University nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
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
33 #include <sys/param.h> /* MAXBSIZE */
53 #include "pathnames.h"
56 #define MINIMUM(a, b) (((a) < (b)) ? (a) : (b))
58 #define DIRECTORY 0x01 /* Tell install it's a directory. */
59 #define SETFLAGS 0x02 /* Tell install to set flags. */
60 #define USEFSYNC 0x04 /* Tell install to use fsync(2). */
61 #define NOCHANGEBITS (UF_IMMUTABLE | UF_APPEND | SF_IMMUTABLE | SF_APPEND)
62 #define BACKUP_SUFFIX ".old"
66 int dobackup
, docompare
, dodest
, dodir
, dopreserve
, dostrip
, safecopy
;
67 int mode
= S_IRWXU
|S_IRGRP
|S_IXGRP
|S_IROTH
|S_IXOTH
;
68 char pathbuf
[PATH_MAX
], tempfile
[PATH_MAX
];
69 char *suffix
= BACKUP_SUFFIX
;
73 void copy(int, char *, int, char *, off_t
, int);
74 int compare(int, const char *, off_t
, int, const char *, off_t
);
75 void install(char *, char *, u_long
, u_int
);
76 void install_dir(char *, int);
79 int create_newfile(char *, struct stat
*);
80 int create_tempfile(char *, char *, size_t);
81 int file_write(int, char *, size_t, int *, int *, int);
82 void file_flush(int, int);
85 main(int argc
, char *argv
[])
87 struct stat from_sb
, to_sb
;
92 char *flags
, *to_name
, *group
= NULL
, *owner
= NULL
;
95 while ((ch
= getopt(argc
, argv
, "B:bCcDdFf:g:m:o:pSs")) != -1)
102 /* fall through; -B implies -b */
107 /* For backwards compatibility. */
116 mode
= strtol(optarg
, NULL
, 8);
122 docompare
= dopreserve
= 1;
143 /* some options make no sense when creating directories */
144 if ((safecopy
|| docompare
|| dostrip
) && dodir
)
147 /* must have at least two arguments, except when creating directories */
148 if (argc
< 2 && !dodir
)
151 /* need to make a temp copy so we can compare stripped version */
152 if (docompare
&& dostrip
)
155 /* get group and owner id's */
156 if (group
&& !(gp
= getgrnam(group
)) && !isdigit((unsigned char)*group
))
157 errx(1, "unknown group %s", group
);
158 gid
= (group
) ? ((gp
) ? gp
->gr_gid
: (gid_t
)strtoul(group
, NULL
, 10)) : (gid_t
)-1;
159 if (owner
&& !(pp
= getpwnam(owner
)) && !isdigit((unsigned char)*owner
))
160 errx(1, "unknown user %s", owner
);
161 uid
= (owner
) ? ((pp
) ? pp
->pw_uid
: (uid_t
)strtoul(owner
, NULL
, 10)) : (uid_t
)-1;
164 for (; *argv
!= NULL
; ++argv
)
165 install_dir(*argv
, mode
);
171 char *dest
= dirname(argv
[argc
- 1]);
173 errx(1, "cannot determine dirname");
175 * When -D is passed, do not chmod the directory with the mode set for
176 * the target file. If more restrictive permissions are required then
177 * '-d -m' ought to be used instead.
179 install_dir(dest
, 0755);
182 no_target
= stat(to_name
= argv
[argc
- 1], &to_sb
);
183 if (!no_target
&& S_ISDIR(to_sb
.st_mode
)) {
184 for (; *argv
!= to_name
; ++argv
)
185 install(*argv
, to_name
, fset
, iflags
| DIRECTORY
);
190 /* can't do file1 file2 directory/file */
192 errx(1, "Target: %s", argv
[argc
-1]);
195 if (stat(*argv
, &from_sb
))
197 if (!S_ISREG(to_sb
.st_mode
))
198 errc(1, EFTYPE
, "%s", to_name
);
199 if (to_sb
.st_dev
== from_sb
.st_dev
&&
200 to_sb
.st_ino
== from_sb
.st_ino
)
201 errx(1, "%s and %s are the same file", *argv
, to_name
);
203 install(*argv
, to_name
, fset
, iflags
);
210 * build a path name and install the file
213 install(char *from_name
, char *to_name
, u_long fset
, u_int flags
)
215 struct stat from_sb
, to_sb
;
216 struct timespec ts
[2];
217 int devnull
, from_fd
, to_fd
, serrno
, files_match
= 0;
220 (void)memset(&from_sb
, 0, sizeof(from_sb
));
221 (void)memset(&to_sb
, 0, sizeof(to_sb
));
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
))
226 err(1, "%s", from_name
);
227 if (!S_ISREG(from_sb
.st_mode
))
228 errc(1, EFTYPE
, "%s", from_name
);
229 /* Build the target path. */
230 if (flags
& DIRECTORY
) {
231 (void)snprintf(pathbuf
, sizeof(pathbuf
), "%s/%s",
233 (p
= strrchr(from_name
, '/')) ? ++p
: from_name
);
241 if (stat(to_name
, &to_sb
) == 0) {
242 /* Only compare against regular files. */
243 if (docompare
&& !S_ISREG(to_sb
.st_mode
)) {
245 warnc(EFTYPE
, "%s", to_name
);
247 } else if (docompare
) {
248 /* File does not exist so silently ignore compare flag. */
253 if ((from_fd
= open(from_name
, O_RDONLY
, 0)) < 0)
254 err(1, "%s", from_name
);
258 to_fd
= create_tempfile(to_name
, tempfile
, sizeof(tempfile
));
260 err(1, "%s", tempfile
);
261 } else if (docompare
&& !dostrip
) {
262 if ((to_fd
= open(to_name
, O_RDONLY
, 0)) < 0)
263 err(1, "%s", to_name
);
265 if ((to_fd
= create_newfile(to_name
, &to_sb
)) < 0)
266 err(1, "%s", to_name
);
270 if (docompare
&& !safecopy
) {
271 files_match
= !(compare(from_fd
, from_name
,
272 from_sb
.st_size
, to_fd
,
273 to_name
, to_sb
.st_size
));
275 /* Truncate "to" file for copy unless we match */
278 if ((to_fd
= create_newfile(to_name
, &to_sb
)) < 0)
279 err(1, "%s", to_name
);
283 copy(from_fd
, from_name
, to_fd
,
284 safecopy
? tempfile
: to_name
, from_sb
.st_size
,
285 ((off_t
)from_sb
.st_blocks
* S_BLKSIZE
< from_sb
.st_size
));
289 strip(safecopy
? tempfile
: to_name
);
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.
296 if ((to_fd
= open(safecopy
? tempfile
: to_name
, O_RDONLY
,
298 err(1, "stripping %s", to_name
);
302 * Compare the (possibly stripped) temp file to the target.
304 if (safecopy
&& docompare
) {
308 /* Re-open to_fd using the real target name. */
309 if ((to_fd
= open(to_name
, O_RDONLY
, 0)) < 0)
310 err(1, "%s", to_name
);
312 if (fstat(temp_fd
, &temp_sb
)) {
314 (void)unlink(tempfile
);
315 errc(1, serrno
, "%s", tempfile
);
318 if (compare(temp_fd
, tempfile
, temp_sb
.st_size
, to_fd
,
319 to_name
, to_sb
.st_size
) == 0) {
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.
325 if (to_sb
.st_nlink
!= 1) {
326 ts
[0] = to_sb
.st_atim
;
327 ts
[1] = to_sb
.st_mtim
;
328 futimens(temp_fd
, ts
);
331 (void)unlink(tempfile
);
339 * Preserve the timestamp of the source file if necessary.
341 if (dopreserve
&& !files_match
) {
342 ts
[0] = from_sb
.st_atim
;
343 ts
[1] = from_sb
.st_mtim
;
348 * Set owner, group, mode for target; do the chown first,
349 * chown may lose the setuid bits.
351 if ((gid
!= (gid_t
)-1 || uid
!= (uid_t
)-1) &&
352 fchown(to_fd
, uid
, gid
)) {
354 (void)unlink(safecopy
? tempfile
: to_name
);
355 errx(1, "%s: chown/chgrp: %s",
356 safecopy
? tempfile
: to_name
, strerror(serrno
));
358 if (fchmod(to_fd
, mode
)) {
360 (void)unlink(safecopy
? tempfile
: to_name
);
361 errx(1, "%s: chmod: %s", safecopy
? tempfile
: to_name
,
365 if (flags
& USEFSYNC
)
369 (void)close(from_fd
);
372 * Move the new file into place if doing a safe copy
373 * and the files are different (or just not compared).
375 if (safecopy
&& !files_match
) {
377 char backup
[PATH_MAX
];
378 (void)snprintf(backup
, PATH_MAX
, "%s%s", to_name
,
380 /* It is ok for the target file not to exist. */
381 if (rename(to_name
, backup
) < 0 && errno
!= ENOENT
) {
384 errx(1, "rename: %s to %s: %s", to_name
,
385 backup
, strerror(serrno
));
388 if (rename(tempfile
, to_name
) < 0 ) {
391 errx(1, "rename: %s to %s: %s", tempfile
,
392 to_name
, strerror(serrno
));
399 * copy from one file to another
402 copy(int from_fd
, char *from_name
, int to_fd
, char *to_name
, off_t size
,
407 char *p
, buf
[MAXBSIZE
];
412 /* Rewind file descriptors. */
413 if (lseek(from_fd
, (off_t
)0, SEEK_SET
) == (off_t
)-1)
414 err(1, "lseek: %s", from_name
);
415 if (lseek(to_fd
, (off_t
)0, SEEK_SET
) == (off_t
)-1)
416 err(1, "lseek: %s", to_name
);
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
421 * wins some CPU back. Sparse files need special treatment.
423 if (!sparse
&& size
<= 8 * 1048576) {
426 if ((p
= mmap(NULL
, (size_t)size
, PROT_READ
, MAP_PRIVATE
,
427 from_fd
, (off_t
)0)) == MAP_FAILED
) {
429 (void)unlink(to_name
);
430 errc(1, serrno
, "%s", from_name
);
432 madvise(p
, size
, MADV_SEQUENTIAL
);
434 if ((nw
= write(to_fd
, p
, siz
)) != siz
) {
436 (void)unlink(to_name
);
438 to_name
, strerror(nw
> 0 ? EIO
: serrno
));
440 (void) munmap(p
, (size_t)size
);
442 int sz
, rem
, isem
= 1;
446 * Pass the blocksize of the file being written to the write
447 * routine. if the size is zero, use the default S_BLKSIZE.
449 if (fstat(to_fd
, &sb
) != 0 || sb
.st_blksize
== 0)
455 while ((nr
= read(from_fd
, buf
, sizeof(buf
))) > 0) {
457 nw
= file_write(to_fd
, buf
, nr
, &rem
, &isem
, sz
);
459 nw
= write(to_fd
, buf
, nr
);
462 (void)unlink(to_name
);
464 to_name
, strerror(nw
> 0 ? EIO
: serrno
));
468 file_flush(to_fd
, isem
);
471 (void)unlink(to_name
);
472 errc(1, serrno
, "%s", from_name
);
479 * compare two files; non-zero means files differ
482 compare(int from_fd
, const char *from_name
, off_t from_len
, int to_fd
,
483 const char *to_name
, off_t to_len
)
487 off_t from_off
, to_off
, remainder
;
490 if (from_len
== 0 && from_len
== to_len
)
493 if (from_len
!= to_len
)
497 * Compare the two files being careful not to mmap
498 * more than 8M at a time.
500 from_off
= to_off
= (off_t
)0;
501 remainder
= from_len
;
503 length
= MINIMUM(remainder
, 8 * 1048576);
506 if ((p1
= mmap(NULL
, length
, PROT_READ
, MAP_PRIVATE
,
507 from_fd
, from_off
)) == MAP_FAILED
)
508 err(1, "%s", from_name
);
509 if ((p2
= mmap(NULL
, length
, PROT_READ
, MAP_PRIVATE
,
510 to_fd
, to_off
)) == MAP_FAILED
)
511 err(1, "%s", to_name
);
513 madvise(p1
, length
, MADV_SEQUENTIAL
);
514 madvise(p2
, length
, MADV_SEQUENTIAL
);
517 dfound
= memcmp(p1
, p2
, length
);
519 (void) munmap(p1
, length
);
520 (void) munmap(p2
, length
);
525 } while (!dfound
&& remainder
> 0);
532 * use strip(1) to strip the target file
538 char * volatile path_strip
;
540 if (issetugid() || (path_strip
= getenv("STRIP")) == NULL
)
541 path_strip
= _PATH_STRIP
;
546 (void)unlink(to_name
);
547 errc(1, serrno
, "forks");
549 execl(path_strip
, "strip", "--", to_name
, (char *)NULL
);
550 warn("%s", path_strip
);
553 if (wait(&status
) == -1 || !WIFEXITED(status
))
554 (void)unlink(to_name
);
560 * build directory hierarchy
563 install_dir(char *path
, int mode
)
570 if (!*p
|| (p
!= path
&& *p
== '/')) {
573 if (mkdir(path
, 0777)) {
574 int mkdir_errno
= errno
;
575 if (stat(path
, &sb
)) {
576 /* Not there; use mkdir()s errno */
577 errc(1, mkdir_errno
, "%s",
581 if (!S_ISDIR(sb
.st_mode
)) {
582 /* Is there, but isn't a directory */
583 errc(1, ENOTDIR
, "%s", path
);
591 if (((gid
!= (gid_t
)-1 || uid
!= (uid_t
)-1) && chown(path
, uid
, gid
)) ||
599 * print a usage message and die
604 (void)fprintf(stderr
, "\
605 usage: install [-bCcDdFpSs] [-B suffix] [-f flags] [-g group] [-m mode] [-o owner]\n source ... target ...\n");
612 * create a temporary file based on path and open it
615 create_tempfile(char *path
, char *temp
, size_t tsize
)
619 strlcpy(temp
, path
, tsize
);
620 if ((p
= strrchr(temp
, '/')) != NULL
)
625 strlcat(p
, "INS@XXXXXXXXXX", tsize
);
627 return(mkstemp(temp
));
632 * create a new file, overwriting an existing one if necessary
635 create_newfile(char *path
, struct stat
*sbp
)
637 char backup
[PATH_MAX
];
640 (void)snprintf(backup
, PATH_MAX
, "%s%s", path
, suffix
);
641 /* It is ok for the target file not to exist. */
642 if (rename(path
, backup
) < 0 && errno
!= ENOENT
)
643 err(1, "rename: %s to %s (errno %d)", path
, backup
, errno
);
645 if (unlink(path
) < 0 && errno
!= ENOENT
)
649 return(open(path
, O_CREAT
| O_RDWR
| O_EXCL
, S_IRUSR
| S_IWUSR
));
654 * Write/copy a file (during copy or archive extract). This routine knows
655 * how to copy files with lseek holes in it. (Which are read as file
656 * blocks containing all 0's but do not have any file blocks associated
657 * with the data). Typical examples of these are files created by dbm
658 * variants (.pag files). While the file size of these files are huge, the
659 * actual storage is quite small (the files are sparse). The problem is
660 * the holes read as all zeros so are probably stored on the archive that
661 * way (there is no way to determine if the file block is really a hole,
662 * we only know that a file block of all zero's can be a hole).
663 * At this writing, no major archive format knows how to archive files
664 * with holes. However, on extraction (or during copy, -rw) we have to
665 * deal with these files. Without detecting the holes, the files can
666 * consume a lot of file space if just written to disk. This replacement
667 * for write when passed the basic allocation size of a file system block,
668 * uses lseek whenever it detects the input data is all 0 within that
669 * file block. In more detail, the strategy is as follows:
670 * While the input is all zero keep doing an lseek. Keep track of when we
671 * pass over file block boundaries. Only write when we hit a non zero
672 * input. once we have written a file block, we continue to write it to
673 * the end (we stop looking at the input). When we reach the start of the
674 * next file block, start checking for zero blocks again. Working on file
675 * block boundaries significantly reduces the overhead when copying files
676 * that are NOT very sparse. This overhead (when compared to a write) is
677 * almost below the measurement resolution on many systems. Without it,
678 * files with holes cannot be safely copied. It does has a side effect as
679 * it can put holes into files that did not have them before, but that is
680 * not a problem since the file contents are unchanged (in fact it saves
681 * file space). (Except on paging files for diskless clients. But since we
682 * cannot determine one of those file from here, we ignore them). If this
683 * ever ends up on a system where CTG files are supported and the holes
684 * are not desired, just do a conditional test in those routines that
685 * call file_write() and have it call write() instead. BEFORE CLOSING THE
686 * FILE, make sure to call file_flush() when the last write finishes with
687 * an empty block. A lot of file systems will not create an lseek hole at
688 * the end. In this case we drop a single 0 at the end to force the
689 * trailing 0's in the file.
691 * rem: how many bytes left in this file system block
692 * isempt: have we written to the file block yet (is it empty)
693 * sz: basic file block allocation size
694 * cnt: number of bytes on this write
695 * str: buffer to write
697 * number of bytes written, -1 on write (or lseek) error.
701 file_write(int fd
, char *str
, size_t cnt
, int *rem
, int *isempt
, int sz
)
709 * while we have data to process
714 * We are now at the start of file system block again
715 * (or what we think one is...). start looking for
723 * only examine up to the end of the current file block or
724 * remaining characters to write, whatever is smaller
726 wcnt
= MINIMUM(cnt
, *rem
);
731 * have not written to this block yet, so we keep
738 * look for a zero filled buffer
740 while ((pt
< end
) && (*pt
== '\0'))
745 * skip, buf is empty so far
747 if (lseek(fd
, (off_t
)wcnt
, SEEK_CUR
) < 0) {
755 * drat, the buf is not zero filled
761 * have non-zero data in this file system block, have to write
763 if (write(fd
, st
, wcnt
) != wcnt
) {
774 * when the last file block in a file is zero, many file systems will not
775 * let us create a hole at the end. To get the last block with zeros, we
776 * write the last BYTE with a zero (back up one byte and write a zero).
779 file_flush(int fd
, int isempt
)
781 static char blnk
[] = "\0";
784 * silly test, but make sure we are only called when the last block is
785 * filled with all zeros.
791 * move back one byte and write a zero
793 if (lseek(fd
, (off_t
)-1, SEEK_CUR
) < 0) {
794 warn("Failed seek on file");
798 if (write(fd
, blnk
, 1) < 0)
799 warn("Failed write to file");