1# 2# CDDL HEADER START 3# 4# The contents of this file are subject to the terms of the 5# Common Development and Distribution License (the "License"). 6# You may not use this file except in compliance with the License. 7# 8# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9# or https://opensource.org/licenses/CDDL-1.0. 10# See the License for the specific language governing permissions 11# and limitations under the License. 12# 13# When distributing Covered Code, include this CDDL HEADER in each 14# file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15# If applicable, add the following below this CDDL HEADER, with the 16# fields enclosed by brackets "[]" replaced with your own identifying 17# information: Portions Copyright [yyyy] [name of copyright owner] 18# 19# CDDL HEADER END 20# 21 22# 23# Copyright 2007 Sun Microsystems, Inc. All rights reserved. 24# Use is subject to license terms. 25# 26 27# 28# Copyright (c) 2013, 2016 by Delphix. All rights reserved. 29# 30 31. $STF_SUITE/include/libtest.shlib 32. $STF_SUITE/tests/functional/history/history.cfg 33 34function run_and_verify 35{ 36 typeset user pool 37 while getopts "p:u:" opt; do 38 case $opt in 39 p) 40 pool=$OPTARG 41 ;; 42 u) 43 user=$OPTARG 44 ;; 45 esac 46 done 47 shift $(($OPTIND - 1)) 48 49 pool=${pool:-$TESTPOOL} 50 user=${user:-"root"} 51 fullcmd="$1" 52 flags="$2" 53 54 if is_illumos; then 55 histcmd=$(echo $fullcmd | sed 's=/usr/sbin/==g') 56 else 57 histcmd=$(echo $fullcmd | sed -E 's=^.*/(zpool|zfs)$=\1=') 58 fi 59 60 read -r cmd subcmd _ <<<"$histcmd" 61 62 # If we aren't running zpool or zfs, something is wrong 63 [[ $cmd == "zpool" || $cmd == "zfs" ]] || \ 64 log_fail "run_and_verify called with \"$cmd ($fullcmd)\"" 65 66 # If this is a 'zfs receive' truncate the stdin redirect 67 [[ $subcmd == "receive" || $subcmd == "recv" ]] && \ 68 histcmd=${histcmd%% <*} 69 70 # Run the command as the specified user, and find the new history. 71 zpool history $flags $pool > $OLD_HISTORY 2>/dev/null 72 if [[ $user == "root" ]]; then 73 log_must_busy eval "$fullcmd" 74 else 75 log_must_busy user_run $user "$fullcmd" 76 fi 77 zpool history $flags $pool > $TMP_HISTORY 2>/dev/null 78 diff $OLD_HISTORY $TMP_HISTORY | sed -n 's/^> //gp' > $NEW_HISTORY 79 80 # Verify what's common to every case, regardless of zpool history flags. 81 grep -q "$histcmd" $NEW_HISTORY || \ 82 log_fail "Didn't find \"$histcmd\" in pool history" 83 84 # If 'zpool history' was called without any flags, then we're done. 85 [[ -z $flags ]] && return 86 87 # Verify the new history in cases that are more interesting because 88 # additional information is logged with -i or -l. 89 90 [[ $flags =~ "i" ]] && log_must verify_$subcmd "$histcmd" "$subcmd" \ 91 "$flags" 92 [[ $flags =~ "l" ]] && log_must verify_long "$histcmd" "$user" "$flags" 93} 94 95function verify_long 96{ 97 typeset cmd=$1 98 typeset user=$2 99 typeset flags=$3 100 101 [[ $flags =~ "l" ]] || return 1 102 103 typeset uid=$(id -u $user) 104 typeset hname=$(hostname) 105 if ! is_global_zone; then 106 hname=$hname:$(zonename) 107 fi 108 109 typeset suffix="" 110 if is_linux; then 111 suffix=":linux" 112 elif is_freebsd; then 113 suffix=":freebsd" 114 fi 115 116 if ! grep -q "$cmd \[user $uid ($user) on $hname$suffix\]" $NEW_HISTORY; then 117 log_note "Couldn't find long information for \"$cmd\"" 118 return 1 119 fi 120 121 return 0 122} 123 124function verify_hold 125{ 126 typeset cmd=$1 127 typeset subcmd=$2 128 typeset flags=$3 129 130 [[ $flags =~ "i" ]] || return 1 131 132 typeset tag _ 133 read -r _ _ _ tag _ <<<"$cmd" 134 typeset fullname=${cmd##* } 135 typeset dsname=${fullname%%@*} 136 typeset snapname=${fullname##*@} 137 138 # This works whether or not the hold was recursive 139 for ds in $(zfs list -r -Ho name -t snapshot $dsname | \ 140 grep "@$snapname"); do 141 if ! grep -q "$subcmd $ds ([0-9]*) tag=$tag" $NEW_HISTORY; then 142 log_note "Didn't find hold on $ds with $tag" 143 return 1 144 fi 145 done 146 147 return 0 148} 149 150function verify_release 151{ 152 # hold and release formats only differ by the subcommand name, so 153 # simply reuse the hold function. 154 verify_hold "$1" "release" "$3" 155} 156 157function verify_rollback 158{ 159 typeset cmd=$1 160 typeset flags=$3 161 162 [[ $flags =~ "i" ]] || return 1 163 164 typeset fullname=${cmd##* } 165 typeset dsname=${fullname%%@*} 166 typeset parent_fs=${dsname##*/} 167 typeset rb_fs=${dsname}/%rollback 168 typeset snapname=${fullname##*@} 169 170 if ! grep -q "clone swap $rb_fs ([0-9]*) parent=$parent_fs" $NEW_HISTORY ; then 171 log_note "Didn't find rollback clone swap in pool history" 172 return 1 173 fi 174 175 if ! grep -q "destroy $rb_fs" $NEW_HISTORY; then 176 log_note "Didn't find rollback destroy in pool history" 177 return 1 178 fi 179 180 return 0 181} 182 183function verify_inherit 184{ 185 typeset cmd=$1 186 typeset flags=$3 187 188 [[ $flags =~ "i" ]] || return 1 189 190 typeset dsname=${cmd##* } 191 typeset prop=${cmd% *} 192 prop=${prop##* } 193 194 # This works whether or not the inherit was recursive 195 for ds in $(zfs list -r -Ho name -t filesystem $dsname); do 196 if ! grep -q "$subcmd $ds ([0-9]*) ${prop}=" $NEW_HISTORY; then 197 log_note "Didn't find inherit history for $ds" 198 return 1 199 fi 200 done 201 202 return 0 203} 204 205function verify_allow 206{ 207 typeset cmd=$1 208 typeset subcmd=$2 209 typeset flags=$3 210 211 [[ $flags =~ "i" ]] || return 1 212 [[ $subcmd == "allow" ]] && subcmd="update" 213 [[ $subcmd == "unallow" ]] && subcmd="remove" 214 typeset is_set lflag dflag dsname gname gid uname uid opt str code tmp 215 216 # 217 # Here, we determine three things: 218 # - Whether we're operating on a set or an individual permission (which 219 # dictates the case of the first character in the code) 220 # - The name of the dataset we're operating on. 221 # - Whether the operation applies locally or to descendent datasets (or 222 # both) 223 # 224 echo $cmd | awk '$(NF - 1) ~ /@/ {exit 1}' || is_set=1 225 dsname=${cmd##* } 226 [[ $cmd =~ "-l " ]] && lflag=1 227 [[ $cmd =~ "-d " ]] && dflag=1 228 if [[ -z $lflag && -z $dflag ]]; then 229 lflag=1 230 dflag=1 231 fi 232 233 # 234 # For each of the five cases below, the operation is essentially the 235 # same. First, use the command passed in to determine what the code at 236 # the end of the pool history will be. The specifics of the code are 237 # described in a block comment at the top of dsl_deleg.c. Once that's 238 # been assembled, check for its presence in the history, and return 239 # success or failure accordingly. 240 # 241 if [[ $cmd =~ "-s " ]]; then 242 str="s-\$@" 243 [[ -n $is_set ]] && str="S-\$@" 244 tmp=${cmd#*@} 245 code="$str${tmp% *}" 246 if ! grep -q "permission $subcmd $dsname ([0-9]*) $code" $NEW_HISTORY; then 247 log_note "Couldn't find $code in $NEW_HISTORY" 248 return 1 249 fi 250 elif [[ $cmd =~ "-c " ]]; then 251 str="c-\$" 252 [[ -n $is_set ]] && str="C-\$" 253 tmp=${cmd#*-c} 254 code="$str${tmp% *}" 255 if ! grep "permission $subcmd $dsname ([0-9]*) $code" $NEW_HISTORY; then 256 log_note "Couldn't find $code in $NEW_HISTORY" 257 return 1 258 fi 259 elif [[ $cmd =~ "-u " ]]; then 260 str="u" 261 [[ -n $is_set ]] && str="U" 262 tmp=${cmd##*-u } 263 read -r _ opt _ <<<"$opt" 264 uid=$(id -u ${tmp%% *}) 265 if [[ -n $lflag ]]; then 266 code="${str}l\$$uid $opt" 267 if grep -q "permission $subcmd $dsname ([0-9]*) $code" $NEW_HISTORY]; then 268 log_note "Couldn't find $code in $NEW_HISTORY" 269 return 1 270 fi 271 fi 272 if [[ -n $dflag ]]; then 273 code="${str}d\$$uid $opt" 274 if grep -q "permission $subcmd $dsname ([0-9]*) $code" $NEW_HISTORY]; then 275 log_note "Couldn't find $code in $NEW_HISTORY" 276 return 1 277 fi 278 fi 279 elif [[ $cmd =~ "-g " ]]; then 280 str="g" 281 [[ -n $is_set ]] && str="G" 282 tmp=${cmd##*-g } 283 read -r _ opt _ <<<"$opt" 284 gid=$(awk -F: "/^${tmp%% *}:/ {print \$3}" /etc/group) 285 if [[ -n $lflag ]]; then 286 code="${str}l\$$gid $opt" 287 if ! grep -q "permission $subcmd $dsname ([0-9]*) $code" $NEW_HISTORY; then 288 log_note "Couldn't find $code in $NEW_HISTORY" 289 return 1 290 fi 291 fi 292 if [[ -n $dflag ]]; then 293 code="${str}d\$$gid $opt" 294 if ! grep -q "permission $subcmd $dsname ([0-9]*) $code" $NEW_HISTORY; then 295 log_note "Couldn't find $code in $NEW_HISTORY" 296 return 1 297 fi 298 fi 299 elif [[ $cmd =~ "-e " ]]; then 300 str="e" 301 [[ -n $is_set ]] && str="E" 302 opt=${cmd##*-e } 303 opt=${opt%% *} 304 if [[ -n $lflag ]]; then 305 code="${str}l\$ $opt" 306 if ! grep -q "permission $subcmd $dsname ([0-9]*) $code" $NEW_HISTORY; then 307 log_note "Couldn't find $code in $NEW_HISTORY" 308 return 1 309 fi 310 fi 311 if [[ -n $dflag ]]; then 312 code="${str}d\$ $opt" 313 if ! grep -q "permission $subcmd $dsname ([0-9]*) $code" $NEW_HISTORY; then 314 log_note "Couldn't find $code in $NEW_HISTORY" 315 return 1 316 fi 317 fi 318 else 319 log_note "Can't parse command \"$cmd\"" 320 return 1 321 fi 322 323 return 0 324} 325 326function verify_unallow 327{ 328 # 329 # The unallow and allow history have the same format, except the former 330 # logs "permission removed" and the latter "permission updated" so 331 # simply reuse the allow function. 332 # 333 verify_allow "$1" "unallow" "$3" 334} 335 336function verify_destroy 337{ 338 typeset cmd=$1 339 typeset flags=$3 340 341 # This function doesn't currently verify the zpool command. 342 [[ ${cmd%% *} == "zfs" ]] || return 1 343 [[ $flags =~ "i" ]] || return 1 344 345 typeset dsname=${cmd##* } 346 [[ $dsname =~ "@" ]] && typeset is_snap=1 347 348 if [[ -n $is_snap ]]; then 349 if ! grep -q "ioctl destroy_snaps" $NEW_HISTORY; then 350 log_note "Didn't find ioctl while destroying $dsname" 351 return 1 352 fi 353 fi 354 355 # This should be present for datasets and snapshots alike 356 if ! grep -q "destroy $dsname" $NEW_HISTORY; then 357 log_note "Didn't find \"destroy\" for $dsname" 358 return 1 359 fi 360 361 return 0 362} 363 364function verify_snapshot 365{ 366 typeset cmd=$1 367 typeset flags=$3 368 369 [[ $flags =~ "i" ]] || return 1 370 371 typeset fullname=${cmd##* } 372 typeset dsname=${fullname%%@*} 373 typeset snapname=${fullname##*@} 374 375 if ! grep -q "\[txg:[0-9]*\] $subcmd $fullname ([0-9]*)" $NEW_HISTORY; then 376 log_note "Didn't find snapshot command for $fullname" 377 return 1 378 fi 379 380 # This works whether or not the snapshot was recursive 381 for ds in $(zfs list -r -Ho name -t snapshot $dsname | \ 382 grep "@$snapname"); do 383 if ! grep -q "^[ ]* $ds$" $NEW_HISTORY; then 384 log_note "Didn't find \"ioctl snapshot\" for $ds" 385 return 1 386 fi 387 done 388 389 return 0 390} 391