#!/bin/bash # Copyright 2011 Thomas Schmitt # Copyright 2011 George Danchev # Licensed under GNU GPL version 2 or later # Test the correct handling of hardlinks by xorriso options # -update_r , -hardlinks perform_update , and -extract # If there is support for ACLs or xattr in xorriso and on the local system, # then test recording and restoring of these features. not_in_releng_exit() { printf "\nPlease execute the tests from releng directory.\n\n" exit 1 } . inc/releng_getopts.inc || not_in_releng_exit print_specific_help() { cat << HLP Specific options: none yet. Overview: Tests ISO image contents by performing various image generation, extractions and comparisons. HLP } if test "$SPECIFIC_HELP" = 1; then print_specific_help exit 0 fi if [ ! -x $RELENG_XORRISO ]; then print_help printf "\n${SELF}: -x absolute or relative path to binary to be run.\n\n" exit 31 fi # check data dir, if any and after checking -x xorriso if [ -d "${GEN_DATA_DIR}" ]; then printf "\n${SELF}: directory %s exists!" ${GEN_DATA_DIR} printf "\n${SELF}: use '${SELF} -c' to remove.\n" exit 8 else mkdir "${GEN_DATA_DIR}" fi export xorriso=${RELENG_XORRISO} export workdir=${GEN_DATA_DIR} export image_file="$workdir"/xorriso_hardlinks.iso export on_disk="$workdir"/xorriso_hardlinks_test_dir export in_iso="" export copy_on_disk="$workdir"/xorriso_hardlinks_copy_dir export failure=0 export simulate_failure=${SIMULATE_FAILURE} export next_is_xorriso=0 export next_is_rc=0 export bad=0 export report_about="-report_about UPDATE" test -z "$in_iso" && in_iso="$on_disk" # mkdir "$workdir" || bad=1 mkdir "$on_disk" || bad=1 if test "$bad" = 1 then echo -e "\nFAIL : ${SELF} : Test environment error : Cannot make directories" exit 3 fi # All must be set at this point printf "\n${SELF}: Setting up $on_disk with several hardlinks\n" >&2 echo test_content >"$on_disk"/file_1 || exit 1 echo test_content >"$on_disk"/file_2 || exit 1 ln "$on_disk"/file_1 "$on_disk"/file_1_link_a || exit 1 ln "$on_disk"/file_1 "$on_disk"/file_1_link_b || exit 1 ln "$on_disk"/file_2 "$on_disk"/file_2_link_a || exit 1 # trivial ISO 9660 image validation routine is_valid_iso9660() { ISOfile="$1" if ! which file >/dev/null 2>&1; then printf "\nFAIL : ${SELF}: Not found: file. Please install the file(1) utility.\n" failure=1 return fi if [ ! -f ${ISOfile} ]; then failure=1 printf "\nFAIL : ${SELF} : Not found: ${ISOfile}\n" return fi file ${ISOfile} if file ${ISOfile} | grep "ISO *9660" >/dev/null 2>&1; then printf "\n${SELF}: Resulting ${ISOfile} OK. Looks like ISO 9660 filesystem.\n" else failure=1 printf "\nFAIL : ${SELF} : ${ISOfile} DOES NOT look like ISO 9660 filesystem data.\n" fi } # Retrieve and evaluate return value of command run under return_wrapper check_xorriso_return() { ret=$(cat "$return_value_file") rm "$return_value_file" if test "$ret" = 0 then return 0 fi failure=1 echo echo "FAIL : ${SELF} : xorriso run exited with value $ret" return 1 } # Create test file and find out whether ACLs and/or xattr are available. # # Users known on GNU/Linux and FreeBSD: root games daemon man # Groups : daemon games bin sshd sys # On both systems, ACLs are manipulated by setfacl/getfacl # acl_xattr_test_file="$on_disk"/acl_xattr_test_file acl_xattr_copy_file="$copy_on_disk"/acl_xattr_test_file acl_xattr_test_dir="$on_disk"/acl_xattr_test_dir acl_xattr_iso_dir="$in_iso"/acl_xattr_test_dir acl_xattr_copy_dir="$copy_on_disk"/acl_xattr_test_dir mkdir "$acl_xattr_test_dir" echo echo hello world >"$acl_xattr_test_file" || exit 1 sys=$(uname -s) acls=no default_acls=no setfacl_opts="" if ( setfacl -m u::rwx,g::r-x,o::---,u:root:rwx,g:sys:rwx,u:daemon:r--,mask::rwx \ "$acl_xattr_test_file" ) >/dev/null 2>&1 then if ( getfacl "$acl_xattr_test_file" ) >/dev/null 2>&1 then if ( setfacl -m u::rwx,g::r-x,o::---,u:root:rwx,g:sys:rwx,u:daemon:r--,mask::rwx \ "$acl_xattr_test_dir" ) >/dev/null 2>&1 then acls=yes # Setting of "default" ACLs will fail on FreeBSD. It will nevertheless be # done in the image by a xorriso command. Restoring is supposed to skip # "default" ACLs if none could be recorded. if setfacl -m u::rwx,g::r-x,o::---,u:root:rwx,g:sys:rwx,u:daemon:r--,mask::rwx,d:u::rwx,d:g::r-x,d:o::---,d:u:root:rwx,d:g:sys:rwx,d:u:daemon:r--,d:mask::rwx "$acl_xattr_iso_dir" 2>/dev/null then default_acls=yes fi setfacl_opts="-setfacl u::rwx,g::r-x,o::---,u:root:rwx,g:sys:rwx,u:daemon:r--,mask::rwx,d:u::rwx,d:g::r-x,d:o::---,d:u:root:rwx,d:g:sys:rwx,d:u:daemon:r--,d:mask::rwx $acl_xattr_iso_dir --" fi fi fi # GNU/Linux and FreeBSD have different tools for Extended Attributes xattrs=no extattrs=no # Try GNU/Linux style setattr/getattr if ( setfattr -n user.test_xattr -v test_value "$acl_xattr_test_file" ) \ >/dev/null 2>&1 then if ( getfattr -d "$acl_xattr_test_file" ) >/dev/null 2>&1 then xattrs=yes setfattr -n user.long_data -v 0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 "$acl_xattr_test_file" setfattr -n user.more_data -v 01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 "$acl_xattr_test_file" fi fi if test "$xattrs" = no then # Try FreeBSD style setextattr if ( setextattr user test_xattr test_value "$acl_xattr_test_file" ) \ >/dev/null 2>&1 then if ( getextattr user test_xattr "$acl_xattr_test_file" ) >/dev/null 2>&1 then setextattr user long_data 0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 "$acl_xattr_test_file" setextattr user more_data 01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 "$acl_xattr_test_file" if ( lsextattr user "$acl_xattr_test_file" ) >/dev/null 2>&1 then extattrs=yes fi fi fi fi echo echo "${SELF}: Detected sys='$sys' , acls=$acls , d_acls=$default_acls , xattrs=$xattrs , extattrs=$extattrs" # Examine capabilities of xorriso xorriso_acls=no xorriso_xattrs=no extras=$("$xorriso" -list_extras all 2>/dev/null) if test "$?" = 0 then if echo "$extras" | fgrep 'Local ACL : yes' >/dev/null 2>&1 then xorriso_acls=yes fi if echo "$extras" | fgrep 'Local xattr : yes' >/dev/null 2>&1 then xorriso_xattrs=yes fi fi if test "$xorriso_acls" = no then acls=no setfacl_opts= fi if test "$xorriso_xattrs" = no then xattrs=no extattrs=no fi echo "${SELF}: Detected xorriso_acls=$xorriso_acls , xorriso_xattrs=$xorriso_xattrs" echo ls -l "$on_disk"/* echo -e "\n${SELF}: Producing simple image via -o" >&2 "$xorriso" -as mkisofs "$on_disk" -o "$workdir"/image_minus_o.iso is_valid_iso9660 "$workdir"/image_minus_o.iso echo -e "\n${SELF}: Producing simple image via redirect" >&2 "$xorriso" -as mkisofs "$on_disk" > "$workdir"/image_redirected.iso is_valid_iso9660 "$workdir"/image_redirected.iso echo -e "\n${SELF}: Producing simple image via pipe" >&2 return_wrapper "$xorriso" -as mkisofs "$on_disk" | \ cat > "$workdir"/image_piped.iso check_xorriso_return is_valid_iso9660 "$workdir"/image_piped.iso echo -e "\n${SELF}: Producing simple image with for_backup/update_r/hardlinks" >&2 "$xorriso" \ $report_about \ -version \ -for_backup \ -padding 0 \ -outdev "$image_file" \ -volid TEST_AUTO_ISOCONTENT \ -update_r "$on_disk" "$in_iso" \ $setfacl_opts \ -hardlinks perform_update ret=$? if test "$ret" -gt 0 -a "$ret" -lt 32 then printf "\nFAIL : ${SELF} : xorriso write run failed\n\n" cleanup exit 1 fi is_valid_iso9660 "$image_file" # It must refuse to load and go on with -assert_volid and non-matching pattern. msg=$(\ "$xorriso" \ -abort_on FATAL \ -return_with FAILURE 32 \ -assert_volid 'NON_MATCHING*' FATAL \ -indev "$image_file" \ 2>&1 ) ret=$? if test "$ret" -gt 0 -a "$ret" -lt 32 then printf "\n${SELF}: Ok. -assert_volid snapped.\n" elif test "$ret" -ne 0 then failure=1 echo >&2 echo "$msg" >&2 printf "\nFAIL : ${SELF} : -assert_volid test not properly performed\n\n" else failure=1 printf "\nFAIL : ${SELF} : -assert_volid did not snap\n\n" >&2 fi echo -e "\n${SELF}: Copying from image to temporary disk tree" >&2 "$xorriso" \ $report_about \ -for_backup \ -assert_volid 'TEST_AUTO_ISOCONT*' FATAL \ -indev "$image_file" \ -osirrox on \ -find "$in_iso" -exec lsdl -- \ -extract "$in_iso" "$copy_on_disk" ret=$? if test "$ret" -gt 0 -a "$ret" -lt 32 then printf "\nFAIL : ${SELF} : xorriso file extraction run failed\n\n" cleanup exit 1 fi if test "$simulate_failure" = 1 then echo -e "\n${SELF}: SIMULATING FAILURE BY REMOVING AN EXTRACTED FILE" >&2 echo -e "\nFAIL : ${SELF} : Simulated failure caused by option -fail" rm "$copy_on_disk"/file_1_link_b fi printf "\n${SELF}: Comparing original disk tree and temporary one..." >&2 diff -r "$on_disk" "$copy_on_disk" if test "$?" -ne 0 then echo -e "\nFAIL : ${SELF} : diff -r $on_disk $copy_on_disk reports differences" >&2 echo -e "\nFAIL : ${SELF} : diff -r reports differences" failure=1 else printf "OK" >&2 fi printf "\n${SELF}: Checking for hardlinks being siblings...\n" ls -l "$copy_on_disk"/* x=$(echo $(ls -ld "$copy_on_disk"/*file* | awk '{print $2}')) expected="1 3 3 3 2 2" if test x"$x" = x"$expected" then printf "${SELF}: Checking for hardlinks being siblings done: ok.\n" >&2 else printf "\nFAIL : ${SELF} : Link count of extracted files is not as expected." >&2 printf "\n${SELF}: Expected: $expected" >&2 printf "\n${SELF}: Got : $x\n" >&2 failure=1 fi if test "$acls" = yes then printf "\n${SELF}: Checking ACLs ...\n" >&2 acl_on_disk=$(getfacl "$acl_xattr_test_file" | grep -v '^# file:' | sort) acl_in_copy=$(getfacl "$acl_xattr_copy_file" | grep -v '^# file:' | sort) if test "$acl_on_disk" = "$acl_in_copy" then printf "${SELF}: Checking ACLs done: ok.\n" >&2 else printf "\nFAIL : ${SELF} : ACL mismatch between original and extracted copy\n" printf "\nOriginal:\n${acl_on_disk}\n" printf "\nCopy:\n${acl_in_copy}\n" failure=1 fi fi if test "$xattrs" = yes then printf "\n${SELF}: Checking xattr via getfattr ...\n" >&2 xattr_on_disk=$(getfattr "$acl_xattr_test_file" | \ grep -v '^# file:' | grep -v '^$' | \sort) xattr_in_copy=$(getfattr "$acl_xattr_copy_file" | grep -v '^# file:' | grep -v '^$' | sort) if test "$xattr_on_disk" = "$xattr_in_copy" then num_xattr=$(echo "$xattr_on_disk" | wc -l) printf "${SELF}: Checking xattr done: $num_xattr attributes, ok.\n" >&2 else printf "\nFAIL : ${SELF} : xattr mismatch between original and extracted copy\n" printf "\nOriginal:\n${xattr_on_disk}\n" printf "\nCopy:\n${xattr_in_copy}\n" failure=1 fi elif test "$extattrs" = yes then printf "\n${SELF}: Checking xattr via lsextattr and getextattr ...\n" >&2 lsext_on_disk=$(lsextattr -q user "$acl_xattr_test_file") xattr_on_disk=$(for i in $lsext_on_disk ; do echo $i $(getextattr -q user $i "$acl_xattr_test_file"); done | sort) lsext_in_copy=$(lsextattr -q user "$acl_xattr_copy_file") xattr_in_copy=$(for i in $lsext_in_copy ; do echo $i $(getextattr -q user $i "$acl_xattr_copy_file"); done | sort) if test "$xattr_on_disk" = "$xattr_in_copy" then num_xattr=$(echo "$xattr_on_disk" | wc -l) printf "${SELF}: Checking xattr done: $num_xattr attributes, ok.\n" >&2 else printf "\nFAIL : ${SELF} : xattr mismatch between original and extracted copy\n" printf "\nOriginal:\n${xattr_on_disk}\n" printf "\nCopy:\n${xattr_in_copy}\n" failure=1 fi fi # echo cleanup # Report result echo if test "$failure" = 1 then printf "${SELF}: FAILED" echo exit 1 else printf "${SELF}: Passed" echo fi exit 0