Initial Revision
[ohcount] / test / detect_files / bourne_again_script
1 #!/bin/bash
2
3 # findbl - find bad symbolic links (dangling, malformed etc.)
4 # Copyright © 2000-2006 by Pádraig Brady <P@draigBrady.com>.
5 #
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 2 of the License, or
9 # any later version.
10 #
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14 # See the GNU General Public License for more details,
15 # which is available at www.gnu.org
16
17
18 # Notes:
19 #
20 # By default (-d) it reports dangling (stale) links. Note invalid
21 # pathnames are reported as stale by this script.
22 #
23 # To report redundant info in symbolic links, such as multiple
24 # consequtive ////'s or /./././ etc. you specify the -n option.
25 # Note that fixing this won't give you back any disk space as
26 # the link will take a disk block anyway, but malformed links
27 # like this could cause other programs problems.
28 #
29 # To report all absolute links in the specified path(s), use
30 # the -A option. This can help when you want to move a tree
31 # around in the filesystem.
32 #
33 # Likewise the -l option reports all relative links in the
34 # specified paths.
35 #
36 # The -s option reports suspect absolute links. I.E. absolute
37 # links to files in the same directory as the link or below.
38 # TODO: support finding suspect relative link also. For e.g.:
39 # /etc/file.lnk ->../etc/file (python and abspath may be needed?)
40 #
41 # Note if this output passed to xargs or rm etc.
42 # then filenames with spaces will cause problems
43 #
44 # Should insert list of filesystems that support links
45 # or specify -xdev or something
46 #
47 # auto tidying of messy links could use tr -s / to squeeze consequtive /'s
48 # and sed s//..///d to remove /../
49
50 script_dir=`dirname $0`                #directory of this script
51 script_dir=`readlink -f "$script_dir"` #Make sure absolute path
52
53 . $script_dir/supprt/fslver
54
55 Usage() {
56         ProgName=`basename "$0"`
57         echo "find \"Bad\" symbolic Links.
58 Usage: $ProgName [-d] [-s] [-l] [-s] [-n] [[-r] [-f] paths(s) ...]
59
60 These options are mutually exclusive (i.e. only the last one takes effect).
61 -d Dangling (or stale) links. This is the default mode
62 -s Suspect links (absolute links to paths within or below the link's directory)
63 -l all reLative links
64 -A all Absolute links
65 -n reduNdant info in links (/././. ///// /../ etc.)
66
67 If no path(s) specified, then the current directory is assumed.
68
69 e.g. find dangling links in "library directories":
70 findbl \`getffl\`"
71         exit
72 }
73
74 mode="dangling" #default
75
76 # Note must be careful with expressions (which are currently
77 # wrong I think), as the following are valid file/dir names:
78 # " ...", "..." etc. Hmm the symlinks program probably doesn't
79 # handle this correctly either?
80
81 ASC_01=`printf "\001"`
82
83 for arg
84 do
85         case "$arg" in
86         -d)
87                 mode="dangling" ;;
88         -s)
89                 mode="suspect" ;;
90         -A)
91                 mode="absolute"
92                 search_expr="${ASC_01}/" ;;
93         -l)
94                 mode="relative"
95                 search_expr="${ASC_01}[^/]+" ;;
96         -n)
97                 mode="redundant"
98 search_expr="(${ASC_01}.*[/]{2,})" #finds 2 or more consequtive /'s
99 search_expr="$search_expr|([${ASC_01}/]\./)" # starting with ./ or /./ anywhere
100 search_expr="$search_expr|(${ASC_01}.*[^.]+/[.][.]/)" #finds x/../y
101 search_expr="$search_expr|(${ASC_01}/[.][.]/)" #finds /../y
102 search_expr="$search_expr|(${ASC_01}.*[.]{3,}/[.][.]/)" #finds .../../y etc
103 search_expr="$search_expr|(${ASC_01}.+/$)" ;; #finds ending with /
104         -h|--help|-help)
105                 Usage ;;
106         -v|--version)
107                 Version ;;
108         *)
109                 argsToPassOn="$argsToPassOn '$arg'" ;;
110         esac
111 done
112
113 . $script_dir/supprt/getfpf "$argsToPassOn"
114
115 case "$mode" in
116 dangling)
117         find "$@" -type l -printf "$FPF\n" |
118         #perl -nle '-e || print' | #this is much faster than below
119         #/usr/share/dict/words is 45424 lines which is 0.12s for
120         #perl and 3.8s for shell while read! should be OK though?
121         #Note also this doesn't distinguish EPERM and ENOENT
122         while read file; do [ -e "$file" ] || echo $file; done |
123         tr '\n' '\0' |
124         xargs -r0 ls -lUd -- |
125         sed 's/.*[0-9]\{2\} \(.*\)/\1/' ;; #only leave link -> target
126 suspect)
127         find "$@" -type l -printf "$FPF ->\1%p\1%l\n" |
128         grep "${ASC_01}.*${ASC_01}/" | #get absolute links
129         sed -e "s¬${ASC_01}./¬${ASC_01}$PWD/¬g" | #change rel to abs paths
130         grep -E "${ASC_01}(.*)/[^/]+${ASC_01}\1" | #find suspect links
131         sed -e "s¬${ASC_01}.*${ASC_01}¬ ¬g" ;; #drop work column
132 absolute|relative|redundant)
133         find "$@" -type l -printf "$FPF ->\1%l\n" |
134         grep -E "$search_expr" |
135         tr '\1' ' ' ;;
136 esac