| #!/bin/sh |
| |
| # Copyright 2015-2023 Rivoreo |
| |
| # Permission is hereby granted, free of charge, to any person obtaining a copy |
| # of this software and associated documentation files (the "Software"), to |
| # deal in the Software without restriction, including without limitation the |
| # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or |
| # sell copies of the Software, and to permit persons to whom the Software is |
| # furnished to do so, subject to the following conditions: |
| |
| # The above copyright notice and this permission notice shall be included in |
| # all copies or substantial portions of the Software. |
| |
| # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
| # COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, |
| # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR |
| # IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
| # SOFTWARE. |
| |
| |
| PROGRAM_DIR="`dirname \"$0\"`" |
| . "$PROGRAM_DIR/chflags.common.sh" |
| |
| case "`uname -s`" in |
| Linux) |
| EXT2_IOC_GETFLAGS=0x80086601 |
| EXT2_IOC_SETFLAGS=0x40086602 |
| ;; |
| #*FreeBSD) |
| # EXT2_IOC_GETFLAGS=0x40086601 |
| # EXT2_IOC_SETFLAGS=0x80086602 |
| # ;; |
| *) |
| echo "Kernel type not supported" 1>&2 |
| exit 1 |
| esac |
| |
| EXT2_IMMUTABLE_FL=0x00000010 |
| EXT2_APPEND_FL=0x00000020 |
| |
| if ! toolbox_path="`which toolbox`"; then |
| echo "toolbox(1) not available" 1>&2 |
| return 1 |
| fi |
| |
| elf_ident="`dd if=\"$toolbox_path\" bs=1 skip=4 count=2 2> /dev/null`" |
| case "${elf_ident%?}" in |
| "`printf '\\001'`") |
| flags_size=4 |
| ;; |
| "`printf '\\002'`") |
| flags_size=8 |
| ;; |
| *) |
| echo "Failed to determine register size of toolbox(1)" 1>&2 |
| exit 1 |
| esac |
| case "${elf_ident#?}" in |
| "`printf '\\001'`") |
| flags_order=little |
| ;; |
| "`printf '\\002'`") |
| flags_order=big |
| ;; |
| *) |
| echo "Failed to determine byte order of toolbox(1)" 1>&2 |
| exit 1 |
| esac |
| |
| parse_flags_string() { |
| local ORIG_IFS="$IFS" |
| IFS=, |
| set -- $1 |
| IFS="$ORIG_IFS" |
| set_flags=0 |
| clear_flags=0 |
| local f set_var_name clear_var_name |
| for f in "$@"; do |
| fn="${f#no}" |
| if [ "$fn" = "$f" ]; then |
| set_var_name=set_flags |
| clear_var_name=clear_flags |
| else |
| set_var_name=clear_flags |
| clear_var_name=set_flags |
| fi |
| case "$fn" in |
| simmutable) |
| f=$EXT2_IMMUTABLE_FL |
| ;; |
| sappend) |
| f=$EXT2_APPEND_FL |
| ;; |
| *) |
| printf 'chflags: invalid flag: %s.\n' "$f" 1>&2 |
| return 1 |
| esac |
| eval "$set_var_name=\$(($set_var_name|f))" |
| eval "$clear_var_name=\$(($clear_var_name&(~f)))" |
| done |
| } |
| |
| get_flags() { |
| local v |
| v="`toolbox ioctl -l $flags_size -r \"$1\" $EXT2_IOC_GETFLAGS`" || return |
| v="${v#* |
| }" |
| flags= |
| for b in ${v#*:}; do |
| b=${b#0x} |
| [ "$flags_order" = big ] && flags=$flags$b || flags=$b$flags |
| done |
| flags=0x$flags |
| } |
| |
| case "$1" in |
| 0*) |
| replace_flags="$1" |
| flags_s= |
| ;; |
| =*) |
| parse_flags_string "$1" || exit 255 |
| replace_flags="$set_flags" |
| ;; |
| *) |
| replace_flags= |
| parse_flags_string "$1" || exit 255 |
| ;; |
| esac |
| shift |
| [ -n "$no_fail" ] && exec 2> /dev/null |
| r=0 |
| chflags_loop() { |
| local level=$1 f |
| shift |
| for f in "$@"; do |
| if [ -n "$no_follow" ] && [ -h "$f" ]; then |
| # Won't be able to ioctl(2) a symbolic link itself, skipping |
| if [ -z "$no_fail" ]; then |
| printf 'chflags: %s: Not following symbolic link\n' "$f" 1>&2 |
| r=1 |
| fi |
| continue |
| fi |
| if [ -n "$replace_flags" ]; then |
| new_flags="$replace_flags" |
| else |
| if ! get_flags "$f"; then |
| [ -z "$no_fail" ] && r=1 |
| continue |
| fi |
| new_flags=$(((flags|set_flags)&(~clear_flags))) |
| fi |
| if toolbox ioctl -l $flags_size -r "$f" $EXT2_IOC_SETFLAGS $new_flags || [ -n "$no_fail" ]; then |
| [ -n "$verbose" ] && printf %s\\n "$f" |
| else |
| r=1 |
| fi |
| if [ -n "$recursive" ]; then |
| case "$recursive_follow" in |
| never) |
| [ -h "$f" ] && continue |
| ;; |
| explict) |
| [ $level -gt 0 ] && [ -h "$f" ] && continue |
| ;; |
| esac |
| [ -d "$f" ] && chflags_loop $((level+1)) "$f"/* |
| fi |
| done |
| } |
| chflags_loop 0 "$@" |
| exit $r |