aubrsync 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304
  1. #!/bin/sh
  2. # Copyright (C) 2005-2009 Junjiro Okajima
  3. #
  4. # This program, aufs is free software; you can redistribute it and/or modify
  5. # it under the terms of the GNU General Public License as published by
  6. # the Free Software Foundation; either version 2 of the License, or
  7. # (at your option) any later version.
  8. #
  9. # This program is distributed in the hope that it will be useful,
  10. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. # GNU General Public License for more details.
  13. #
  14. # You should have received a copy of the GNU General Public License
  15. # along with this program; if not, write to the Free Software
  16. # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  17. #
  18. # The development of this script is sponcered by ASUSTek Computer Inc.
  19. # Kindly they agreed that I keep my aufs work as free software as it has
  20. # been.
  21. #
  22. set -eu
  23. #set -x
  24. me=$(basename $0)
  25. EEcho() # str
  26. {
  27. echo ${me}: $@ 1>&2
  28. }
  29. f=/sbin/mount.aufs
  30. test ! -x $f && EEcho $f is not installed && exit 1
  31. # special handling for backward compatibility.
  32. #
  33. # aufs in the donated eeepc is aufs1 20080211 without CONFIG_AUFS_COMPAT.
  34. # /etc/default/aufs was introduced in aufs1 20080922.
  35. # shwh/noshwh was introduced in aufs1 20080310 with CONFIG_AUFS_SHWH.
  36. # noshwh became always available regardless CONFIG_AUFS_SHWH in aufs1 20081117.
  37. noshwh=1
  38. AUFS_VERSION=20080211
  39. f=/etc/default/aufs
  40. if [ -s $f ]
  41. then
  42. . $f
  43. else
  44. echo ${me}: warning, broken $f, assuming aufs is $AUFS_VERSION
  45. f=/usr/lib/aufs.shlib
  46. test ! -s $f && EEcho $f is not installed && exit 1
  47. . $f
  48. case $AUFS_VERSION in
  49. 200*) # aufs1
  50. test $AUFS_VERSION -lt 20081117 && noshwh=0
  51. ;;
  52. esac
  53. AUFS_SUPER_MAGIC=1635083891
  54. AUFS_SUPER_MAGIC_HEX=0x61756673
  55. AUFS_WH_PFX=.wh.
  56. AUFS_WH_PFX2=.wh..wh.
  57. AUFS_WH_DIROPQ=.wh..wh..opq
  58. fi
  59. ########################################
  60. _Rsync="rsync --exclude=lost+found"
  61. Rsync="$_Rsync -aHSx --devices --specials --delete-before"
  62. Copy="$Rsync"
  63. Move="$Copy"
  64. RsyncWh="$_Rsync -ptgoHx"
  65. FindForRm() # rw
  66. {
  67. echo "find \"$1\" -xdev -depth \(
  68. \( ! -type d
  69. \( -name $AUFS_WH_DIROPQ
  70. -o ! -name ${AUFS_WH_PFX2}\* \) \)
  71. -o \( -type d
  72. ! -name ${AUFS_WH_PFX2}\*
  73. ! -wholename \"$1\"
  74. ! -wholename \"$1/lost+found\" \)
  75. \) -print0"
  76. }
  77. MoveWh() # rw ro+wh
  78. {
  79. cd "$1"
  80. find . -xdev -name ${AUFS_WH_PFX}\* ! -name ${AUFS_WH_PFX2}\* \
  81. -printf '%P\n' |
  82. while read wh
  83. do
  84. f=$(echo "$wh" | sed -e '
  85. s/^'${AUFS_WH_PFX}'//
  86. t
  87. s:/'${AUFS_WH_PFX}':/:
  88. ')
  89. test -e "$dst/$f" || echo "$wh"
  90. done |
  91. # -v
  92. $RsyncWh --files-from=- ./ "$2"
  93. cd "$OLDPWD"
  94. }
  95. copy()
  96. {
  97. $Copy $@ "$mntpnt"/ "$dst"
  98. }
  99. _move()
  100. {
  101. set +x
  102. test $hinotify -ne 1 && echo ${me}: warning, -i is not specified
  103. src_is_nfs=0
  104. test $(stat -f -c %T "$src") = nfs && src_is_nfs=1
  105. set $quiet
  106. $Move $@ &&
  107. eval $(FindForRm "$src") |
  108. {
  109. if [ $src_is_nfs -eq 1 ]
  110. then
  111. mount -o remount "$mntpnt"
  112. mount -o remount "$src"
  113. fi
  114. xargs -r0 rm -fr #-v
  115. }
  116. }
  117. move()
  118. {
  119. _move $@ "$mntpnt"/ "$dst"
  120. }
  121. move_with_wh()
  122. {
  123. {
  124. set +x
  125. MoveWh "$src" "$dst"
  126. set $quiet
  127. } &&
  128. move --exclude=${AUFS_WH_PFX}\*
  129. }
  130. # backward compatibility
  131. move_w()
  132. {
  133. move_with_wh $@
  134. }
  135. Usage()
  136. {
  137. t=$(FindForRm src_branch | sed -e '
  138. s/"//g
  139. $b
  140. s/$/ \\/')
  141. cat <<- EOF
  142. $me Options move | move_with_wh | copy \\
  143. mntpnt src_branch dst_branch [ options for rsync ]
  144. generic form:
  145. $me [ -w | --wh ] [ -i | --inotify ] Options \\
  146. mntpnt cmd [ parameters for cmd ]
  147. Options:
  148. [ -n | --dry_run ]
  149. [ -q | --quiet ]
  150. The dst_branch must be mounted as writable.
  151. During the operation, the mntpnt is set readonly.
  152. If you are opening a file for writing on the writable branch,
  153. you need to close the file before invoking this script.
  154. The -w or --wh option requires CONFIG_AUFS_SHWH enabled.
  155. The -i or --inotify option requires CONFIG_AUFS_HINOTIFY enabled.
  156. 'copy' is a shortcut for
  157. $me mntpnt \\
  158. $Copy mntpnt/ dst_branch
  159. 'move' is a shortcut for
  160. $me mntpnt \\
  161. "$Move \\
  162. mntpnt/ dst_branch && \\
  163. $t |\\
  164. xargs -r0 rm -fr"
  165. Note: in most cases, you will need '-i' option, and
  166. find(1) is invoked by $me only when rsync(1)
  167. succeded.
  168. 'move_with_wh' is a simple variation of 'move' which moves
  169. whiteouts separately before the actual 'move'.
  170. If you execute this script under linux-2.6.24 or earlier, the
  171. kernel may produce a harmless warning "inotify.c:NNN
  172. set_dentry_child_flags()". The message was already removed in
  173. linux-2.6.25.
  174. examples:
  175. - Copy and reflect all the modification (modifed files, newly
  176. created and removed ones) in the upper branch to the lower
  177. branch. This operation is for aufs which has only 2 branches,
  178. and mainly for a system shutdown script.
  179. All files on the upper branch remain.
  180. $ sudo $me copy /your/aufs /your/upper_branch /your/lower_branch
  181. - Like above (2 branches), move and reflect all modifications
  182. from upper to lower. Almost all files on the upper branch will
  183. be removed. You can still use this aufs after the
  184. operation. But the inode number may be changed. If your
  185. application which depends upon the inode number was running at
  186. that time, it may not work correctly.
  187. $ sudo $me move /your/aufs /your/upper_branch /your/lower_branch
  188. EOF
  189. # - Like above (2 branches), generate a new middle layer like a
  190. # snapshot including whiteouts and make the upper_branch almost
  191. # empty, but untouch the lower_branch.
  192. #
  193. # $ img=/hda1/a.ext2
  194. # $ dd if=/dev/zero of=\$img bs=4k count=1k
  195. # $ mkfs -t ext2 -F \$img
  196. # $ sudo mount -o rw,loop \$img /your/new_branch
  197. # $ sudo mount -o remount,ins:1:/your/new_branch=ro+wh /your/aufs
  198. # $ sudo $me _move /your/aufs /your/upper_branch /your/lower_branch \\
  199. # "--remove-source-files \\
  200. # --exclude=$AUFS_WH_BASE \\
  201. # --exclude=$AUFS_WH_PLINKDIR \\
  202. # --exclude=$AUFS_WH_TMPDIR \\
  203. # /your/upper_branch/ /your/new_branch; \\
  204. # mount -o remount,ro /your/new_branch"
  205. # EOF
  206. }
  207. ########################################
  208. wh=0
  209. hinotify=0
  210. quiet=-x
  211. dry_run=
  212. cmd=
  213. cmd_opts=
  214. for i
  215. do
  216. case $i in
  217. -w|--wh) wh=1;;
  218. -i|--inotify) hinotify=1;;
  219. -n|--dry_run) dry_run=echo;;
  220. -q|--quiet) quiet=+x;;
  221. -h|--help) Usage; exit 0;;
  222. --) shift; break;;
  223. *) break;;
  224. esac
  225. shift
  226. done
  227. test $# -lt 2 && Usage 1>&2 && exit 1
  228. case "$1" in
  229. _move|move|copy|move_w|move_with_wh)
  230. test $# -lt 4 && Usage 1>&2 && exit 1
  231. cmd=$1
  232. SetDir mntpnt "$2"
  233. SetDir src "$3"
  234. SetDir dst "$4"
  235. shift 4
  236. wh=0
  237. ;;
  238. *)
  239. SetDir mntpnt "$1"
  240. cmd="$2"
  241. shift 2
  242. ;;
  243. esac
  244. cmd_opts="$@"
  245. case $(stat -f -c %T "$mntpnt") in
  246. aufs|UNKNOWN*${AUFS_SUPER_MAGIC_HEX}*) ;;
  247. *)
  248. EEcho "$mntpnt" is not aufs
  249. exit 1
  250. ;;
  251. esac
  252. cur_opts=$(MntOpts "$mntpnt")
  253. test ! "$cur_opts" &&
  254. EEcho bad /proc/mounts or "$mntpnt" is not mounted &&
  255. exit 1
  256. cur_opts="udba=reval,noshwh,$cur_opts"
  257. test $noshwh -eq 0 && cur_opts=$(echo $cur_opts | sed -e 's/,noshwh//')
  258. # force flushing the pusedo-links
  259. tmp_opts="remount,ro,udba=reval,noshwh"
  260. test $noshwh -eq 0 && tmp_opts=$(echo $tmp_opts | sed -e 's/,noshwh//')
  261. test $wh -eq 1 && tmp_opts="$tmp_opts,shwh"
  262. test $hinotify -eq 1 && tmp_opts="$tmp_opts,udba=inotify"
  263. # here we go
  264. trap "$dry_run mount -o remount,$cur_opts \"$mntpnt\"" EXIT
  265. set $quiet
  266. $dry_run mount -o $tmp_opts "$mntpnt"
  267. eval "$dry_run $cmd $cmd_opts"