diff options
author | Ingo Schwarze <schwarze@cvs.openbsd.org> | 2019-02-09 22:08:26 +0000 |
---|---|---|
committer | Ingo Schwarze <schwarze@cvs.openbsd.org> | 2019-02-09 22:08:26 +0000 |
commit | 7ae3cdccafb486c25fd7d9b2b80c694c40d526ba (patch) | |
tree | 3057359f62c4c65a9f5a0425d9b598e410cfcc3c /usr.bin/xinstall | |
parent | 005e8570a3c816e3300d6416aa08e123afaec871 (diff) |
Revert previous.
It appears the flag combination -S -p not only preserved the modification
time as documented, but also the file mode unless the file content changed,
so with the change in rev. 1.68, the flag -p no longer applies the given
file mode if the file content does not change.
Regression in the lang/go-boostrap build system reported by espie@.
Diffstat (limited to 'usr.bin/xinstall')
-rw-r--r-- | usr.bin/xinstall/xinstall.c | 104 |
1 files changed, 83 insertions, 21 deletions
diff --git a/usr.bin/xinstall/xinstall.c b/usr.bin/xinstall/xinstall.c index fa4af64e98c..158f59ffba1 100644 --- a/usr.bin/xinstall/xinstall.c +++ b/usr.bin/xinstall/xinstall.c @@ -1,4 +1,4 @@ -/* $OpenBSD: xinstall.c,v 1.68 2019/02/08 12:53:44 schwarze Exp $ */ +/* $OpenBSD: xinstall.c,v 1.69 2019/02/09 22:08:25 schwarze Exp $ */ /* $NetBSD: xinstall.c,v 1.9 1995/12/20 10:25:17 jonathan Exp $ */ /* @@ -60,7 +60,7 @@ #define NOCHANGEBITS (UF_IMMUTABLE | UF_APPEND | SF_IMMUTABLE | SF_APPEND) #define BACKUP_SUFFIX ".old" -int dobackup, docompare, dodest, dodir, dopreserve, dostrip; +int dobackup, docompare, dodest, dodir, dopreserve, dostrip, safecopy; int mode = S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH; char pathbuf[PATH_MAX], tempfile[PATH_MAX]; char *suffix = BACKUP_SUFFIX; @@ -73,6 +73,7 @@ void install(char *, char *, u_long, u_int); void install_dir(char *, int); void strip(char *); void usage(void); +int create_newfile(char *, struct stat *); int create_tempfile(char *, char *, size_t); int file_write(int, char *, size_t, int *, int *, int); void file_flush(int, int); @@ -128,7 +129,7 @@ main(int argc, char *argv[]) docompare = dopreserve = 1; break; case 'S': - /* For backwards compatibility. */ + safecopy = 1; break; case 's': dostrip = 1; @@ -147,13 +148,17 @@ main(int argc, char *argv[]) argv += optind; /* some options make no sense when creating directories */ - if ((docompare || dostrip) && dodir) + if ((safecopy || docompare || dostrip) && dodir) usage(); /* must have at least two arguments, except when creating directories */ if (argc < 2 && !dodir) usage(); + /* need to make a temp copy so we can compare stripped version */ + if (docompare && dostrip) + safecopy = 1; + /* get group and owner id's */ if (group != NULL && gid_from_group(group, &gid) == -1) { gid = strtonum(group, 0, GID_MAX, &errstr); @@ -260,30 +265,54 @@ install(char *from_name, char *to_name, u_long fset, u_int flags) err(1, "%s", from_name); } - to_fd = create_tempfile(to_name, tempfile, sizeof(tempfile)); - if (to_fd < 0) - err(1, "%s", tempfile); + if (safecopy) { + to_fd = create_tempfile(to_name, tempfile, sizeof(tempfile)); + if (to_fd < 0) + err(1, "%s", tempfile); + } else if (docompare && !dostrip) { + if ((to_fd = open(to_name, O_RDONLY, 0)) < 0) + err(1, "%s", to_name); + } else { + if ((to_fd = create_newfile(to_name, &to_sb)) < 0) + err(1, "%s", to_name); + } - if (!devnull) - copy(from_fd, from_name, to_fd, tempfile, from_sb.st_size, - ((off_t)from_sb.st_blocks * S_BLKSIZE < from_sb.st_size)); + if (!devnull) { + if (docompare && !safecopy) { + files_match = !(compare(from_fd, from_name, + from_sb.st_size, to_fd, + to_name, to_sb.st_size)); + + /* Truncate "to" file for copy unless we match */ + if (!files_match) { + (void)close(to_fd); + if ((to_fd = create_newfile(to_name, &to_sb)) < 0) + err(1, "%s", to_name); + } + } + if (!files_match) + copy(from_fd, from_name, to_fd, + safecopy ? tempfile : to_name, from_sb.st_size, + ((off_t)from_sb.st_blocks * S_BLKSIZE < from_sb.st_size)); + } if (dostrip) { - strip(tempfile); + strip(safecopy ? tempfile : to_name); /* * Re-open our fd on the target, in case we used a strip * that does not work in-place -- like gnu binutils strip. */ close(to_fd); - if ((to_fd = open(tempfile, O_RDONLY, 0)) < 0) + if ((to_fd = open(safecopy ? tempfile : to_name, O_RDONLY, + 0)) < 0) err(1, "stripping %s", to_name); } /* * Compare the (possibly stripped) temp file to the target. */ - if (docompare) { + if (safecopy && docompare) { int temp_fd = to_fd; struct stat temp_sb; @@ -333,13 +362,15 @@ install(char *from_name, char *to_name, u_long fset, u_int flags) if ((gid != (gid_t)-1 || uid != (uid_t)-1) && fchown(to_fd, uid, gid)) { serrno = errno; - (void)unlink(tempfile); - errx(1, "%s: chown/chgrp: %s", tempfile, strerror(serrno)); + (void)unlink(safecopy ? tempfile : to_name); + errx(1, "%s: chown/chgrp: %s", + safecopy ? tempfile : to_name, strerror(serrno)); } if (fchmod(to_fd, mode)) { serrno = errno; - (void)unlink(tempfile); - errx(1, "%s: chmod: %s", tempfile, strerror(serrno)); + (void)unlink(safecopy ? tempfile : to_name); + errx(1, "%s: chmod: %s", safecopy ? tempfile : to_name, + strerror(serrno)); } /* @@ -349,7 +380,8 @@ install(char *from_name, char *to_name, u_long fset, u_int flags) if (fchflags(to_fd, flags & SETFLAGS ? fset : from_sb.st_flags & ~UF_NODUMP)) { if (errno != EOPNOTSUPP || (from_sb.st_flags & ~UF_NODUMP) != 0) - warnx("%s: chflags: %s", tempfile, strerror(errno)); + warnx("%s: chflags: %s", + safecopy ? tempfile :to_name, strerror(errno)); } if (flags & USEFSYNC) @@ -359,10 +391,10 @@ install(char *from_name, char *to_name, u_long fset, u_int flags) (void)close(from_fd); /* - * Move the new file into place if the files are different - * or were not compared. + * Move the new file into place if doing a safe copy + * and the files are different (or just not compared). */ - if (!files_match) { + if (safecopy && !files_match) { /* Try to turn off the immutable bits. */ if (to_sb.st_flags & (NOCHANGEBITS)) (void)chflags(to_name, to_sb.st_flags & ~(NOCHANGEBITS)); @@ -626,6 +658,36 @@ create_tempfile(char *path, char *temp, size_t tsize) } /* + * create_newfile -- + * create a new file, overwriting an existing one if necessary + */ +int +create_newfile(char *path, struct stat *sbp) +{ + char backup[PATH_MAX]; + + /* + * Unlink now... avoid ETXTBSY errors later. Try and turn + * off the append/immutable bits -- if we fail, go ahead, + * it might work. + */ + if (sbp->st_flags & (NOCHANGEBITS)) + (void)chflags(path, sbp->st_flags & ~(NOCHANGEBITS)); + + if (dobackup) { + (void)snprintf(backup, PATH_MAX, "%s%s", path, suffix); + /* It is ok for the target file not to exist. */ + if (rename(path, backup) < 0 && errno != ENOENT) + err(1, "rename: %s to %s (errno %d)", path, backup, errno); + } else { + if (unlink(path) < 0 && errno != ENOENT) + err(1, "%s", path); + } + + return(open(path, O_CREAT | O_RDWR | O_EXCL, S_IRUSR | S_IWUSR)); +} + +/* * file_write() * Write/copy a file (during copy or archive extract). This routine knows * how to copy files with lseek holes in it. (Which are read as file |