2 # Copyright (c) 2004 Matthias S. Benkmann <article AT winterdrache DOT de>
3 # You may do everything with this code except misrepresent its origin.
4 # PROVIDED `AS IS' WITH ABSOLUTELY NO WARRANTY OF ANY KIND!
6 if [ $# -lt 1 -o \( $# -gt 1 -a "z$1" != "z:man" -a "z$1" != "z:mani" -a "z$1" != "z:lib" \) -o "$1" = "--help" ]; then
8 echo 1>&2 'USAGE: '"${0##*/}"' <user_or_group_name>'
10 echo 1>&2 ' Entries will be matched if group and/or user equals <user_or_group_name>'
11 echo 1>&2 ' (numeric UID/GID allowed).'
12 echo 1>&2 ' This script uses `forall_direntries_from'"'"' and `list_suspicious_files_from'"'."
14 echo 1>&2 ' NOTE: Several minutes may pass before you see the first output.'
15 echo 1>&2 ' You should probably redirect output to a file for later reference.'
17 echo 1>&2 ' WARNING! This program is for listing files from package users only!'
18 echo 1>&2 ' Do NOT use it to list files from untrusted users!'
19 echo 1>&2 ' An untrusted user could set up a manipulated manpage to exploit'
20 echo 1>&2 ' a bug in man when it is used to extract the summary!'
25 # - when extracting summaries from manpages, candidate manpages are considered
26 # in alphabetic order rather than the order used by the man command.
27 # The problem with this is that section 8, which contains manpages for
28 # admin commands, will be considered after lower-numbered sections.
29 # In the rare case that an admin command has the same name as a topic from
30 # a lower-numbered manpage installed by the same package, the summary will
31 # be taken from the wrong manpage.
32 # An example for such a clash are the faillog.5 and faillog.8 manpages from
34 # Because this problem is difficult to fix, rare and easily spotted (since
35 # the manpage that should have provided the summary will be listed under
36 # EXTRA MANPAGES) I won't fix it.
40 #suppress ugly debug output from shell
50 echo $'command\2'"$name"$'\2man\2'"$2" ;;
55 echo $'command\2'"$name"$'\2mani\2'"$2" ;;
65 sanitize() { tr -c '[:print:]' '?' ; }
68 # $2: command\2<commandname>\2cmd\2(-><linktarget>)
69 # $3: command\2<commandname>\2man[i]\2<manpage_path> or <empty>
76 linktarget="${cmdline##*${sep}}"
78 if [ -z "$manline" ]; then
79 description='No manpage'
80 #the "l" at the beginning is just to make it sort after "lib"
81 echo -n "lmanlessbin $cmdname" | sanitize
84 else # if [ ! -z "$manline" ]; then
85 manpage=${manline##*${sep}}
87 # The `t l;d;:l;n;b l' in the sed command is voodoo magic to make sed
88 # output only the first match but to keep eating up all input. I use this
89 # instead of `| head -n 1', because head breaks the pipe after doing
90 # its 1 line output, which (if it happens before sed has processed the
91 # complete input) freaks out man and causes it to emit a totally
92 # silly error message including "No such file or directory", which is
93 # annoying when you do testing without suppressing man's errors.
94 # The $'s/.\b\\(.\\)/\\1/g;s/\x1b[^m]\\+m//g' removes the backspace-based
95 # as well as ESC-based formatting from man's output.
96 description="$( { COLUMNS=300 man "$manpage" 2>/dev/null ||
97 echo " $name - Broken manpage" ; } |
98 sed $'s/.\b\\(.\\)/\\1/g;s/\x1b[^m]\\+m//g' |
99 sed -n "/^NAME/,/^[A-Z]/s/^.*${wsc}${cmdname}${wsc}.*-\+${wsc}\(.*\)/\1/p;t l;d;:l;n;b l" )"
100 if [ -z "$description" ]; then
101 description="$( COLUMNS=300 man "$manpage" 2>/dev/null |
102 sed $'s/.\b\\(.\\)/\\1/g;s/\x1b[^m]\\+m//g' |
103 sed -n "s/^.*${wsc}..*${wsc}.*-\+${wsc}\(.*\)/\1/p;t l;d;:l;n;b l" )"
105 test -z "$description" && description="Weird manpage"
108 echo -n "binexe $cmdname" | sanitize
109 test "$linktarget" != '(->)' && echo -n "$linktarget" | sanitize
111 #the "lx" in "lxdescription" is just to make sure it sorts after "lmanlessbin"
112 echo -n "lxdescription $cmdname: $description" | sanitize
116 # NOTE: The -path and -lname stuff at the beginning of the following is
117 # there to make sure that none of the lines output by find contains
118 # a) \n or \r, because that would mess up post-processing the output
120 # b) \x7f, because this character triggers one of the nastier bash-bugs
121 # wrt string handling
122 # c) \2, because I use this as separator within the lines
123 # (Why \2 and not \0 or \1 ? Because bash can't cope with \0 at all and has
124 # bugs related to \1.)
126 # Because of this, having the final section called "ALL FILES" is technically
127 # a lie, because files with a path containing one of the abovementioned
128 # characters will not appear in output.
129 # However, a) no sane package contains such files
130 # b) they will be listed in the output from list_suspicious_files
131 cmd=(\( -path $'*\n*' -or -path $'*\r*' -or -path $'*\x7f*'
133 -or -lname $'*\n*' -or -lname $'*\r*' -or -lname $'*\x7f*'
138 \( -printf "zall %p\n" \) ,
140 \( -type f -or -xtype f \) -and
142 \( -perm -u+x \( -path "*/bin/*" -or -path "*/sbin/*" \) -printf 'command\2%f\2cmd\2(->%l)\n' \)
143 -or \( -path "*/man/man*/*" -exec "$0" ":man" {} \; \)
144 -or \( -path "*/man/*/man*/*" -exec "$0" ":mani" {} \; \)
145 -or \( \( -name "lib*.so" -or -name "lib*.a" -or -name "lib*.so.*" \) -path "*/lib/*" -exec "$0" ":lib" {} \; \)
146 -or \( -type f -perm -u+x -not \( \( -name "lib*.so" -or -name "lib*.a" -or -name "lib*.so.*" \) -path "*/lib/*" \) -printf "nobinexe %p\n" \)
152 forall_direntries_from "$ugname" "${cmd[@]}" | sort -u |
157 if [ -z "$hold" ]; then
158 read -r line || break
165 zcommand${sep}*${sep}cmd${sep}*)
166 cmdname=${line#command${sep}}
167 cmdname=${cmdname%%${sep}*}
170 zcommand${sep}${cmdname}${sep}man${sep}*|zcommand${sep}${cmdname}${sep}mani${sep}*)
171 expand_command "$cmdname" "$line" "$hold"
176 expand_command "$cmdname" "$line" ""
181 zcommand${sep}*${sep}man${sep}*|command${sep}*${sep}mani${sep}*)
183 echo -n "manextra ${line##*${sep}}" | sanitize
188 echo -n "$line" | sanitize
194 } | sort | #no -u here, bc. the above processing may equalize different files
196 # (1) binexe: Executables (in *bin/)
197 # (2) lib: Libraries (in *lib/*)
198 # (3) lmanlessbin: Executables (in *bin/) without manpages
199 # (4) lxdescription: Summaries for executables (in *bin/)
200 # (5) manextra: Extra manpages
201 # full paths, no perms
202 # (6) nobinexe: Executables not in *bin/ (excluding *lib/*.so and *lib/*.so.*)
203 # full paths, no perms
204 # (7) zall: All files
205 # full paths, no perms
208 while read -r line ; do
209 newstate="${line%% *}"
210 if [ "$newstate" != "$curstate" ]; then
214 echo 'EXECUTABLES (in */bin or */sbin)'
215 echo -n " ${line#binexe }"
220 echo 'LIBRARIES (lib*.a or lib*.so)'
221 echo -n " ${line#lib }"
226 echo 'EXECUTABLES WITH NO MANPAGE (in */bin or */sbin)'
227 echo -n " ${line#lmanlessbin }"
232 echo 'MANPAGE SUMMARIES OF EXECUTABLES (in */bin or */sbin)'
233 echo " ${line#lxdescription }"
237 echo 'EXTRA MANPAGES'
238 echo " ${line#manextra }"
242 echo 'EXTRA EXECUTABLES (not in */bin or */sbin)'
243 echo " ${line#nobinexe }"
248 echo " ${line#zall }"
253 echo 'UNEXPECTED LINE'
259 binexe) echo -n ", ${line#binexe }" ;;
260 lib) echo -n ", ${line#lib }" ;;
261 lmanlessbin) echo -n ", ${line#lmanlessbin }" ;;
262 lxdescription) echo " ${line#lxdescription }" ;;
263 manextra) echo " ${line#manextra }" ;;
264 nobinexe) echo " ${line#nobinexe }" ;;
265 zall) echo " ${line#zall }" ;;
268 echo 'UNEXPECTED LINE'
276 list_suspicious_files_from "$ugname"