minor updates
[pkgusr] / usr / bin / forall_direntries_from
1 #!/bin/bash
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!
5
6 #The following list should contain the mount points of all filesystems
7 #that are to be scanned as a space-separated list within parentheses. 
8 #/ will usually be in this list and if you have /usr
9 #on a separate partition, it will also be in this list. Other non-special
10 #filesystems where package users could own files should also be put in this
11 #list.
12 #Mount points whose filesystems are special, such as procfs or sysfs must
13 #not be in this list. While a simple find on those special filesystems should 
14 #be harmless, operations such as "-exec grep something" are NOT SAFE and may 
15 #have HARMFUL SIDE-EFFECTS, especially when performed as root. 
16
17 ## Bastard settings
18 # fs_to_scan=(/ /opt /usr /usr/local /var)
19
20 fs_to_scan=(/)
21
22 #Files with a path prefix found in the following list are ignored.
23 #This list will usually contain the parent directory of your package users'
24 #home directories, because normally you don't want to scan those. You can
25 #also add other directories that will never contain package user files, such
26 #as /home. This reduces scan time.
27 #NOTE: The LFS-6.0 book uses a ramfs mounted on /dev and with that setup
28 #/dev does not need to be in the prune list. But since there is no requirement
29 #that /dev have its on filesystem it's better to prune it explicitly.
30
31 ## Bastard settings
32 # prune_prefixes=(\
33 #      /tools \
34 #      /usr/local/LFS/tools \
35 #      /home \
36 #      /usr/src \
37 #      /dev \
38 #      /mnt \
39 #      /tmp \
40 #      /sys \
41 #      /etc/apache/ssl.key \
42 #      /etc/cups/ssl \
43 #      /etc/firewall \
44 #      /etc/skel \
45 #      /etc/ssl/private \
46 #      /lost+found \
47 #      /**/lost+found \
48 #      /root \
49 #      /usr/local/lost+found \
50 #      /**/.{mc,ssh,mozilla,spamassassin} \
51 #      /usr/local/media/pr0n \
52 #      /usr/local/LFS \
53 #      /usr/share/mailman \
54 #      /var/{cache,chroot,run,snmp,spool} \
55 #      /var/lib/{sshd,nfs,spamassassin,pulse} \
56 #      /var/www/htdocs/SXEmacs-issues{,.old} \
57 #      /var/lost+found) #NO TRAILING SLASHES!!!!
58
59 prune_prefixes=(/home /usr/src /dev /tools) #NO TRAILING SLASHES!!!!
60
61 if [ $# -lt 1 -o "$1" = "--help" ]; then
62     echo 1>&2
63     echo 1>&2 'USAGE: '"${0##*/}"' <user_or_group_name> [<find-commands>]'
64     echo 1>&2
65     echo 1>&2 '  If <find-commands> contains no action other than -prune, -print will be'
66     echo 1>&2 '    executed for all matching files.'
67     echo 1>&2 '  Entries will be matched if group and/or user equals <user_or_group_name>'
68     echo 1>&2 '    (numeric UID/GID allowed).'
69     echo 1>&2 '  All matching entries will be acted on, including device special files, so'
70     echo 1>&2 '    you should be extra careful with the <find-commands> you provide!'
71     echo 1>&2
72     exit 1
73 fi
74
75 #suppress ugly debug output from shell
76 trap ':' SIGPIPE
77
78 ugname="$1"
79 shift 1  #remove user_or_group_name from argument list
80
81 ugmatcher=(-false)
82 #test if find accepts ugname as a user, and append to ugmatcher if it does
83 if find / -maxdepth 0 -user "$ugname" >/dev/null 2>&1 ; then
84     ugmatcher[${#ugmatcher[@]}]="-or"
85     ugmatcher[${#ugmatcher[@]}]="-user"
86     ugmatcher[${#ugmatcher[@]}]="$ugname"
87 fi
88 #test if find accepts ugname as a group, and append to ugmatcher if it does
89 if find / -maxdepth 0 -group "$ugname" >/dev/null 2>&1 ; then
90     ugmatcher[${#ugmatcher[@]}]="-or"
91     ugmatcher[${#ugmatcher[@]}]="-group"
92     ugmatcher[${#ugmatcher[@]}]="$ugname"
93 fi
94
95 #if find accepted ugname as neither user nor group, then exit
96 if [ "${#ugmatcher[@]}" = 1 ]; then
97     echo 1>&2 'find does not accept `'"$ugname'"' as group or user name'
98     exit 1
99 fi
100
101 #construct find commands that match the prune_prefixes. Each prefix will be
102 #matched as -path <prefix> -or -path <prefix>/*
103 #so that the directory itself and all subdirectories are matched.
104 y=(\( -false)
105 for ((i=0; $i<${#prune_prefixes[@]}; i=$i+1))
106 do
107     y[${#y[@]}]='-or'
108     y[${#y[@]}]=-path
109     y[${#y[@]}]="${prune_prefixes[$i]}"
110     y[${#y[@]}]='-or'
111     y[${#y[@]}]=-path
112     y[${#y[@]}]="${prune_prefixes[$i]}/*"
113 done
114 y[${#y[@]}]=')'
115
116 #In the following find command, the part
117 # -not ( ( "${y[@]}" -prune ) -or "${y[@]}" )
118 #is responsible for preventing the files that match prune_prefixes from
119 #being processed. The 2nd "${y[@]}" may seem redundant, but it isn't, because
120 #-prune has no effect and is always false when -depth is used.
121 #The -true before "$@" ensures that -depth can be passed as only parameter.
122 find "${fs_to_scan[@]}" -xdev -noleaf \
123     -not \( \( "${y[@]}" -prune \) -or "${y[@]}" \) \
124     -and \( "${ugmatcher[@]}" \) -and \( -true "$@" \)