blob: 3ff997857287c9db642b3ee7c74d1d76f28752b3 [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
. "$PROGRAM_DIR/which.sh"
if ioctl_program_path="`which toolbox`"; then
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
}
set_flags() {
toolbox ioctl -l $flags_size -r -- "$1" $EXT2_IOC_SETFLAGS $2 > /dev/null
}
elif ioctl_program_path="`get_perl_executable_path`"; then
perl_ioctl() {
perl -e 'my $buffer; $buffer = pack(@ARGV[2], splice(@ARGV, 3)) if $#ARGV > 2; my $res; open(HANDLE, "<@ARGV[0]") && ioctl(HANDLE, @ARGV[1], $buffer) || die "@ARGV[0]: $!\n"; close(HANDLE); my @r_buffer = unpack(@ARGV[2], $buffer); exit unless @r_buffer; print STDOUT sprintf("0x%x\n" x @r_buffer, @r_buffer);' -- "$@"
}
get_flags() {
flags="`perl_ioctl "$1" $((EXT2_IOC_GETFLAGS)) L`"
}
set_flags() {
perl_ioctl "$1" $((EXT2_IOC_SETFLAGS)) L "$2" > /dev/null
}
else
echo "Need toolbox(1) or perl(1) to call ioctl(2)" 1>&2
exit 1
fi
elf_ident="`dd if=\"$ioctl_program_path\" bs=1 skip=4 count=2 2> /dev/null`" || exit
case "${elf_ident%?}" in
"`printf '\\001'`")
flags_size=4
;;
"`printf '\\002'`")
flags_size=8
;;
*)
printf "Failed to determine register size of %s\\n" "$ioctl_program_path" 1>&2
exit 1
esac
case "${elf_ident#?}" in
"`printf '\\001'`")
flags_order=little
;;
"`printf '\\002'`")
flags_order=big
;;
*)
printf "Failed to determine byte order of %s\\n" "$ioctl_program_path" 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
;;
*)
[ -z "$f" ] && continue
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
}
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" ] && set_flags "$f" $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