0

Still learning and I'm getting lost with IFS=

#!/bin/bash
inotifywait -m -r --excludei '(.txt$|.old$|.swp$|.swx$|.swpx$|.zip$)' /path/to/watch -e create |
    while read path action file; do
        cd $path
        USER="$(stat -c %U $file)"
        echo "To: User <[email protected]>
CC: Support <[email protected]>
From: $USER <[email protected]>
Subject: $USER has Uploaded a new File

The user '$USER' uploaded the file '$file' to '$path'" >  /mnt/remote/ian/temp2.txt
    cat /path/to/temp/file.txt | ssmtp [email protected]
    rm /path/to/temp/file.txt
done

This was my first ever script and it works great as long as there are no spaces in the the file names that get uploaded. I've read some scripts that use IFS= 'whatever' to define the field separators but I don't want to mess around with this while it's in production; it works, but it annoys me when I can't get the username of the user who uploaded the file. Please give me a hint.

9
  • Crossposting: serverfault.com/q/679424/234750 Commented Mar 30, 2015 at 21:28
  • Since inotifywait's format strings don't support \0 -- the only character which can't legally exist in a filename -- there literally isn't a 100%-reliable solution possible. Commented Mar 30, 2015 at 21:33
  • @CharlesDuffy that's what I was scared of... Commented Mar 30, 2015 at 21:34
  • BTW, note how I'm using double-quotes around any expansion of "$file" or "$path"? That's essential to avoid bugs; shellcheck.net will point out any places where you're skipping it. Commented Mar 30, 2015 at 21:38
  • 1
    BTW, are you sure you want create (flagging when a file is created, but not necessarily when content is done being written to it), as opposed to close_write? Commented Apr 1, 2015 at 15:25

1 Answer 1

1

This can be broken by an attacker who knows your implementation and wants to spoof arbitrary data (by creating filenames with newlines), but it's a rough first draft:

while IFS= read -r -d $'\n' path && IFS= read -r -d $'\n' file; do
    user=$(stat -c %U "$file")
    printf 'File %q created by %q in %q\n' "$file" "$user" "$path"
done < <(inotifywait --format $'%w\n%f\n' ~/tmp -r -e create)

I'd strongly suggest filing a ticket with upstream inotifytools requesting the ability use \0 in format strings.


Incidentally, this has already been brought up on the inotify-tools mailing list, where Stephane Chazelas offered a workaround:

nl="
"
inotifywait --syslog -e close_write -mr /tmp --format '%f///' |
  while IFS= read -r file; do
    while :; do
      case $file in
        (*///) file=${file%///}; break
      esac
      IFS= read -r extra || exit
      file=$file$nl$extra
    done

    something with "$file"

  done
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.