logo1.gif
                           Welcome to my TWiki wiki
Go

A script for syncing files and directories between two trusted servers (auto ssh login) using inotify. Far from perfect but does the job and a hell lot faster and more responsive than rsync.

Few notes for implementing:

  • Make sure you have inotifywait command on the machine.
  • Create /usr/bin/sys_admin/syncer.list with a directory/file per line.
  • Start debugging :D.

Improved

Fixed some bugs when working on files using winscp and added support for file/dir moves/rename and ownership/permission sync.

Note: required deletion from move operations is delayed until the next update.

  1. #!/bin/bash
  2. # this script requires inotifywait, on debian: apt-get install inotify
  3. PATH="$PATH:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/bin/sys_admin/"
  4. debug=0 # set to 1 for debug only mode, no operation will be performed
  5. files_list="/usr/bin/sys_admin/syncer.list" # dir list, one per line, with trailing slash, no blank lines
  6. target="target_server"
  7. pid_file="/var/run/syncer.pid"
  8. err_log="/var/log/syncer.err"
  9. lock_file="/var/log/syncer.lock"
  10. move_interval=2
  11. check(){
  12. if [ ! -e $files_list ]; then
  13. echo "directoris file not found ($files_list)"
  14. exit 6
  15. fi
  16. if ! ping -c1 $target &>/dev/null; then
  17. echo "target unreacable ($target)"
  18. exit 7
  19. fi
  20. }
  21. create_dir(){
  22. touch $lock_file
  23. attrib_get $1
  24. (($debug)) &&\
  25. echo "ssh $target \"mkdir $1; chmod $perm $1; chown $own $1\";" ||\
  26. ssh $target "mkdir $1; chmod $perm $1; chown $own $" </dev/null
  27. rm -f $lock_file
  28. }
  29. remove_dir(){
  30. touch $lock_file
  31. (($debug)) &&\
  32. echo "ssh $target \"rmdir $1\"" ||\
  33. ssh $target "rmdir $1" </dev/null
  34. rm -f $lock_file
  35. }
  36. move_file(){
  37. touch $lock_file
  38. attrib_get $2
  39. (($debug)) &&\
  40. echo "ssh $target \"mv $1 $2; chmod $perm $2; chown $own $2;\"" ||\
  41. ssh $target "mv $1 $2; chmod $perm $2; chown $own $2;"
  42. rm -f $lock_file
  43. }
  44. remove_file(){
  45. touch $lock_file
  46. (($debug)) &&\
  47. echo "ssh $target \"rm $1\"" ||\
  48. ssh $target "rm $1" </dev/null
  49. rm -f $lock_file
  50. }
  51. copy_file(){
  52. touch $lock_file
  53. attrib_get $1
  54. (($debug)) &&\
  55. echo "scp $1 $target:$1" ||\
  56. scp $1 $target:$1
  57. attrib_do $1
  58. rm -f $lock_file
  59. }
  60. attrib_get(){
  61. touch $lock_file
  62. perm=`stat -c "%a" $1`
  63. own="`stat -c \"%U.%G\" $1`"
  64. rm -f $lock_file
  65. }
  66. attrib_do(){
  67. touch $lock_file
  68. (($debug)) &&\
  69. echo "ssh $target \"chmod $perm $1; chown $own $1\"" ||\
  70. ssh $target "chmod $perm $1; chown $own $1" </dev/null
  71. rm -f $lock_file
  72. }
  73. start(){
  74. /usr/bin/inotifywait -rm --timefmt "%s" --format "%w%f %e %T" -e create -e close_write -e delete -e attrib -e move --fromfile $files_list 2>/dev/null | while read file event time; do
  75. (($debug)) && echo +++++++ $file -- $event -- $time
  76. if [ "x$holder" != "x" ]; then
  77. read stamp tmp_file tmp_event <<< "$holder"
  78. if [ $((`date +%s`-$stamp)) -gt $move_interval ]; then
  79. case $tmp_event in
  80. MOVED_FROM,ISDIR) remove_dir $tmp_file;;
  81. MOVED_FROM) remove_file $tmp_file;;
  82. esac
  83. holder=""
  84. fi
  85. fi
  86. case $event in
  87. CLOSE_WRITE,CLOSE) copy_file $file;;
  88. CREATE) copy_file $file;; # needed for handling winscp
  89. DELETE) remove_file $file;;
  90. CREATE,ISDIR) create_dir $file;;
  91. DELETE,ISDIR) remove_dir $file;;
  92. ATTRIB*) attrib_get $file; attrib_do $file;;
  93. MOVED_FROM*)
  94. if [ "x$holder" == "x" ]; then
  95. holder="`date +%s` $file $event"
  96. (($debug)) && echo "holder: $holder"
  97. else
  98. read stamp tmp_file tmp_event <<< "$holder"
  99. case $tmp_event in
  100. MOVED_FROM,ISDIR) remove_dir $tmp_file;;
  101. MOVED_FROM) remove_file $tmp_file;;
  102. esac
  103. holder="`date +%s` $file $event"
  104. (($debug)) && echo "holder: $holder"
  105. fi
  106. ;;
  107. MOVED_TO*)
  108. if [ "x$holder" == "x" ]; then
  109. case $event in
  110. MOVED_TO,ISDIR) create_dir $file;;
  111. MOVED_TO) copy_file $file;;
  112. esac
  113. else
  114. read stamp tmp_file tmp_event <<< "$holder"
  115. move_file $tmp_file $file
  116. holder=""
  117. fi
  118. ;;
  119. esac
  120. done &> /dev/null
  121. }
  122. stop(){
  123. while true; do
  124. kill `cat $pid_file 2>/dev/null` &>/dev/null && rm -f $pid_file &> /dev/null
  125. if [ ! -e $lock_file ]; then
  126. return 0
  127. else
  128. echo -n "."
  129. sleep 2
  130. fi
  131. done
  132. }
  133. case $1 in
  134. start) echo -n "Starting syncer service... "
  135. if [ -f $pid_file ] && ((`ps awux | grep -v grep | grep -c inotifywait`)); then
  136. echo " already running: pid file found ($pid_file) and an inotifywait process is running"
  137. exit 1
  138. elif [ -f $pid_file ]; then
  139. echo -n "(stale pid file) "
  140. fi
  141. check
  142. start&
  143. pid="$!"
  144. ps --ppid $pid -o pid,cmd | grep inotifywait | awk '{print $1}' > $pid_file
  145. echo "Started"
  146. ;;
  147. stop) echo -n "Stopping syncer service... "
  148. if [ -e $pid_file ]; then
  149. stop
  150. echo "Stopped"
  151. exit 0
  152. else
  153. echo "pid file not found"
  154. exit 2
  155. fi
  156. ;;
  157. restart) $0 stop
  158. $0 start
  159. exit 0
  160. ;;
  161. sync) $0 status; st=$?
  162. ((! $st)) && $0 stop
  163. echo "Running initial sync:"
  164. cat $files_list | while read dir; do
  165. echo -n " Initial sync for $dir"
  166. rsync -ar -e ssh $dir $target:$dir &&\
  167. echo " Done" ||\
  168. echo " Error"
  169. done
  170. ((! $st)) && $0 start
  171. ;;
  172. status) echo -n "Getting status for syncer service... "
  173. pid=`cat $pid_file 2>/dev/null`
  174. if [ -f $pid_file ] && ((`ps awux | grep -v grep | egrep -c "$pid.*inotifywait"`)); then
  175. echo "running (pid $pid)"
  176. exit 0
  177. elif [ -f $pid_file ]; then
  178. echo "not runing (pid file found $pid)"
  179. exit 3
  180. elif ((`ps awux | grep -v grep | egrep -c "$pid.*inotifywait"`)); then
  181. echo "not running (inotifywait procs found)"
  182. exit 4
  183. else
  184. echo "not running"
  185. exit 5
  186. fi
  187. ;;
  188. --help|-h) echo "Syntax: $0 <start|stop|restart|status|sync>"
  189. ;;
  190. *) echo "Syntax error"
  191. $0 -h
  192. ;;
  193. esac

Older version

  1. #!/bin/bash
  2. # this script requires inotifywait
  3. PATH="$PATH:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
  4. debug=0
  5. files_list="/usr/bin/sys_admin/syncer.list"
  6. target="1.1.1.0"
  7. pid_file="/var/run/syncer.pid"
  8. lock_file="/var/run/syncer.lock"
  9. err_log="/var/log/syncer.err"
  10. check(){
  11. if [ ! -e $files_list ]; then
  12. echo "directoris file not found ($files_list)"
  13. exit 3
  14. fi
  15. if ! ping -c1 $target &>/dev/null; then
  16. echo "target unreacable ($target)"
  17. exit 4
  18. fi
  19. }
  20. start(){
  21. /usr/bin/inotifywait -rm --timefmt "%s" --format "%w%f %e %T" -e create -e modify -e delete --fromfile $files_list 2>/dev/null | while read file event time; do
  22. (($debug)) && echo +++++++ $file -- $event -- $time
  23. case $event in
  24. CREATE|MODIFY) (($debug)) && echo "scp $file $target:$file"
  25. touch $lock_file
  26. scp $file $target:$file
  27. rm -f $lock_file
  28. ;;
  29. DELETE) (($debug)) && echo "ssh $target \"rm $file\""
  30. touch $lock_file
  31. ssh $target "rm $file" </dev/null
  32. rm -f $lock_file
  33. ;;
  34. CREATE,ISDIR) (($debug)) && echo "ssh $target \"mkdir $file\""
  35. touch $lock_file
  36. ssh $target "mkdir $file" </dev/null
  37. rm -f $lock_file
  38. ;;
  39. DELETE,ISDIR) (($debug)) && echo "ssh $target \"rmdir $file\""
  40. touch $lock_file
  41. ssh $target "rmdir $file" </dev/null
  42. rm -f $lock_file
  43. ;;
  44. esac
  45. done &> /dev/null #2>&1 | sed "s#^#`date` -- #" > $err_log
  46. }
  47. stop(){
  48. while true; do
  49. kill `cat $pid_file` &>/dev/null && rm -f $pid_file &> /dev/null
  50. if [ ! -e $lock_file ]; then
  51. return 0
  52. else
  53. echo -n "."
  54. sleep 2
  55. fi
  56. done
  57. }
  58. case $1 in
  59. start) echo -n "Starting syncer service... "
  60. if [ -f $pid_file ] && ((`ps awux | grep -v grep | grep -c inotifywait`)); then
  61. echo " already running: pid file found ($pid_file) and an inotifywait process is running"
  62. exit 1
  63. elif [ -f $pid_file ]; then
  64. echo -n "(stale pid file) "
  65. fi
  66. check
  67. start&
  68. pid="$!"
  69. ps --ppid $pid -o pid,cmd | grep inotifywait | awk '{print $1}' > $pid_file
  70. echo "Started"
  71. ;;
  72. stop) echo -n "Stopping syncer service... "
  73. if [ -e $pid_file ]; then
  74. stop
  75. echo "Stopped"
  76. exit 0
  77. else
  78. echo "pid file not found"
  79. exit 2
  80. fi
  81. ;;
  82. restart) $0 stop
  83. $0 start
  84. exit 0
  85. ;;
  86. status) echo -n "Getting status for syncer service... "
  87. pid=`cat $pid_file 2>/dev/null`
  88. if [ -f $pid_file ] && ((`ps awux | grep -v grep | egrep -c "$pid.*inotifywait"`)); then
  89. echo "running (pid $pid)"
  90. exit 0
  91. elif [ -f $pid_file ]; then
  92. echo "not runing (pif file found $pid)"
  93. exit 0
  94. elif ((`ps awux | grep -v grep | egrep -c "$pid.*inotifywait"`)); then
  95. echo "not running (inotifywait procs found)"
  96. exit 0
  97. else
  98. echo "not running"
  99. exit 0
  100. fi
  101. ;;
  102. --help|-h) echo "Syntax: $0 <start|stop|restart|status>"
  103. ;;
  104. *) echo "Syntax error"
  105. $0 -h
  106. ;;
  107. esac

TODO

  • Add help and documentation
  • Add a background proc for MOVED_FROM timeouts

Recent Changes

  • EC2Setup
    Here's my fiddling with AWS, mostly basic usage ...
                07 Jan 2009 - 12:26
  • ToastersInc
    Setup (25 December 2008): Debian Etch ...
                25 Dec 2008 - 16:58
  • AmazonCloudSecurity
    Host security Hardened Linux installations ...
                07 Dec 2008 - 15:54
  • SysAdmins
    Cloud Security Info Howtos (A Sysadmin ...
                07 Dec 2008 - 15:50
  • WebHome
    RSS ATOM One Liners Practical examples of the ...
                23 Nov 2008 - 15:54
  • HomeInternetUplink
    I keep this one running on putty window on my ...
                03 Nov 2008 - 11:21
more changes
Del.icio.us Digg Technorati BlikList Furl Reddit Newsvine Spurl Yahoo Myweb Google Bookmarks Bookmark pagehide
r4 - 25 Oct 2008 - 00:10:16 - ShoKo
This site is powered by the TWiki collaboration platformCopyright © by the contributing authors. All material on this collaboration platform is the property of the contributing authors.
Ideas, requests, problems regarding TWiki? Send feedback
Syndicate this site RSSATOM