setfacl utility wrapper

I like the enhancements and the granular control offered by using POSIX ACLS for FreeBSD. But it's a PITA to operate on ACLS, especially if the file system structure is complex. Since I wanted to make my life easyer, I wrote a script to help ACL manipulation. So, I no longer need to set each file's ACLS individually, if I need to grant a specific ACL to a directory and it's contents.
Here it is:

set_acls.sh

#!/bin/sh
# this script is a shorthand for setting POSIX ACLS, a wrapper for setfacl utility
# made by Cazamir Emil
# You can use this script AS IS and change it the way you like it.
# args=`getopt abo: $*`
# -u user / -g group / -s aclspec (r/rw/-)

usage()
{
    echo "How to use: ./set_posix_acls -r -u <user> -g <group> -s|-x <aclspec> <target>"
    echo " -u user : the ACL entry reffers to the specified user, use '-' for the owning user"
    echo " -g group : the ACL entry reffers to the specified group, use '-' for the owning grup"
    echo " -o : the ACL entry reffers to others than the owner user or group"
    echo " You may specify ACL entries for multiple users, groups"
    echo " by specifying multiple -u xxx -g yyy command line arguments"
    echo " -r - the ACL entry will be applied recursive"
    echo " -d - the default ACL entry will be modified too (only for directories)"
    echo " -s aclspec = r|rw|- (read/change/no_access). For the matching directories will be set +x"
    echo " The specified file/directory must exist and it should have an default ACL already set"
    echo "The target can't be specified using wildcards"
    echo "The target specification should be escaped or enclosed between \"\" if it contains spaces"
    echo "Example: ${0} -u - -u webmaster -g wheel -s rw -r -d /usr/local/www"
    echo "You can check the results using getfacl utility"
}

args=`getopt dru:g:os:x: $*`

if [ $? -ne 0 ]; then
    usage;
    exit 2
fi
f_recursive=""
acl_target=""
recursive="NO"
access_spec=""
echo $args
set -- $args

for i
do
    case "$i"
    in
    -r)
        change_recursive="YES"
        shift;;
    -d)
        change_default="YES"
        shift;;
    -u)
        user="$2"; shift;
        if [ "${user}" = "-" ]; then
        user=""
        fi
        if [ "$acl_target" = "" ]; then
            acl_target="u:${user}:PERM_HOLDER"
        else
            acl_target="${acl_target},u:${user}:PERM_HOLDER"
        fi
        shift;;
    -g)
        group="$2"; shift;
        if [ "${group}" = "-" ]; then
        group=""
        fi
        if [ "$acl_target" = "" ]; then
            acl_target="g:${group}:PERM_HOLDER"
        else
            acl_target="${acl_target},g:${group}:PERM_HOLDER"
        fi
        shift;;
    -o)
        if [ "$acl_target" = "" ]; then
            acl_target="o::PERM_HOLDER"
        else
            acl_target="${acl_target},o::PERM_HOLDER"
        fi
        shift;;
    -s)
        access_spec="$2"; shift;
        acl_command="-m"
        shift;;
    -x)
        access_spec="$2"; shift;
        acl_command="-x"
        shift;;
    --)
        shift; break;;
    esac
done

target="$*"

if [ -z "${access_spec}" -o -z "$acl_target" -o -z "${target}" ]; then
    usage;
    exit 2;
fi

if [ ! -f "${target}" -a ! -d "${target}" ]; then
    usage;
    exit 2;
fi

# replace PERM_HOLDER with ${aclspec}

echo "acl_target=${acl_target}"
echo "access_spec=${access_spec}"
if [ "${access_spec}" = "-" ]; then
    access_spec=""
fi

effective_acl_spec_files=`echo ${acl_target} | sed s/PERM_HOLDER/${access_spec}/g`
case ${access_spec} in
    "")
    effective_acl_spec_dirs=`echo ${acl_target} | sed s/PERM_HOLDER/${access_spec}/g`
    ;;
    *)
    effective_acl_spec_dirs=`echo ${acl_target} | sed s/PERM_HOLDER/${access_spec}x/g`
    ;;
esac

echo "change_recursive=${change_recursive}"
echo "change_default=${change_default}"
echo "target=${target}"
if [ -d "$target" ]; then
    target_is_dir="YES"
fi

# commands for modifying a file's ACL
if [ "${target_is_dir}" != "YES" ]; then
    effective_acl_spec=`echo ${acl_target} | sed s/PERM_HOLDER/${access_spec}/g`
    setfacl ${acl_command} ${effective_acl_spec} "${target}"
    exit 0;
fi

# directory, no recursion
if [ "${target_is_dir}" = "YES" -a "${change_recursive}" != "YES" ]; then
    effective_acl_spec=`echo ${acl_target} | sed s/PERM_HOLDER/${access_spec}x/g`
    if [ "${change_default}" = "YES" ]; then
    setfacl -d ${acl_command} ${effective_acl_spec} "${target}"
    fi
    exit 0;
fi

# Directory, recursive
if [ "${target_is_dir}" = "YES" -a "${change_recursive}" = "YES" ]; then
    setfacl ${acl_command} ${effective_acl_spec_dirs} "${target}"
    find "${target}" -type f -exec setfacl ${acl_command} ${effective_acl_spec_files} "{}" \;
    find "${target}" -type d -exec setfacl ${acl_command} ${effective_acl_spec_dirs} "{}" \;
    if [ "${change_default}" = "YES" ]; then
    setfacl -d ${acl_command} ${effective_acl_spec_dirs} "${target}"
    find "${target}" -type d -exec setfacl -d ${acl_command} ${effective_acl_spec_dirs} "{}" \;
    fi
fi


Caveats:

It is not possible to modify a 'directory default ACL' for a specific user or group, unless a previous 'default ACL' has been defined, referring to the owning user, group and other access permissions, similar to the traditional file permissions. This script does not handle this situation, requiring manual setting of the default ACL previously, using a command like:

# setfacl -d -m u::rw,g::r,o::r /data1


If the default ACL do not exist and this script is executed, the following error will appear:
# set_acls.sh -u userid -s rw -r -d web
-u userid -s rw -r -d -- web
acl_target=u:userid:PERM_HOLDER
access_spec=rw
change_recursive=YES
change_default=YES
target=web
setfacl: web: acl_calc_mask() failed: Invalid argument
setfacl: web: failed to set ACL mask
setfacl: web: acl_calc_mask() failed: Invalid argument
setfacl: web: failed to set ACL mask
setfacl: web/dev: acl_calc_mask() failed: Invalid argument
setfacl: web/dev: failed to set ACL mask

The directories created below a directory which already has a default ACL defined, will inherit the ACLs from the default ACL.

Scripts and commands
ċ
set_acls_en.sh
(5k)
Emil Cazamir,
Dec 11, 2009, 2:51 AM
Comments