Merge "Clean up local variable usage - misc functions"

This commit is contained in:
Jenkins
2014-08-02 00:36:17 +00:00
committed by Gerrit Code Review

View File

@@ -49,6 +49,7 @@ function iniadd {
local section=$2 local section=$2
local option=$3 local option=$3
shift 3 shift 3
local values="$(iniget_multiline $file $section $option) $@" local values="$(iniget_multiline $file $section $option) $@"
iniset_multiline $file $section $option $values iniset_multiline $file $section $option $values
$xtrace $xtrace
@@ -62,6 +63,7 @@ function inicomment {
local file=$1 local file=$1
local section=$2 local section=$2
local option=$3 local option=$3
sed -i -e "/^\[$section\]/,/^\[.*\]/ s|^\($option[ \t]*=.*$\)|#\1|" "$file" sed -i -e "/^\[$section\]/,/^\[.*\]/ s|^\($option[ \t]*=.*$\)|#\1|" "$file"
$xtrace $xtrace
} }
@@ -75,6 +77,7 @@ function iniget {
local section=$2 local section=$2
local option=$3 local option=$3
local line local line
line=$(sed -ne "/^\[$section\]/,/^\[.*\]/ { /^$option[ \t]*=/ p; }" "$file") line=$(sed -ne "/^\[$section\]/,/^\[.*\]/ { /^$option[ \t]*=/ p; }" "$file")
echo ${line#*=} echo ${line#*=}
$xtrace $xtrace
@@ -89,6 +92,7 @@ function iniget_multiline {
local section=$2 local section=$2
local option=$3 local option=$3
local values local values
values=$(sed -ne "/^\[$section\]/,/^\[.*\]/ { s/^$option[ \t]*=[ \t]*//gp; }" "$file") values=$(sed -ne "/^\[$section\]/,/^\[.*\]/ { s/^$option[ \t]*=[ \t]*//gp; }" "$file")
echo ${values} echo ${values}
$xtrace $xtrace
@@ -103,6 +107,7 @@ function ini_has_option {
local section=$2 local section=$2
local option=$3 local option=$3
local line local line
line=$(sed -ne "/^\[$section\]/,/^\[.*\]/ { /^$option[ \t]*=/ p; }" "$file") line=$(sed -ne "/^\[$section\]/,/^\[.*\]/ { /^$option[ \t]*=/ p; }" "$file")
$xtrace $xtrace
[ -n "$line" ] [ -n "$line" ]
@@ -145,6 +150,7 @@ function iniset_multiline {
local file=$1 local file=$1
local section=$2 local section=$2
local option=$3 local option=$3
shift 3 shift 3
local values local values
for v in $@; do for v in $@; do
@@ -237,28 +243,28 @@ function die {
# die_if_not_set $LINENO env-var "message" # die_if_not_set $LINENO env-var "message"
function die_if_not_set { function die_if_not_set {
local exitcode=$? local exitcode=$?
FXTRACE=$(set +o | grep xtrace) local xtrace=$(set +o | grep xtrace)
set +o xtrace set +o xtrace
local line=$1; shift local line=$1; shift
local evar=$1; shift local evar=$1; shift
if ! is_set $evar || [ $exitcode != 0 ]; then if ! is_set $evar || [ $exitcode != 0 ]; then
die $line "$*" die $line "$*"
fi fi
$FXTRACE $xtrace
} }
# Prints line number and "message" in error format # Prints line number and "message" in error format
# err $LINENO "message" # err $LINENO "message"
function err { function err {
local exitcode=$? local exitcode=$?
errXTRACE=$(set +o | grep xtrace) local xtrace=$(set +o | grep xtrace)
set +o xtrace set +o xtrace
local msg="[ERROR] ${BASH_SOURCE[2]}:$1 $2" local msg="[ERROR] ${BASH_SOURCE[2]}:$1 $2"
echo $msg 1>&2; echo $msg 1>&2;
if [[ -n ${SCREEN_LOGDIR} ]]; then if [[ -n ${SCREEN_LOGDIR} ]]; then
echo $msg >> "${SCREEN_LOGDIR}/error.log" echo $msg >> "${SCREEN_LOGDIR}/error.log"
fi fi
$errXTRACE $xtrace
return $exitcode return $exitcode
} }
@@ -268,14 +274,14 @@ function err {
# err_if_not_set $LINENO env-var "message" # err_if_not_set $LINENO env-var "message"
function err_if_not_set { function err_if_not_set {
local exitcode=$? local exitcode=$?
errinsXTRACE=$(set +o | grep xtrace) local xtrace=$(set +o | grep xtrace)
set +o xtrace set +o xtrace
local line=$1; shift local line=$1; shift
local evar=$1; shift local evar=$1; shift
if ! is_set $evar || [ $exitcode != 0 ]; then if ! is_set $evar || [ $exitcode != 0 ]; then
err $line "$*" err $line "$*"
fi fi
$errinsXTRACE $xtrace
return $exitcode return $exitcode
} }
@@ -304,14 +310,14 @@ function is_set {
# warn $LINENO "message" # warn $LINENO "message"
function warn { function warn {
local exitcode=$? local exitcode=$?
errXTRACE=$(set +o | grep xtrace) local xtrace=$(set +o | grep xtrace)
set +o xtrace set +o xtrace
local msg="[WARNING] ${BASH_SOURCE[2]}:$1 $2" local msg="[WARNING] ${BASH_SOURCE[2]}:$1 $2"
echo $msg 1>&2; echo $msg 1>&2;
if [[ -n ${SCREEN_LOGDIR} ]]; then if [[ -n ${SCREEN_LOGDIR} ]]; then
echo $msg >> "${SCREEN_LOGDIR}/error.log" echo $msg >> "${SCREEN_LOGDIR}/error.log"
fi fi
$errXTRACE $xtrace
return $exitcode return $exitcode
} }
@@ -322,13 +328,16 @@ function warn {
# Determine OS Vendor, Release and Update # Determine OS Vendor, Release and Update
# Tested with OS/X, Ubuntu, RedHat, CentOS, Fedora # Tested with OS/X, Ubuntu, RedHat, CentOS, Fedora
# Returns results in global variables: # Returns results in global variables:
# os_VENDOR - vendor name # ``os_VENDOR`` - vendor name: ``Ubuntu``, ``Fedora``, etc
# os_RELEASE - release # ``os_RELEASE`` - major release: ``14.04`` (Ubuntu), ``20`` (Fedora)
# os_UPDATE - update # ``os_UPDATE`` - update: ex. the ``5`` in ``RHEL6.5``
# os_PACKAGE - package type # ``os_PACKAGE`` - package type: ``deb`` or ``rpm``
# os_CODENAME - vendor's codename for release # ``os_CODENAME`` - vendor's codename for release: ``snow leopard``, ``trusty``
declare os_VENDOR os_RELEASE os_UPDATE os_PACKAGE os_CODENAME
# GetOSVersion # GetOSVersion
function GetOSVersion { function GetOSVersion {
# Figure out which vendor we are # Figure out which vendor we are
if [[ -x "`which sw_vers 2>/dev/null`" ]]; then if [[ -x "`which sw_vers 2>/dev/null`" ]]; then
# OS/X # OS/X
@@ -418,6 +427,8 @@ function GetOSVersion {
# Translate the OS version values into common nomenclature # Translate the OS version values into common nomenclature
# Sets global ``DISTRO`` from the ``os_*`` values # Sets global ``DISTRO`` from the ``os_*`` values
declare DISTRO
function GetDistro { function GetDistro {
GetOSVersion GetOSVersion
if [[ "$os_VENDOR" =~ (Ubuntu) || "$os_VENDOR" =~ (Debian) ]]; then if [[ "$os_VENDOR" =~ (Ubuntu) || "$os_VENDOR" =~ (Debian) ]]; then
@@ -452,9 +463,7 @@ function GetDistro {
# Utility function for checking machine architecture # Utility function for checking machine architecture
# is_arch arch-type # is_arch arch-type
function is_arch { function is_arch {
ARCH_TYPE=$1 [[ "$(uname -m)" == "$1" ]]
[[ "$(uname -m)" == "$ARCH_TYPE" ]]
} }
# Determine if current distribution is a Fedora-based distribution # Determine if current distribution is a Fedora-based distribution
@@ -661,16 +670,17 @@ function get_default_host_ip {
# Search for an IP unless an explicit is set by ``HOST_IP`` environment variable # Search for an IP unless an explicit is set by ``HOST_IP`` environment variable
if [ -z "$host_ip" -o "$host_ip" == "dhcp" ]; then if [ -z "$host_ip" -o "$host_ip" == "dhcp" ]; then
host_ip="" host_ip=""
host_ips=`LC_ALL=C ip -f inet addr show ${host_ip_iface} | awk '/inet/ {split($2,parts,"/"); print parts[1]}'` local host_ips=$(LC_ALL=C ip -f inet addr show ${host_ip_iface} | awk '/inet/ {split($2,parts,"/"); print parts[1]}')
for IP in $host_ips; do local ip
for ip in $host_ips; do
# Attempt to filter out IP addresses that are part of the fixed and # Attempt to filter out IP addresses that are part of the fixed and
# floating range. Note that this method only works if the ``netaddr`` # floating range. Note that this method only works if the ``netaddr``
# python library is installed. If it is not installed, an error # python library is installed. If it is not installed, an error
# will be printed and the first IP from the interface will be used. # will be printed and the first IP from the interface will be used.
# If that is not correct set ``HOST_IP`` in ``localrc`` to the correct # If that is not correct set ``HOST_IP`` in ``localrc`` to the correct
# address. # address.
if ! (address_in_net $IP $fixed_range || address_in_net $IP $floating_range); then if ! (address_in_net $ip $fixed_range || address_in_net $ip $floating_range); then
host_ip=$IP host_ip=$ip
break; break;
fi fi
done done
@@ -683,6 +693,7 @@ function get_default_host_ip {
# Reverse syntax is supported: -1 is the last field, -2 is second to last, etc. # Reverse syntax is supported: -1 is the last field, -2 is second to last, etc.
# get_field field-number # get_field field-number
function get_field { function get_field {
local data field
while read data; do while read data; do
if [ "$1" -lt 0 ]; then if [ "$1" -lt 0 ]; then
field="(\$(NF$1))" field="(\$(NF$1))"
@@ -725,12 +736,12 @@ function policy_add {
# Usage: get_or_create_user <username> <password> <project> [<email>] # Usage: get_or_create_user <username> <password> <project> [<email>]
function get_or_create_user { function get_or_create_user {
if [[ ! -z "$4" ]]; then if [[ ! -z "$4" ]]; then
local EMAIL="--email=$4" local email="--email=$4"
else else
local EMAIL="" local email=""
fi fi
# Gets user id # Gets user id
USER_ID=$( local user_id=$(
# Gets user id # Gets user id
openstack user show $1 -f value -c id 2>/dev/null || openstack user show $1 -f value -c id 2>/dev/null ||
# Creates new user # Creates new user
@@ -738,63 +749,63 @@ function get_or_create_user {
$1 \ $1 \
--password "$2" \ --password "$2" \
--project $3 \ --project $3 \
$EMAIL \ $email \
-f value -c id -f value -c id
) )
echo $USER_ID echo $user_id
} }
# Gets or creates project # Gets or creates project
# Usage: get_or_create_project <name> # Usage: get_or_create_project <name>
function get_or_create_project { function get_or_create_project {
# Gets project id # Gets project id
PROJECT_ID=$( local project_id=$(
# Gets project id # Gets project id
openstack project show $1 -f value -c id 2>/dev/null || openstack project show $1 -f value -c id 2>/dev/null ||
# Creates new project if not exists # Creates new project if not exists
openstack project create $1 -f value -c id openstack project create $1 -f value -c id
) )
echo $PROJECT_ID echo $project_id
} }
# Gets or creates role # Gets or creates role
# Usage: get_or_create_role <name> # Usage: get_or_create_role <name>
function get_or_create_role { function get_or_create_role {
ROLE_ID=$( local role_id=$(
# Gets role id # Gets role id
openstack role show $1 -f value -c id 2>/dev/null || openstack role show $1 -f value -c id 2>/dev/null ||
# Creates role if not exists # Creates role if not exists
openstack role create $1 -f value -c id openstack role create $1 -f value -c id
) )
echo $ROLE_ID echo $role_id
} }
# Gets or adds user role # Gets or adds user role
# Usage: get_or_add_user_role <role> <user> <project> # Usage: get_or_add_user_role <role> <user> <project>
function get_or_add_user_role { function get_or_add_user_role {
# Gets user role id # Gets user role id
USER_ROLE_ID=$(openstack user role list \ local user_role_id=$(openstack user role list \
$2 \ $2 \
--project $3 \ --project $3 \
--column "ID" \ --column "ID" \
--column "Name" \ --column "Name" \
| grep " $1 " | get_field 1) | grep " $1 " | get_field 1)
if [[ -z "$USER_ROLE_ID" ]]; then if [[ -z "$user_role_id" ]]; then
# Adds role to user # Adds role to user
USER_ROLE_ID=$(openstack role add \ user_role_id=$(openstack role add \
$1 \ $1 \
--user $2 \ --user $2 \
--project $3 \ --project $3 \
| grep " id " | get_field 2) | grep " id " | get_field 2)
fi fi
echo $USER_ROLE_ID echo $user_role_id
} }
# Gets or creates service # Gets or creates service
# Usage: get_or_create_service <name> <type> <description> # Usage: get_or_create_service <name> <type> <description>
function get_or_create_service { function get_or_create_service {
# Gets service id # Gets service id
SERVICE_ID=$( local service_id=$(
# Gets service id # Gets service id
openstack service show $1 -f value -c id 2>/dev/null || openstack service show $1 -f value -c id 2>/dev/null ||
# Creates new service if not exists # Creates new service if not exists
@@ -804,22 +815,22 @@ function get_or_create_service {
--description="$3" \ --description="$3" \
-f value -c id -f value -c id
) )
echo $SERVICE_ID echo $service_id
} }
# Gets or creates endpoint # Gets or creates endpoint
# Usage: get_or_create_endpoint <service> <region> <publicurl> <adminurl> <internalurl> # Usage: get_or_create_endpoint <service> <region> <publicurl> <adminurl> <internalurl>
function get_or_create_endpoint { function get_or_create_endpoint {
# Gets endpoint id # Gets endpoint id
ENDPOINT_ID=$(openstack endpoint list \ local endpoint_id=$(openstack endpoint list \
--column "ID" \ --column "ID" \
--column "Region" \ --column "Region" \
--column "Service Name" \ --column "Service Name" \
| grep " $2 " \ | grep " $2 " \
| grep " $1 " | get_field 1) | grep " $1 " | get_field 1)
if [[ -z "$ENDPOINT_ID" ]]; then if [[ -z "$endpoint_id" ]]; then
# Creates new endpoint # Creates new endpoint
ENDPOINT_ID=$(openstack endpoint create \ endpoint_id=$(openstack endpoint create \
$1 \ $1 \
--region $2 \ --region $2 \
--publicurl $3 \ --publicurl $3 \
@@ -827,9 +838,10 @@ function get_or_create_endpoint {
--internalurl $5 \ --internalurl $5 \
| grep " id " | get_field 2) | grep " id " | get_field 2)
fi fi
echo $ENDPOINT_ID echo $endpoint_id
} }
# Package Functions # Package Functions
# ================= # =================
@@ -990,6 +1002,7 @@ function get_packages {
} }
# Distro-agnostic package installer # Distro-agnostic package installer
# Uses globals ``NO_UPDATE_REPOS``, ``REPOS_UPDATED``, ``RETRY_UPDATE``
# install_package package [package ...] # install_package package [package ...]
function update_package_repo { function update_package_repo {
if [[ "$NO_UPDATE_REPOS" = "True" ]]; then if [[ "$NO_UPDATE_REPOS" = "True" ]]; then
@@ -1090,6 +1103,7 @@ function yum_install {
} }
# zypper wrapper to set arguments correctly # zypper wrapper to set arguments correctly
# Uses globals ``OFFLINE``, ``*_proxy``
# zypper_install package [package ...] # zypper_install package [package ...]
function zypper_install { function zypper_install {
[[ "$OFFLINE" = "True" ]] && return [[ "$OFFLINE" = "True" ]] && return
@@ -1106,7 +1120,8 @@ function zypper_install {
# _run_process() is designed to be backgrounded by run_process() to simulate a # _run_process() is designed to be backgrounded by run_process() to simulate a
# fork. It includes the dirty work of closing extra filehandles and preparing log # fork. It includes the dirty work of closing extra filehandles and preparing log
# files to produce the same logs as screen_it(). The log filename is derived # files to produce the same logs as screen_it(). The log filename is derived
# from the service name and global-and-now-misnamed SCREEN_LOGDIR # from the service name and global-and-now-misnamed ``SCREEN_LOGDIR``
# Uses globals ``CURRENT_LOG_TIME``, ``SCREEN_LOGDIR``
# _run_process service "command-line" # _run_process service "command-line"
function _run_process { function _run_process {
local service=$1 local service=$1
@@ -1132,6 +1147,7 @@ function _run_process {
# Helper to remove the ``*.failure`` files under ``$SERVICE_DIR/$SCREEN_NAME``. # Helper to remove the ``*.failure`` files under ``$SERVICE_DIR/$SCREEN_NAME``.
# This is used for ``service_check`` when all the ``screen_it`` are called finished # This is used for ``service_check`` when all the ``screen_it`` are called finished
# Uses globals ``SCREEN_NAME``, ``SERVICE_DIR``
# init_service_check # init_service_check
function init_service_check { function init_service_check {
SCREEN_NAME=${SCREEN_NAME:-stack} SCREEN_NAME=${SCREEN_NAME:-stack}
@@ -1149,15 +1165,15 @@ function init_service_check {
function is_running { function is_running {
local name=$1 local name=$1
ps auxw | grep -v grep | grep ${name} > /dev/null ps auxw | grep -v grep | grep ${name} > /dev/null
RC=$? local exitcode=$?
# some times I really hate bash reverse binary logic # some times I really hate bash reverse binary logic
return $RC return $exitcode
} }
# run_process() launches a child process that closes all file descriptors and # run_process() launches a child process that closes all file descriptors and
# then exec's the passed in command. This is meant to duplicate the semantics # then exec's the passed in command. This is meant to duplicate the semantics
# of screen_it() without screen. PIDs are written to # of screen_it() without screen. PIDs are written to
# $SERVICE_DIR/$SCREEN_NAME/$service.pid # ``$SERVICE_DIR/$SCREEN_NAME/$service.pid``
# run_process service "command-line" # run_process service "command-line"
function run_process { function run_process {
local service=$1 local service=$1
@@ -1169,6 +1185,8 @@ function run_process {
} }
# Helper to launch a service in a named screen # Helper to launch a service in a named screen
# Uses globals ``CURRENT_LOG_TIME``, ``SCREEN_NAME``, ``SCREEN_LOGDIR``,
# ``SERVICE_DIR``, ``USE_SCREEN``
# screen_it service "command-line" # screen_it service "command-line"
function screen_it { function screen_it {
SCREEN_NAME=${SCREEN_NAME:-stack} SCREEN_NAME=${SCREEN_NAME:-stack}
@@ -1211,6 +1229,7 @@ function screen_it {
} }
# Screen rc file builder # Screen rc file builder
# Uses globals ``SCREEN_NAME``, ``SCREENRC``
# screen_rc service "command-line" # screen_rc service "command-line"
function screen_rc { function screen_rc {
SCREEN_NAME=${SCREEN_NAME:-stack} SCREEN_NAME=${SCREEN_NAME:-stack}
@@ -1241,6 +1260,7 @@ function screen_rc {
# If a PID is available use it, kill the whole process group via TERM # If a PID is available use it, kill the whole process group via TERM
# If screen is being used kill the screen window; this will catch processes # If screen is being used kill the screen window; this will catch processes
# that did not leave a PID behind # that did not leave a PID behind
# Uses globals ``SCREEN_NAME``, ``SERVICE_DIR``, ``USE_SCREEN``
# screen_stop service # screen_stop service
function screen_stop { function screen_stop {
SCREEN_NAME=${SCREEN_NAME:-stack} SCREEN_NAME=${SCREEN_NAME:-stack}
@@ -1261,6 +1281,7 @@ function screen_stop {
} }
# Helper to get the status of each running service # Helper to get the status of each running service
# Uses globals ``SCREEN_NAME``, ``SERVICE_DIR``
# service_check # service_check
function service_check { function service_check {
local service local service
@@ -1330,18 +1351,19 @@ function pip_install {
fi fi
if [[ $TRACK_DEPENDS = True ]]; then if [[ $TRACK_DEPENDS = True ]]; then
source $DEST/.venv/bin/activate source $DEST/.venv/bin/activate
CMD_PIP=$DEST/.venv/bin/pip local cmd_pip=$DEST/.venv/bin/pip
SUDO_PIP="env" local sudo_pip="env"
else else
SUDO_PIP="sudo" local cmd_pip=$(get_pip_command)
CMD_PIP=$(get_pip_command) local sudo_pip="sudo"
fi fi
# Mirror option not needed anymore because pypi has CDN available, # Mirror option not needed anymore because pypi has CDN available,
# but it's useful in certain circumstances # but it's useful in certain circumstances
PIP_USE_MIRRORS=${PIP_USE_MIRRORS:-False} PIP_USE_MIRRORS=${PIP_USE_MIRRORS:-False}
local pip_mirror_opt=""
if [[ "$PIP_USE_MIRRORS" != "False" ]]; then if [[ "$PIP_USE_MIRRORS" != "False" ]]; then
PIP_MIRROR_OPT="--use-mirrors" pip_mirror_opt="--use-mirrors"
fi fi
# pip < 1.4 has a bug where it will use an already existing build # pip < 1.4 has a bug where it will use an already existing build
@@ -1354,13 +1376,13 @@ function pip_install {
local pip_build_tmp=$(mktemp --tmpdir -d pip-build.XXXXX) local pip_build_tmp=$(mktemp --tmpdir -d pip-build.XXXXX)
$xtrace $xtrace
$SUDO_PIP PIP_DOWNLOAD_CACHE=${PIP_DOWNLOAD_CACHE:-/var/cache/pip} \ $sudo_pip PIP_DOWNLOAD_CACHE=${PIP_DOWNLOAD_CACHE:-/var/cache/pip} \
http_proxy=$http_proxy \ http_proxy=$http_proxy \
https_proxy=$https_proxy \ https_proxy=$https_proxy \
no_proxy=$no_proxy \ no_proxy=$no_proxy \
$CMD_PIP install --build=${pip_build_tmp} \ $cmd_pip install --build=${pip_build_tmp} \
$PIP_MIRROR_OPT $@ \ $pip_mirror_opt $@ \
&& $SUDO_PIP rm -rf ${pip_build_tmp} && $sudo_pip rm -rf ${pip_build_tmp}
} }
# this should be used if you want to install globally, all libraries should # this should be used if you want to install globally, all libraries should
@@ -1395,7 +1417,7 @@ function setup_package_with_req_sync {
if [[ $update_requirements != "changed" ]]; then if [[ $update_requirements != "changed" ]]; then
(cd $REQUIREMENTS_DIR; \ (cd $REQUIREMENTS_DIR; \
$SUDO_CMD python update.py $project_dir) python update.py $project_dir)
fi fi
setup_package $project_dir $flags setup_package $project_dir $flags
@@ -1502,6 +1524,7 @@ function disable_service {
# enable_service service [service ...] # enable_service service [service ...]
function enable_service { function enable_service {
local tmpsvcs="${ENABLED_SERVICES}" local tmpsvcs="${ENABLED_SERVICES}"
local service
for service in $@; do for service in $@; do
if ! is_service_enabled $service; then if ! is_service_enabled $service; then
tmpsvcs+=",$service" tmpsvcs+=",$service"
@@ -1538,7 +1561,8 @@ function is_service_enabled {
local xtrace=$(set +o | grep xtrace) local xtrace=$(set +o | grep xtrace)
set +o xtrace set +o xtrace
local enabled=1 local enabled=1
services=$@ local services=$@
local service
for service in ${services}; do for service in ${services}; do
[[ ,${ENABLED_SERVICES}, =~ ,${service}, ]] && enabled=0 [[ ,${ENABLED_SERVICES}, =~ ,${service}, ]] && enabled=0
@@ -1574,8 +1598,9 @@ function is_service_enabled {
function use_exclusive_service { function use_exclusive_service {
local options=${!1} local options=${!1}
local selection=$3 local selection=$3
out=$2 local out=$2
[ -z $selection ] || [[ ! "$options" =~ "$selection" ]] && return 1 [ -z $selection ] || [[ ! "$options" =~ "$selection" ]] && return 1
local opt
for opt in $options;do for opt in $options;do
[[ "$opt" = "$selection" ]] && enable_service $opt || disable_service $opt [[ "$opt" = "$selection" ]] && enable_service $opt || disable_service $opt
done done
@@ -1599,7 +1624,7 @@ function _safe_permission_operation {
let last="${#args[*]} - 1" let last="${#args[*]} - 1"
dir_to_check=${args[$last]} local dir_to_check=${args[$last]}
if [ ! -d "$dir_to_check" ]; then if [ ! -d "$dir_to_check" ]; then
dir_to_check=`dirname "$dir_to_check"` dir_to_check=`dirname "$dir_to_check"`
fi fi