version 1.62, 2015/07/19 18:27:26 |
version 1.63, 2015/12/31 16:16:54 |
|
|
#include <string.h> |
#include <string.h> |
#include <unistd.h> |
#include <unistd.h> |
#include <limits.h> |
#include <limits.h> |
#include <sysexits.h> |
|
#include <utime.h> |
#include <utime.h> |
#include <libgen.h> |
#include <libgen.h> |
|
|
|
|
case 'f': |
case 'f': |
flags = optarg; |
flags = optarg; |
if (strtofflags(&flags, &fset, NULL)) |
if (strtofflags(&flags, &fset, NULL)) |
errx(EX_USAGE, "%s: invalid flag", flags); |
errx(1, "%s: invalid flag", flags); |
iflags |= SETFLAGS; |
iflags |= SETFLAGS; |
break; |
break; |
case 'g': |
case 'g': |
|
|
break; |
break; |
case 'm': |
case 'm': |
if (!(set = setmode(optarg))) |
if (!(set = setmode(optarg))) |
errx(EX_USAGE, "%s: invalid file mode", optarg); |
errx(1, "%s: invalid file mode", optarg); |
mode = getmode(set, 0); |
mode = getmode(set, 0); |
free(set); |
free(set); |
break; |
break; |
|
|
|
|
/* get group and owner id's */ |
/* get group and owner id's */ |
if (group && !(gp = getgrnam(group)) && !isdigit((unsigned char)*group)) |
if (group && !(gp = getgrnam(group)) && !isdigit((unsigned char)*group)) |
errx(EX_NOUSER, "unknown group %s", group); |
errx(1, "unknown group %s", group); |
gid = (group) ? ((gp) ? gp->gr_gid : (gid_t)strtoul(group, NULL, 10)) : (gid_t)-1; |
gid = (group) ? ((gp) ? gp->gr_gid : (gid_t)strtoul(group, NULL, 10)) : (gid_t)-1; |
if (owner && !(pp = getpwnam(owner)) && !isdigit((unsigned char)*owner)) |
if (owner && !(pp = getpwnam(owner)) && !isdigit((unsigned char)*owner)) |
errx(EX_NOUSER, "unknown user %s", owner); |
errx(1, "unknown user %s", owner); |
uid = (owner) ? ((pp) ? pp->pw_uid : (uid_t)strtoul(owner, NULL, 10)) : (uid_t)-1; |
uid = (owner) ? ((pp) ? pp->pw_uid : (uid_t)strtoul(owner, NULL, 10)) : (uid_t)-1; |
|
|
if (dodir) { |
if (dodir) { |
for (; *argv != NULL; ++argv) |
for (; *argv != NULL; ++argv) |
install_dir(*argv, mode); |
install_dir(*argv, mode); |
exit(EX_OK); |
exit(0); |
/* NOTREACHED */ |
/* NOTREACHED */ |
} |
} |
|
|
if (dodest) { |
if (dodest) { |
char *dest = dirname(argv[argc - 1]); |
char *dest = dirname(argv[argc - 1]); |
if (dest == NULL) |
if (dest == NULL) |
errx(EX_OSERR, "cannot determine dirname"); |
errx(1, "cannot determine dirname"); |
/* |
/* |
* When -D is passed, do not chmod the directory with the mode set for |
* When -D is passed, do not chmod the directory with the mode set for |
* the target file. If more restrictive permissions are required then |
* the target file. If more restrictive permissions are required then |
|
|
if (!no_target && S_ISDIR(to_sb.st_mode)) { |
if (!no_target && S_ISDIR(to_sb.st_mode)) { |
for (; *argv != to_name; ++argv) |
for (; *argv != to_name; ++argv) |
install(*argv, to_name, fset, iflags | DIRECTORY); |
install(*argv, to_name, fset, iflags | DIRECTORY); |
exit(EX_OK); |
exit(0); |
/* NOTREACHED */ |
/* NOTREACHED */ |
} |
} |
|
|
/* can't do file1 file2 directory/file */ |
/* can't do file1 file2 directory/file */ |
if (argc != 2) |
if (argc != 2) |
errx(EX_OSERR, "Target: %s", argv[argc-1]); |
errx(1, "Target: %s", argv[argc-1]); |
|
|
if (!no_target) { |
if (!no_target) { |
if (stat(*argv, &from_sb)) |
if (stat(*argv, &from_sb)) |
err(EX_OSERR, "%s", *argv); |
err(1, "%s", *argv); |
if (!S_ISREG(to_sb.st_mode)) |
if (!S_ISREG(to_sb.st_mode)) |
errc(EX_OSERR, EFTYPE, "%s", to_name); |
errc(1, EFTYPE, "%s", to_name); |
if (to_sb.st_dev == from_sb.st_dev && |
if (to_sb.st_dev == from_sb.st_dev && |
to_sb.st_ino == from_sb.st_ino) |
to_sb.st_ino == from_sb.st_ino) |
errx(EX_USAGE, "%s and %s are the same file", *argv, to_name); |
errx(1, "%s and %s are the same file", *argv, to_name); |
} |
} |
install(*argv, to_name, fset, iflags); |
install(*argv, to_name, fset, iflags); |
exit(EX_OK); |
exit(0); |
/* NOTREACHED */ |
/* NOTREACHED */ |
} |
} |
|
|
|
|
/* If try to install NULL file to a directory, fails. */ |
/* If try to install NULL file to a directory, fails. */ |
if (flags & DIRECTORY || strcmp(from_name, _PATH_DEVNULL)) { |
if (flags & DIRECTORY || strcmp(from_name, _PATH_DEVNULL)) { |
if (stat(from_name, &from_sb)) |
if (stat(from_name, &from_sb)) |
err(EX_OSERR, "%s", from_name); |
err(1, "%s", from_name); |
if (!S_ISREG(from_sb.st_mode)) |
if (!S_ISREG(from_sb.st_mode)) |
errc(EX_OSERR, EFTYPE, "%s", from_name); |
errc(1, EFTYPE, "%s", from_name); |
/* Build the target path. */ |
/* Build the target path. */ |
if (flags & DIRECTORY) { |
if (flags & DIRECTORY) { |
(void)snprintf(pathbuf, sizeof(pathbuf), "%s/%s", |
(void)snprintf(pathbuf, sizeof(pathbuf), "%s/%s", |
|
|
|
|
if (!devnull) { |
if (!devnull) { |
if ((from_fd = open(from_name, O_RDONLY, 0)) < 0) |
if ((from_fd = open(from_name, O_RDONLY, 0)) < 0) |
err(EX_OSERR, "%s", from_name); |
err(1, "%s", from_name); |
} |
} |
|
|
if (safecopy) { |
if (safecopy) { |
to_fd = create_tempfile(to_name, tempfile, sizeof(tempfile)); |
to_fd = create_tempfile(to_name, tempfile, sizeof(tempfile)); |
if (to_fd < 0) |
if (to_fd < 0) |
err(EX_OSERR, "%s", tempfile); |
err(1, "%s", tempfile); |
} else if (docompare && !dostrip) { |
} else if (docompare && !dostrip) { |
if ((to_fd = open(to_name, O_RDONLY, 0)) < 0) |
if ((to_fd = open(to_name, O_RDONLY, 0)) < 0) |
err(EX_OSERR, "%s", to_name); |
err(1, "%s", to_name); |
} else { |
} else { |
if ((to_fd = create_newfile(to_name, &to_sb)) < 0) |
if ((to_fd = create_newfile(to_name, &to_sb)) < 0) |
err(EX_OSERR, "%s", to_name); |
err(1, "%s", to_name); |
} |
} |
|
|
if (!devnull) { |
if (!devnull) { |
|
|
if (!files_match) { |
if (!files_match) { |
(void)close(to_fd); |
(void)close(to_fd); |
if ((to_fd = create_newfile(to_name, &to_sb)) < 0) |
if ((to_fd = create_newfile(to_name, &to_sb)) < 0) |
err(EX_OSERR, "%s", to_name); |
err(1, "%s", to_name); |
} |
} |
} |
} |
if (!files_match) |
if (!files_match) |
|
|
close(to_fd); |
close(to_fd); |
if ((to_fd = open(safecopy ? tempfile : to_name, O_RDONLY, |
if ((to_fd = open(safecopy ? tempfile : to_name, O_RDONLY, |
0)) < 0) |
0)) < 0) |
err(EX_OSERR, "stripping %s", to_name); |
err(1, "stripping %s", to_name); |
} |
} |
|
|
/* |
/* |
|
|
|
|
/* Re-open to_fd using the real target name. */ |
/* Re-open to_fd using the real target name. */ |
if ((to_fd = open(to_name, O_RDONLY, 0)) < 0) |
if ((to_fd = open(to_name, O_RDONLY, 0)) < 0) |
err(EX_OSERR, "%s", to_name); |
err(1, "%s", to_name); |
|
|
if (fstat(temp_fd, &temp_sb)) { |
if (fstat(temp_fd, &temp_sb)) { |
serrno = errno; |
serrno = errno; |
(void)unlink(tempfile); |
(void)unlink(tempfile); |
errc(EX_OSERR, serrno, "%s", tempfile); |
errc(1, serrno, "%s", tempfile); |
} |
} |
|
|
if (compare(temp_fd, tempfile, temp_sb.st_size, to_fd, |
if (compare(temp_fd, tempfile, temp_sb.st_size, to_fd, |
|
|
fchown(to_fd, uid, gid)) { |
fchown(to_fd, uid, gid)) { |
serrno = errno; |
serrno = errno; |
(void)unlink(safecopy ? tempfile : to_name); |
(void)unlink(safecopy ? tempfile : to_name); |
errx(EX_OSERR, "%s: chown/chgrp: %s", |
errx(1, "%s: chown/chgrp: %s", |
safecopy ? tempfile : to_name, strerror(serrno)); |
safecopy ? tempfile : to_name, strerror(serrno)); |
} |
} |
if (fchmod(to_fd, mode)) { |
if (fchmod(to_fd, mode)) { |
serrno = errno; |
serrno = errno; |
(void)unlink(safecopy ? tempfile : to_name); |
(void)unlink(safecopy ? tempfile : to_name); |
errx(EX_OSERR, "%s: chmod: %s", safecopy ? tempfile : to_name, |
errx(1, "%s: chmod: %s", safecopy ? tempfile : to_name, |
strerror(serrno)); |
strerror(serrno)); |
} |
} |
|
|
|
|
if (rename(to_name, backup) < 0 && errno != ENOENT) { |
if (rename(to_name, backup) < 0 && errno != ENOENT) { |
serrno = errno; |
serrno = errno; |
unlink(tempfile); |
unlink(tempfile); |
errx(EX_OSERR, "rename: %s to %s: %s", to_name, |
errx(1, "rename: %s to %s: %s", to_name, |
backup, strerror(serrno)); |
backup, strerror(serrno)); |
} |
} |
} |
} |
if (rename(tempfile, to_name) < 0 ) { |
if (rename(tempfile, to_name) < 0 ) { |
serrno = errno; |
serrno = errno; |
unlink(tempfile); |
unlink(tempfile); |
errx(EX_OSERR, "rename: %s to %s: %s", tempfile, |
errx(1, "rename: %s to %s: %s", tempfile, |
to_name, strerror(serrno)); |
to_name, strerror(serrno)); |
} |
} |
} |
} |
|
|
|
|
/* Rewind file descriptors. */ |
/* Rewind file descriptors. */ |
if (lseek(from_fd, (off_t)0, SEEK_SET) == (off_t)-1) |
if (lseek(from_fd, (off_t)0, SEEK_SET) == (off_t)-1) |
err(EX_OSERR, "lseek: %s", from_name); |
err(1, "lseek: %s", from_name); |
if (lseek(to_fd, (off_t)0, SEEK_SET) == (off_t)-1) |
if (lseek(to_fd, (off_t)0, SEEK_SET) == (off_t)-1) |
err(EX_OSERR, "lseek: %s", to_name); |
err(1, "lseek: %s", to_name); |
|
|
/* |
/* |
* Mmap and write if less than 8M (the limit is so we don't totally |
* Mmap and write if less than 8M (the limit is so we don't totally |
|
|
from_fd, (off_t)0)) == MAP_FAILED) { |
from_fd, (off_t)0)) == MAP_FAILED) { |
serrno = errno; |
serrno = errno; |
(void)unlink(to_name); |
(void)unlink(to_name); |
errc(EX_OSERR, serrno, "%s", from_name); |
errc(1, serrno, "%s", from_name); |
} |
} |
madvise(p, size, MADV_SEQUENTIAL); |
madvise(p, size, MADV_SEQUENTIAL); |
siz = (size_t)size; |
siz = (size_t)size; |
if ((nw = write(to_fd, p, siz)) != siz) { |
if ((nw = write(to_fd, p, siz)) != siz) { |
serrno = errno; |
serrno = errno; |
(void)unlink(to_name); |
(void)unlink(to_name); |
errx(EX_OSERR, "%s: %s", |
errx(1, "%s: %s", |
to_name, strerror(nw > 0 ? EIO : serrno)); |
to_name, strerror(nw > 0 ? EIO : serrno)); |
} |
} |
(void) munmap(p, (size_t)size); |
(void) munmap(p, (size_t)size); |
|
|
if (nw != nr) { |
if (nw != nr) { |
serrno = errno; |
serrno = errno; |
(void)unlink(to_name); |
(void)unlink(to_name); |
errx(EX_OSERR, "%s: %s", |
errx(1, "%s: %s", |
to_name, strerror(nw > 0 ? EIO : serrno)); |
to_name, strerror(nw > 0 ? EIO : serrno)); |
} |
} |
} |
} |
|
|
if (nr != 0) { |
if (nr != 0) { |
serrno = errno; |
serrno = errno; |
(void)unlink(to_name); |
(void)unlink(to_name); |
errc(EX_OSERR, serrno, "%s", from_name); |
errc(1, serrno, "%s", from_name); |
} |
} |
} |
} |
} |
} |
|
|
|
|
if ((p1 = mmap(NULL, length, PROT_READ, MAP_PRIVATE, |
if ((p1 = mmap(NULL, length, PROT_READ, MAP_PRIVATE, |
from_fd, from_off)) == MAP_FAILED) |
from_fd, from_off)) == MAP_FAILED) |
err(EX_OSERR, "%s", from_name); |
err(1, "%s", from_name); |
if ((p2 = mmap(NULL, length, PROT_READ, MAP_PRIVATE, |
if ((p2 = mmap(NULL, length, PROT_READ, MAP_PRIVATE, |
to_fd, to_off)) == MAP_FAILED) |
to_fd, to_off)) == MAP_FAILED) |
err(EX_OSERR, "%s", to_name); |
err(1, "%s", to_name); |
if (length) { |
if (length) { |
madvise(p1, length, MADV_SEQUENTIAL); |
madvise(p1, length, MADV_SEQUENTIAL); |
madvise(p2, length, MADV_SEQUENTIAL); |
madvise(p2, length, MADV_SEQUENTIAL); |
|
|
case -1: |
case -1: |
serrno = errno; |
serrno = errno; |
(void)unlink(to_name); |
(void)unlink(to_name); |
errc(EX_TEMPFAIL, serrno, "forks"); |
errc(1, serrno, "forks"); |
case 0: |
case 0: |
execl(path_strip, "strip", "--", to_name, (char *)NULL); |
execl(path_strip, "strip", "--", to_name, (char *)NULL); |
warn("%s", path_strip); |
warn("%s", path_strip); |
_exit(EX_OSERR); |
_exit(1); |
default: |
default: |
if (wait(&status) == -1 || !WIFEXITED(status)) |
if (wait(&status) == -1 || !WIFEXITED(status)) |
(void)unlink(to_name); |
(void)unlink(to_name); |
|
|
int mkdir_errno = errno; |
int mkdir_errno = errno; |
if (stat(path, &sb)) { |
if (stat(path, &sb)) { |
/* Not there; use mkdir()s errno */ |
/* Not there; use mkdir()s errno */ |
errc(EX_OSERR, mkdir_errno, "%s", |
errc(1, mkdir_errno, "%s", |
path); |
path); |
/* NOTREACHED */ |
/* NOTREACHED */ |
} |
} |
if (!S_ISDIR(sb.st_mode)) { |
if (!S_ISDIR(sb.st_mode)) { |
/* Is there, but isn't a directory */ |
/* Is there, but isn't a directory */ |
errc(EX_OSERR, ENOTDIR, "%s", path); |
errc(1, ENOTDIR, "%s", path); |
/* NOTREACHED */ |
/* NOTREACHED */ |
} |
} |
} |
} |
|
|
{ |
{ |
(void)fprintf(stderr, "\ |
(void)fprintf(stderr, "\ |
usage: install [-bCcDdpSs] [-B suffix] [-f flags] [-g group] [-m mode] [-o owner]\n source ... target ...\n"); |
usage: install [-bCcDdpSs] [-B suffix] [-f flags] [-g group] [-m mode] [-o owner]\n source ... target ...\n"); |
exit(EX_USAGE); |
exit(1); |
/* NOTREACHED */ |
/* NOTREACHED */ |
} |
} |
|
|
|
|
(void)snprintf(backup, PATH_MAX, "%s%s", path, suffix); |
(void)snprintf(backup, PATH_MAX, "%s%s", path, suffix); |
/* It is ok for the target file not to exist. */ |
/* It is ok for the target file not to exist. */ |
if (rename(path, backup) < 0 && errno != ENOENT) |
if (rename(path, backup) < 0 && errno != ENOENT) |
err(EX_OSERR, "rename: %s to %s (errno %d)", path, backup, errno); |
err(1, "rename: %s to %s (errno %d)", path, backup, errno); |
} else { |
} else { |
if (unlink(path) < 0 && errno != ENOENT) |
if (unlink(path) < 0 && errno != ENOENT) |
err(EX_OSERR, "%s", path); |
err(1, "%s", path); |
} |
} |
|
|
return(open(path, O_CREAT | O_RDWR | O_EXCL, S_IRUSR | S_IWUSR)); |
return(open(path, O_CREAT | O_RDWR | O_EXCL, S_IRUSR | S_IWUSR)); |