Test if a directory is writable by a given UID?
Here's a long, roundabout way of checking.
USER=johndoeDIR=/path/to/somewhere# Use -L to get information about the target of a symlink,# not the link itself, as pointed out in the commentsINFO=( $(stat -L -c "%a %G %U" "$DIR") )PERM=${INFO[0]}GROUP=${INFO[1]}OWNER=${INFO[2]}ACCESS=noif (( ($PERM & 0002) != 0 )); then # Everyone has write access ACCESS=yeselif (( ($PERM & 0020) != 0 )); then # Some group has write access. # Is user in that group? gs=( $(groups $USER) ) for g in "${gs[@]}"; do if [[ $GROUP == $g ]]; then ACCESS=yes break fi doneelif (( ($PERM & 0200) != 0 )); then # The owner has write access. # Does the user own the file? [[ $USER == $OWNER ]] && ACCESS=yesfi
That could do the test:
if read -a dirVals < <(stat -Lc "%U %G %A" $directory) && ( ( [ "$dirVals" == "$wantedUser" ] && [ "${dirVals[2]:2:1}" == "w" ] ) || ( [ "${dirVals[2]:8:1}" == "w" ] ) || ( [ "${dirVals[2]:5:1}" == "w" ] && ( gMember=($(groups $wantedUser)) && [[ "${gMember[*]:2}" =~ ^(.* |)${dirVals[1]}( .*|)$ ]] ) ) ) then echo 'Happy new year!!!' fi
Explanations:
There is only one test (if), no loop and no fork.
+ Nota: as I'v used stat -Lc
instead of stat -c
, this will work for symlinks too!
So condition is if,
- I could successfully read stats of
$directory
and assign them todirVals
, - And (
- ( Owner match And Flag UserWriteable is present )
- or flag Other Writeable is present
- or ( Flag GroupWriteabe is present AND
- I could successfully assing member list of
$wantedUser
togMember
AND - A string built by merging fields 2 to last of
$gMember
will match beginOfSting-Or-something-followed-by-a-space, immediately followed by target's group (${dirVals[1]}
), immediately followed by a-space-followed-by-something-Or-endOfString. )
- I could successfully assing member list of
then echo Happy new year!
As the group's test implie a second fork (And I love to reduce as possible such calls), this is the last test to be done.
Old:
Simply:
su - mysql -c "test -w '$directory'" && echo yesyes
or:
if su - mysql -s /bin/sh -c "test -w '$directory'" ; then echo 'Eureka!' fi
Nota: Warn to enclose first with double-quotes for having $directory
developped!
You can use sudo
to execute the test in your script. For instance:
sudo -u mysql -H sh -c "if [ -w $directory ] ; then echo 'Eureka' ; fi"
To do this, the user executing the script will need sudo
privileges of course.
If you explicitly need the uid instead of the username, you can also use:
sudo -u \#42 -H sh -c "if [ -w $directory ] ; then echo 'Eureka' ; fi"
In this case, 42
is the uid of the mysql
user. Substitute your own value if needed.
UPDATE (to support non-sudo-priviledged users)
To get a bash script to change-users without sudu
would be to require the ability to suid
("switch user id"). This, as pointed out by this answer, is a security restriction that requires a hack to work around. Check this blog for an example of "how to" work around it (I haven't tested/tried it, so I can't confirm it's success).
My recommendation, if possible, would be to write a script in C that is given permission to suid (try chmod 4755 file-name
). Then, you can call setuid(#)
from the C script to set the current user's id and either continue code-execution from the C application, or have it execute a separate bash script that runs whatever commands you need/want. This is also a pretty hacky method, but as far as non-sudo alternatives it's probably one of the easiest (in my opinion).