1# 2# Copyright 2017 Shivansh Rai 3# Copyright (c) 2026 Jitendra Bhati 4# All rights reserved. 5# 6# Redistribution and use in source and binary forms, with or without 7# modification, are permitted provided that the following conditions 8# are met: 9# 1. Redistributions of source code must retain the above copyright 10# notice, this list of conditions and the following disclaimer. 11# 2. Redistributions in binary form must reproduce the above copyright 12# notice, this list of conditions and the following disclaimer in the 13# documentation and/or other materials provided with the distribution. 14# 15# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25# SUCH DAMAGE. 26# 27# 28 29usage_output='usage: chflags' 30 31# Skip the calling test if the work filesystem does not support 32# setting the nodump file flag (e.g. some ZFS configurations). 33require_chflags() 34{ 35 touch .chflags_probe 36 if ! chflags nodump .chflags_probe 2>/dev/null; then 37 rm -f .chflags_probe 38 atf_skip "filesystem does not support the nodump flag" 39 fi 40 rm -f .chflags_probe 41} 42 43atf_test_case invalid_usage 44invalid_usage_head() 45{ 46 atf_set "descr" "Verify that an invalid usage with a supported option produces a valid error message" 47} 48 49invalid_usage_body() 50{ 51 atf_check -s not-exit:0 -e match:"$usage_output" chflags -f 52 atf_check -s not-exit:0 -e match:"$usage_output" chflags -H 53 atf_check -s not-exit:0 -e match:"$usage_output" chflags -h 54 atf_check -s not-exit:0 -e match:"$usage_output" chflags -L 55 atf_check -s not-exit:0 -e match:"$usage_output" chflags -P 56 atf_check -s not-exit:0 -e match:"$usage_output" chflags -R 57 atf_check -s not-exit:0 -e match:"$usage_output" chflags -v 58} 59 60atf_test_case no_arguments 61no_arguments_head() 62{ 63 atf_set "descr" "Verify that chflags(1) fails and generates a valid usage message when no arguments are supplied" 64} 65 66no_arguments_body() 67{ 68 atf_check -s not-exit:0 -e match:"$usage_output" chflags 69} 70 71atf_test_case relative_path 72relative_path_head() 73{ 74 atf_set "descr" "chflags sets flags on a relative path" 75} 76relative_path_body() 77{ 78 require_chflags 79 touch file 80 atf_check chflags nodump file 81 atf_check -o match:nodump stat -f "%Sf" file 82} 83 84atf_test_case absolute_path 85absolute_path_head() 86{ 87 atf_set "descr" "chflags sets flags on an absolute path" 88} 89absolute_path_body() 90{ 91 require_chflags 92 touch file 93 atf_check chflags nodump "$(pwd)/file" 94 atf_check -o match:nodump stat -f "%Sf" file 95} 96 97atf_test_case dotdot_path 98dotdot_path_head() 99{ 100 atf_set "descr" "chflags sets flags on a path containing .." 101} 102dotdot_path_body() 103{ 104 require_chflags 105 mkdir dir 106 touch file 107 cd dir 108 atf_check chflags nodump ../file 109 atf_check -o match:nodump stat -f "%Sf" ../file 110} 111 112atf_test_case recursive 113recursive_head() 114{ 115 atf_set "descr" "chflags -R sets flags on a directory tree" 116} 117recursive_body() 118{ 119 require_chflags 120 mkdir -p dir/sub 121 touch dir/file dir/sub/file 122 atf_check chflags -R nodump dir 123 atf_check -o match:nodump stat -f "%Sf" dir/file 124 atf_check -o match:nodump stat -f "%Sf" dir/sub/file 125} 126 127atf_test_case mixed_paths 128mixed_paths_head() 129{ 130 atf_set "descr" "chflags handles relative, absolute and .. paths together" 131} 132mixed_paths_body() 133{ 134 require_chflags 135 mkdir dir 136 touch a dir/b c 137 cd dir 138 atf_check chflags nodump b "$(pwd)/../a" ../c 139 atf_check -o match:nodump stat -f "%Sf" b 140 atf_check -o match:nodump stat -f "%Sf" ../a 141 atf_check -o match:nodump stat -f "%Sf" ../c 142} 143 144atf_test_case outside_symlink_rejected 145outside_symlink_rejected_head() 146{ 147 atf_set "descr" "chflags -RL does not follow a symlink pointing " \ 148 "outside the traversal by default" 149} 150outside_symlink_rejected_body() 151{ 152 require_chflags 153 mkdir -p foo/bar/baz 154 touch target 155 ln -s ../../../target foo/bar/baz/link 156 atf_check -s not-exit:0 -e ignore chflags -RL nodump foo/bar 157 atf_check -o match:"target[[:space:]]*-" stat -f "%N %Sf" target 158} 159 160atf_test_case outside_symlink_unsafe 161outside_symlink_unsafe_head() 162{ 163 atf_set "descr" "chflags -RL --dereference-links-unsafely follows " \ 164 "a symlink pointing outside the traversal" 165} 166outside_symlink_unsafe_body() 167{ 168 require_chflags 169 mkdir -p foo/bar/baz 170 touch target 171 ln -s ../../../target foo/bar/baz/link 172 atf_check chflags -RL --dereference-links-unsafely nodump foo/bar 173 atf_check -o match:nodump stat -f "%Sf" target 174} 175 176atf_test_case symlink_no_h 177symlink_no_h_head() 178{ 179 atf_set "descr" "chflags on a symlink without -h changes the target" 180} 181symlink_no_h_body() 182{ 183 require_chflags 184 mkdir dir 185 touch target 186 ln -s ../target dir/link 187 atf_check chflags nodump dir/link 188 atf_check -o match:nodump stat -f "%Sf" target 189 atf_check -o not-match:nodump stat -f "%Sf" dir/link 190} 191 192atf_test_case symlink_rootlevel_H 193symlink_rootlevel_H_head() 194{ 195 atf_set "descr" "chflags -RH follows a symbolic link to a" \ 196 " directory named on the command line" 197} 198symlink_rootlevel_H_body() 199{ 200 require_chflags 201 mkdir dir realdir 202 touch realdir/file 203 ln -s ../realdir dir/dlink 204 atf_check chflags -RH nodump dir/dlink 205 atf_check -o match:nodump stat -f "%Sf" realdir/file 206 atf_check -o not-match:nodump stat -f "%Sf" dir/dlink 207} 208 209atf_test_case symlink_rootlevel_H_dead 210symlink_rootlevel_H_dead_head() 211{ 212 atf_set "descr" "chflags -RH on a broken symbolic link fails" \ 213 " gracefully" 214} 215symlink_rootlevel_H_dead_body() 216{ 217 require_chflags 218 mkdir dir 219 ln -s ../nonexistent dir/dlink 220 atf_check -s not-exit:0 -e match:"No such file or directory" \ 221 chflags -RH nodump dir/dlink 222} 223 224atf_init_test_cases() 225{ 226 atf_add_test_case invalid_usage 227 atf_add_test_case no_arguments 228 atf_add_test_case relative_path 229 atf_add_test_case absolute_path 230 atf_add_test_case dotdot_path 231 atf_add_test_case recursive 232 atf_add_test_case mixed_paths 233 atf_add_test_case symlink_no_h 234 atf_add_test_case symlink_rootlevel_H 235 atf_add_test_case symlink_rootlevel_H_dead 236 atf_add_test_case outside_symlink_rejected 237 atf_add_test_case outside_symlink_unsafe 238} 239