install: handle -m +X more accurately

As described by chmod(1), +X in the mode may be used to optionally set
the +x bit if the file is a directory if any of the execute/search bits
are set in the original mode.  The latter is not applicable because we
assume -m is a fresh mask, but a functional +X could be useful in the
former case if we're passing along a common INSTALL_MODE that's designed
to install either 0644 or 0755 depending simply on whether it's a
directory or not.

Reviewed by:	des
Sponsored by:	Klara, Inc.
Differential Revision:	https://reviews.freebsd.org/D42273
This commit is contained in:
Kyle Evans 2023-10-18 21:43:06 -05:00
parent fb7140b1f9
commit 767c97c501
2 changed files with 26 additions and 2 deletions

View file

@ -481,6 +481,21 @@ set_owner_group_mode_unpriv_body() {
atf_check_equal "$u:$g:10$cM" "$(stat -f"%u:%g:%p" testc)"
}
atf_test_case set_optional_exec
set_optional_exec_head() {
atf_set "require.user" "unprivileged"
}
set_optional_exec_body()
{
echo "abc" > testfile.src
atf_check install -d -m ug+rX testdir
atf_check test -x testdir
atf_check install -m ug+rX testfile.src testfile
atf_check test ! -x testfile
}
atf_init_test_cases() {
atf_add_test_case copy_to_nonexistent
atf_add_test_case copy_to_nonexistent_safe
@ -523,4 +538,5 @@ atf_init_test_cases() {
atf_add_test_case mkdir_simple
atf_add_test_case set_owner_group_mode
atf_add_test_case set_owner_group_mode_unpriv
atf_add_test_case set_optional_exec
}

View file

@ -189,6 +189,7 @@ main(int argc, char *argv[])
fset = 0;
iflags = 0;
set = NULL;
group = owner = NULL;
while ((ch = getopt(argc, argv, "B:bCcD:df:g:h:l:M:m:N:o:pSsT:Uv")) !=
-1)
@ -255,11 +256,10 @@ main(int argc, char *argv[])
break;
case 'm':
haveopt_m = 1;
free(set);
if (!(set = setmode(optarg)))
errx(EX_USAGE, "invalid file mode: %s",
optarg);
mode = getmode(set, 0);
free(set);
break;
case 'N':
if (!setup_getid(optarg))
@ -301,6 +301,14 @@ main(int argc, char *argv[])
usage();
}
/*
* Default permissions based on whether we're a directory or not, since
* an +X may mean that we need to set the execute bit.
*/
if (set != NULL)
mode = getmode(set, dodir ? S_IFDIR : 0) & ~S_IFDIR;
free(set);
if (getenv("DONTSTRIP") != NULL) {
warnx("DONTSTRIP set - will not strip installed binaries");
dostrip = 0;