openpkg/lsync

Mon, 28 Jan 2013 17:37:18 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Mon, 28 Jan 2013 17:37:18 +0100
changeset 758
a2c6460cfb16
parent 13
cb59d6afeb61
permissions
-rw-r--r--

Correct socket error reporting improvement with IPv6 portable code,
after helpful recommendation by Saúl Ibarra Corretgé on OSips devlist.

michael@13 1 #!@l_prefix@/lib/openpkg/bash
michael@13 2 ##
michael@13 3 ## lsync -- Access Layer Synchronization Tool
michael@428 4 ## Copyright (c) 2000-2012 OpenPKG GmbH <http://openpkg.com/>
michael@13 5 ##
michael@428 6 ## This software is property of the OpenPKG GmbH, DE MUC HRB 160208.
michael@428 7 ## All rights reserved. Licenses which grant limited permission to use,
michael@428 8 ## copy, modify and distribute this software are available from the
michael@428 9 ## OpenPKG GmbH.
michael@13 10 ##
michael@428 11 ## THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
michael@13 12 ## WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
michael@13 13 ## MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
michael@13 14 ## IN NO EVENT SHALL THE AUTHORS AND COPYRIGHT HOLDERS AND THEIR
michael@13 15 ## CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
michael@13 16 ## SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
michael@13 17 ## LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
michael@13 18 ## USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
michael@13 19 ## ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
michael@13 20 ## OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
michael@13 21 ## OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
michael@13 22 ## SUCH DAMAGE.
michael@13 23 ##
michael@13 24
michael@13 25 ##
michael@13 26 ## filesystem hierarchy configuration
michael@13 27 ##
michael@13 28
michael@13 29 # program name and version/date
michael@13 30 progname="lsync"
michael@13 31 progvers="1.0.4"
michael@13 32 progdate="04-Aug-2001"
michael@13 33
michael@13 34 # root directory
michael@13 35 # (if empty, .lsyncrc files provide default)
michael@13 36 root=""
michael@13 37
michael@13 38 # subdirectory where packages are physically installed
michael@13 39 pkgdir="PKG"
michael@13 40
michael@13 41 # subdirectories which are synchronized between physically
michael@13 42 # installed package areas and access layer
michael@13 43 subdirs="bin,sbin,man,info,include,lib"
michael@13 44
michael@13 45 ##
michael@13 46 ## command line option parsing
michael@13 47 ##
michael@13 48
michael@13 49 # default run-time modes
michael@13 50 nop=0
michael@13 51 quiet=0
michael@13 52 trace=0
michael@13 53 help=''
michael@13 54 init=0
michael@13 55 uninstall=0
michael@13 56 local=0
michael@13 57
michael@13 58 # be aware of .lsyncrc files
michael@13 59 cwd=`pwd`
michael@13 60 while [ 1 ]; do
michael@13 61 if [ -f "$cwd/.lsyncrc" ]; then
michael@13 62 set -- `cat $cwd/.lsyncrc` "$@"
michael@13 63 fi
michael@13 64 [ ".$cwd" = ./ ] && break
michael@13 65 cwd=`echo $cwd | sed -e 's;/[^/]*$;;' -e 's;^$;/;'`
michael@13 66 done
michael@13 67 if [ ".$HOME" != . -a -f "$HOME/.lsyncrc" ]; then
michael@13 68 set -- `cat $HOME/.lsyncrc` "$@"
michael@13 69 fi
michael@13 70
michael@13 71 # iterate over argument line
michael@13 72 for opt
michael@13 73 do
michael@13 74 case $opt in
michael@13 75 -*=*) arg=`echo "$opt" | sed 's/^[-_a-zA-Z0-9]*=//'` ;;
michael@13 76 *) arg='' ;;
michael@13 77 esac
michael@13 78 case $opt in
michael@13 79 -n|--nop ) nop=1 ;;
michael@13 80 -q|--quiet ) quiet=1 ;;
michael@13 81 -t|--trace ) trace=1 ;;
michael@13 82 -v|--version ) version=1 ;;
michael@13 83 -h|--help ) help="Usage" ;;
michael@13 84 -i|--init ) init=1 ;;
michael@13 85 -u|--uninstall ) uninstall=1 ;;
michael@13 86 -l|--local ) local=1 ;;
michael@13 87 --root=* ) root=$arg ;;
michael@13 88 --pkgdir=* ) pkgdir=$arg ;;
michael@13 89 --subdirs=* ) subdirs=$arg ;;
michael@13 90 * ) help="Invalid option \`$opt'"; break ;;
michael@13 91 esac
michael@13 92 done
michael@13 93
michael@13 94 # error or usage message
michael@13 95 if [ ".$help" != . ]; then
michael@13 96 if [ ".$help" != ".Usage" ]; then
michael@13 97 echo "$progname:ERROR: $help" 1>&2
michael@13 98 fi
michael@13 99 cat 1>&2 <<EOT
michael@13 100 Usage: $progname [options]
michael@13 101
michael@13 102 Global options:
michael@13 103 --version, -v display tool version information
michael@13 104 --help, -h display usage information
michael@13 105 --init, -i create an initial directory hierarchy
michael@13 106
michael@13 107 Run-time options:
michael@13 108 --nop, -n perform no filesystem operations
michael@13 109 --quiet, -q display no verbose messages
michael@13 110 --trace, -t display performed filesystem operations
michael@13 111 --local, -l process a local package area only
michael@13 112 --uninstall, -u uninstall all files
michael@13 113
michael@13 114 Filesystem options:
michael@13 115 --root=DIR override root directory
michael@13 116 --pkgdir=DIR override package sub-directory
michael@13 117 --subdirs=DIR override synchronized sub-directories
michael@13 118
michael@13 119 Current configuration:
michael@13 120 root directory: $root
michael@13 121 package root subdir: $pkgdir
michael@13 122 synchronized subdirs: $subdirs
michael@13 123 EOT
michael@13 124 if [ ".$help" != ".Usage" ]; then
michael@13 125 exit 2
michael@13 126 else
michael@13 127 exit 0
michael@13 128 fi
michael@13 129 fi
michael@13 130
michael@13 131 # version information
michael@13 132 if [ ".$version" = .1 ]; then
michael@13 133 echo "$progname $progvers ($progdate)"
michael@13 134 exit 0
michael@13 135 fi
michael@13 136
michael@13 137 # make sure a root directory was found or specified
michael@13 138 if [ ".$root" = . ]; then
michael@13 139 echo "$progname:ERROR: no root directory specified!" 1>&2
michael@13 140 echo "$progname:HINT: use --root=DIR option explicitly on command line" 1>&2
michael@13 141 echo "$progname:HINT: or implicitly inside an .lsyncrc file in your home" 1>&2
michael@13 142 echo "$progname:HINT: directory or in any parent directory." 1>&2
michael@13 143 exit 3
michael@13 144 fi
michael@13 145
michael@13 146 ##
michael@13 147 ## helper functions
michael@13 148 ##
michael@13 149
michael@13 150 display_hd () {
michael@13 151 if [ ".$headline" != . ]; then
michael@13 152 if [ ".$quiet" = .0 ]; then
michael@13 153 echo "$headline"
michael@13 154 fi
michael@13 155 headline=''
michael@13 156 fi
michael@13 157 }
michael@13 158
michael@13 159 display_op () {
michael@13 160 if [ ".$quiet" = .0 ]; then
michael@13 161 echo " $@"
michael@13 162 fi
michael@13 163 }
michael@13 164
michael@13 165 display_warning () {
michael@13 166 echo "$progname:WARNING: $*" 1>&2
michael@13 167 }
michael@13 168
michael@13 169 display_error () {
michael@13 170 echo "$progname:ERROR: $*" 1>&2
michael@13 171 }
michael@13 172
michael@13 173 perform_op () {
michael@13 174 if [ ".$trace" = .1 ]; then
michael@13 175 echo " \$ $@"
michael@13 176 fi
michael@13 177 if [ ".$nop" = .0 ]; then
michael@13 178 eval "$@"
michael@13 179 fi
michael@13 180 }
michael@13 181
michael@13 182 ##
michael@13 183 ## main processing
michael@13 184 ##
michael@13 185
michael@13 186 # extend a "man" subdir to a complete list with subdirs
michael@13 187 # in order to avoid special cases in the loop processing
michael@13 188 manex=''
michael@13 189 if [ ".$init" = .1 ]; then
michael@13 190 manex='man'
michael@13 191 fi
michael@13 192 for i in 1 2 3 4 5 6 7 8; do
michael@13 193 manex="$manex,man/man$i"
michael@13 194 done
michael@13 195 manex=`echo $manex | sed -e 's;^,;;'`
michael@13 196 subdirs=`echo $subdirs | sed -e "s;man;$manex;"`
michael@13 197
michael@13 198 # special processing: create initial hierarchy
michael@13 199 if [ ".$init" = .1 ]; then
michael@13 200 if [ ! -d $root ]; then
michael@13 201 echo "creating $root"
michael@13 202 perform_op "mkdir $root" || exit 1
michael@13 203 fi
michael@13 204 for subdir in $pkgdir `IFS=,; echo $subdirs`; do
michael@13 205 if [ ! -d "$root/$subdir" ]; then
michael@13 206 echo "creating $root/$subdir"
michael@13 207 perform_op "mkdir $root/$subdir" || exit 1
michael@13 208 fi
michael@13 209 done
michael@13 210 exit 0
michael@13 211 fi
michael@13 212
michael@13 213 # make sure the root directory actually exists
michael@13 214 if [ ! -d "$root" ]; then
michael@13 215 display_warning "root directory \`$root' does not exist"
michael@13 216 exit 3
michael@13 217 fi
michael@13 218
michael@13 219 # if processing is restricted to a local package area, pre-determine its name
michael@13 220 if [ ".$local" = .1 ]; then
michael@13 221 realroot=`cd $root; pwd`
michael@13 222 realthis=`pwd`
michael@13 223 pkgname=`expr "$realthis" : "^$realroot/$pkgdir/\\([^/]*\\).*"`
michael@13 224 if [ ".$pkgname" = . ]; then
michael@13 225 display_error "you are not staying under a local package sub-directory"
michael@13 226 exit 3
michael@13 227 fi
michael@13 228 fi
michael@13 229
michael@13 230 # now perform the synchronization for each sub-directory...
michael@13 231 for subdir in `IFS=,; echo $subdirs`; do
michael@13 232 headline="$root/$subdir:"
michael@13 233
michael@13 234 # make sure the subdir actually exists in the access layer
michael@13 235 if [ ! -d "$root/$subdir" ]; then
michael@13 236 display_warning "access layer directory \`$root/$subdir' does not exist"
michael@13 237 continue
michael@13 238 fi
michael@13 239
michael@13 240 #
michael@13 241 # PASS 1: remove dangling symbolic links in access layer
michael@13 242 #
michael@13 243
michael@13 244 # iterate over all symlinks in the access layer subdir
michael@13 245 for link in . `ls "$root/$subdir/" | sed -e "s;^$root/$subdir/*;;g"`; do
michael@13 246 test ".$link" = ".." && continue
michael@13 247
michael@13 248 # determine the target file of the symlink
michael@13 249 target=`ls -l "$root/$subdir/$link" 2>/dev/null | sed -e 's;.*-> *;;'`
michael@13 250 if [ ".$target" = . ]; then
michael@13 251 display_warning "$root/$subdir/$link seems to be not a symbolic link"
michael@13 252 continue
michael@13 253 fi
michael@13 254
michael@13 255 # (optionally) make sure that link target points into local package area
michael@13 256 if [ ".$local" = .1 -a .`expr $target : "../$pkgdir/$pkgname/.*"` = .0 ]; then
michael@13 257 continue
michael@13 258 fi
michael@13 259
michael@13 260 # check whether link is valid, i.e., points to
michael@13 261 # an existing target file or directory
michael@13 262 if [ ".$uninstall" = .1 ] ||\
michael@13 263 [ ! -f "$root/$subdir/$target" -a \
michael@13 264 ! -d "$root/$subdir/$target" ]; then
michael@13 265 # target no longer exists, so remove dangling symlink
michael@13 266 display_hd
michael@13 267 display_op "remove: $link -> $target"
michael@13 268 perform_op "rm -f $root/$subdir/$link"
michael@13 269 fi
michael@13 270 done
michael@13 271
michael@13 272 # if we are uninstalling only, our work is now done
michael@13 273 if [ ".$uninstall" = ".1" ]; then
michael@13 274 continue
michael@13 275 fi
michael@13 276
michael@13 277 #
michael@13 278 # PASS 2: create new symbolic links in access layer
michael@13 279 #
michael@13 280
michael@13 281 # calculate the corresponding reverse directory for the current subdir
michael@13 282 revdir=`echo $subdir | sed -e 's;[^/][^/]*;..;g'`
michael@13 283
michael@13 284 # iterate over all package directories
michael@13 285 for dir in . `ls "$root/$pkgdir/" | sed -e "s;^$root/$pkgdir/*;;g"`; do
michael@13 286 test ".$dir" = ".." && continue
michael@13 287
michael@13 288 # (optionally) make sure that we operate only for the local package area
michael@13 289 if [ ".$local" = .1 -a ".$dir" != ".$pkgname" ]; then
michael@13 290 continue
michael@13 291 fi
michael@13 292
michael@13 293 # skip all directories with appended version numbers
michael@13 294 # in order to support manual versioning of packages
michael@13 295 case $dir in
michael@13 296 *-[0-9]* ) continue ;;
michael@13 297 esac
michael@13 298
michael@13 299 # skip if package directory or package sub-directories has sticky bit set
michael@13 300 if [ ".`ls -l -d $root/$pkgdir/$dir 2>/dev/null | cut -c10`" = .t ] ||\
michael@13 301 [ ".`ls -l -d $root/$pkgdir/$dir/$subdir 2>/dev/null | cut -c10`" = .t ]; then
michael@13 302 continue
michael@13 303 fi
michael@13 304
michael@13 305 # check whether the processed subdir exists in package area
michael@13 306 if [ -d "$root/$pkgdir/$dir/$subdir" ]; then
michael@13 307
michael@13 308 # iterate over all files/directories in package's subdir
michael@13 309 for file in . `ls "$root/$pkgdir/$dir/$subdir/" |\
michael@13 310 sed -e "s;^$root/$pkgdir/$dir/$subdir/*;;g"`; do
michael@13 311 test ".$file" = ".." && continue
michael@13 312
michael@13 313 # calculate the access layer symlink target
michael@13 314 target="$revdir/$pkgdir/$dir/$subdir/$file"
michael@13 315
michael@13 316 # check whether a possibly conflicting symlink exists
michael@13 317 exlink=`ls -l $root/$subdir/$file 2>/dev/null`
michael@13 318 if [ ".$exlink" != . ]; then
michael@13 319 extarget=`echo $exlink | sed -e 's;.*-> *;;'`
michael@13 320 if [ ".$extarget" = . ]; then
michael@13 321 display_warning "$root/$subdir/$file exits, but seems to be not a symbolic link"
michael@13 322 elif [ ".$extarget" != ".$target" ]; then
michael@13 323 display_hd
michael@13 324 display_op "conflict: $file -> $extarget [existing]"
michael@13 325 display_op " $file -> $target [alternative]"
michael@13 326 fi
michael@13 327 continue
michael@13 328 fi
michael@13 329
michael@13 330 # create new symlink in access layer
michael@13 331 display_hd
michael@13 332 display_op "create: $file -> $target"
michael@13 333 perform_op "cd $root/$subdir && ln -s $target $file"
michael@13 334 done
michael@13 335 fi
michael@13 336 done
michael@13 337 done
michael@13 338

mercurial