Date: Tue, 28 Jul 2026 09:34:14 +0000 From: Dag-Erling=?utf-8?Q? Sm=C3=B8rg?=rav <des@FreeBSD.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org Subject: git: 993df5472e52 - stable/15 - install: Allow installing stdin Message-ID: <6a687796.1c794.7b992d8c@gitrepo.freebsd.org>
index | next in thread | raw e-mail
The branch stable/15 has been updated by des: URL: https://cgit.FreeBSD.org/src/commit/?id=993df5472e52f1fce7d527fcd35a5d0a7d51dde0 commit 993df5472e52f1fce7d527fcd35a5d0a7d51dde0 Author: Dag-Erling Smørgrav <des@FreeBSD.org> AuthorDate: 2026-07-21 08:03:44 +0000 Commit: Dag-Erling Smørgrav <des@FreeBSD.org> CommitDate: 2026-07-28 09:32:28 +0000 install: Allow installing stdin If from_name is "/dev/stdin" or "-" and the target is not a directory, skip the comparison and copy data from standard input to the target. MFC after: 1 week Reviewed by: imp Differential Revision: https://reviews.freebsd.org/D58348 (cherry picked from commit d34870708db9fa1eb8e29b5e085b755de1189b1f) --- usr.bin/xinstall/install.1 | 7 ++++- usr.bin/xinstall/tests/install_test.sh | 32 +++++++++++++++++++++ usr.bin/xinstall/xinstall.c | 52 +++++++++++++++++++++++----------- 3 files changed, 73 insertions(+), 18 deletions(-) diff --git a/usr.bin/xinstall/install.1 b/usr.bin/xinstall/install.1 index c6a55632891c..c4a5fbe68950 100644 --- a/usr.bin/xinstall/install.1 +++ b/usr.bin/xinstall/install.1 @@ -25,7 +25,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd June 3, 2026 +.Dd July 19, 2026 .Dt INSTALL 1 .Os .Sh NAME @@ -286,6 +286,11 @@ utility attempts to prevent moving a file onto itself. Installing .Pa /dev/null creates an empty file. +Installing +.Pa /dev/stdin +or +.Sy - +copies data from standard input to the target. .Sh ENVIRONMENT The .Nm diff --git a/usr.bin/xinstall/tests/install_test.sh b/usr.bin/xinstall/tests/install_test.sh index 377920200490..7acd02abbb80 100755 --- a/usr.bin/xinstall/tests/install_test.sh +++ b/usr.bin/xinstall/tests/install_test.sh @@ -557,6 +557,36 @@ digest_body() { done } +atf_test_case null +null_head() { + atf_set "descr" "Install empty file" +} +null_body() { + atf_check mkdir dst + atf_check -s exit:71 -e not-empty install /dev/null dst + atf_check install /dev/null dst/file + atf_check test -f dst/file + atf_check test ! -s dst/file +} + +atf_test_case stdin +stdin_head() { + atf_set "descr" "Install stdin" +} +stdin_body() { + atf_check mkdir dst + echo "The Magic Words are Squeamish Ossifrage" >file + atf_check -s exit:71 -e not-empty install - dst <file + atf_check test ! -e dst/file + atf_check install - dst/file <file + atf_check cmp -s file dst/file + atf_check rm dst/file + atf_check -s exit:71 -e not-empty install /dev/stdin dst <file + atf_check test ! -e dst/file + atf_check install /dev/stdin dst/file <file + atf_check cmp -s file dst/file +} + atf_init_test_cases() { atf_add_test_case incompatible_opts atf_add_test_case copy_to_empty @@ -605,4 +635,6 @@ atf_init_test_cases() { atf_add_test_case set_optional_exec atf_add_test_case metalog atf_add_test_case digest + atf_add_test_case null + atf_add_test_case stdin } diff --git a/usr.bin/xinstall/xinstall.c b/usr.bin/xinstall/xinstall.c index 2c88e080bb74..38aa793d2492 100644 --- a/usr.bin/xinstall/xinstall.c +++ b/usr.bin/xinstall/xinstall.c @@ -62,6 +62,13 @@ #include "mtree.h" +#ifndef _PATH_STDIN +# ifndef _PATH_DEV +# defne _PATH_DEV "/dev/" +# endif +# define _PATH_STDIN _PATH_DEV "stdin" +#endif + /* * Memory strategy threshold, in pages: if physmem is larger than this, use a * large buffer. @@ -808,18 +815,29 @@ install(const char *from_name, const char *to_name, u_long fset, u_int flags) { struct stat from_sb, temp_sb, to_sb; struct timespec tsb[2]; - int devnull, files_match, from_fd, serrno, stripped, target; + int devnull, files_match, from_fd, ispipe, serrno, stripped, target; int temp_fd, to_fd; char backup[MAXPATHLEN], *p, pathbuf[MAXPATHLEN], tempfile[MAXPATHLEN]; char *digestresult; + devnull = ispipe = 0; digestresult = NULL; files_match = stripped = 0; from_fd = -1; to_fd = -1; - /* If try to install NULL file to a directory, fails. */ - if (flags & DIRECTORY || strcmp(from_name, _PATH_DEVNULL)) { + if (strcmp(from_name, _PATH_DEVNULL) == 0) { + /* We can't create a new file without a name */ + if ((flags & DIRECTORY) != 0) + errc(EX_OSERR, EFTYPE, "%s", from_name); + devnull = 1; + } else if (strcmp(from_name, _PATH_STDIN) == 0 || + strcmp(from_name, "-") == 0) { + /* We can't create a new file without a name */ + if ((flags & DIRECTORY) != 0) + errc(EX_OSERR, EFTYPE, "%s", from_name); + ispipe = 1; + } else { if (!dolink) { if (stat(from_name, &from_sb)) err(EX_OSERR, "%s", from_name); @@ -834,9 +852,6 @@ install(const char *from_name, const char *to_name, u_long fset, u_int flags) (p = strrchr(from_name, '/')) ? ++p : from_name); to_name = pathbuf; } - devnull = 0; - } else { - devnull = 1; } if (*to_name == '\0') errx(EX_USAGE, "destination cannot be an empty string"); @@ -851,19 +866,28 @@ install(const char *from_name, const char *to_name, u_long fset, u_int flags) if (target && !S_ISREG(to_sb.st_mode) && !S_ISLNK(to_sb.st_mode)) errc(EX_CANTCREAT, EFTYPE, "%s", to_name); - if (!devnull && (from_fd = open(from_name, O_RDONLY, 0)) < 0) - err(EX_OSERR, "%s", from_name); + if (devnull) { + /* No from_fd needed */ + } else if (ispipe) { + from_fd = STDIN_FILENO; + } else { + if ((from_fd = open(from_name, O_RDONLY)) < 0) + err(EX_OSERR, "%s", from_name); + } /* If we don't strip, we can compare first. */ if (docompare && !dostrip && target && S_ISREG(to_sb.st_mode)) { - if ((to_fd = open(to_name, O_RDONLY, 0)) < 0) + if ((to_fd = open(to_name, O_RDONLY)) < 0) err(EX_OSERR, "%s", to_name); if (devnull) files_match = to_sb.st_size == 0; - else + else if (ispipe) + files_match = 0; + else { files_match = !(compare(from_fd, from_name, (size_t)from_sb.st_size, to_fd, to_name, (size_t)to_sb.st_size, &digestresult)); + } /* Close "to" file unless we match. */ if (!files_match) @@ -1070,7 +1094,7 @@ install(const char *from_name, const char *to_name, u_long fset, u_int flags) #endif (void)close(to_fd); - if (!devnull) + if (!devnull && !ispipe) (void)close(from_fd); metadata_log(to_name, "file", tsb, NULL, digestresult, to_sb.st_size); @@ -1188,12 +1212,6 @@ copy(int from_fd, const char *from_name, int to_fd, const char *to_name) #endif DIGEST_CTX ctx; - /* Rewind file descriptors. */ - if (lseek(from_fd, 0, SEEK_SET) < 0) - err(EX_OSERR, "lseek: %s", from_name); - if (lseek(to_fd, 0, SEEK_SET) < 0) - err(EX_OSERR, "lseek: %s", to_name); - #ifndef BOOTSTRAP_XINSTALL /* Try copy_file_range() if no digest is requested */ if (digesttype == DIGEST_NONE) {home | help
Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?6a687796.1c794.7b992d8c>
