blob: 75ca63d5b631346a095324cc70480ff39e2f27ae [file] [log] [blame] [raw]
#!/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 -sm`" in
"Linux mips"*|"Linux ppc"*|"Linux sparc"*)
EXT2_IOC_GETFLAGS=0x40086601
EXT2_IOC_SETFLAGS=0x80086602
;;
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"
;;
=*)
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 new_flags skip
shift
[ $level -gt 0 ] && [ $# = 1 ] && [ "${1%/\*}" != "$1" ] && [ ! -h "$1" ] && [ ! -e "$1" ] && return
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
skip=
if [ -n "$replace_flags" ]; then
new_flags="$replace_flags"
elif get_flags "$f"; then
new_flags=$(((flags|set_flags)&(~clear_flags)))
[ $new_flags = $((flags)) ] && skip=2
else
#[ -z "$no_fail" ] && r=1
[ -z "$recursive" ] && continue
skip=1
fi
if [ -z "$skip" ] && toolbox ioctl -l $flags_size -r "$f" $EXT2_IOC_SETFLAGS $new_flags || [ -n "$no_fail" ]; then
[ -n "$verbose" ] && printf %s\\n "$f"
elif [ "$skip" != 2 ]; then
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