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