Commit | Line | Data |
---|---|---|
f5673211 MW |
1 | #! /bin/sh |
2 | ### | |
3 | ### List a user's keys | |
4 | ### | |
5 | ### (c) 2011 Mark Wooding | |
6 | ### | |
7 | ||
8 | ###----- Licensing notice --------------------------------------------------- | |
9 | ### | |
10 | ### This file is part of the distorted.org.uk key management suite. | |
11 | ### | |
12 | ### distorted-keys is free software; you can redistribute it and/or modify | |
13 | ### it under the terms of the GNU General Public License as published by | |
14 | ### the Free Software Foundation; either version 2 of the License, or | |
15 | ### (at your option) any later version. | |
16 | ### | |
17 | ### distorted-keys is distributed in the hope that it will be useful, | |
18 | ### but WITHOUT ANY WARRANTY; without even the implied warranty of | |
19 | ### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
20 | ### GNU General Public License for more details. | |
21 | ### | |
22 | ### You should have received a copy of the GNU General Public License | |
23 | ### along with distorted-keys; if not, write to the Free Software Foundation, | |
24 | ### Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |
25 | ||
26 | set -e | |
27 | case "${KEYSLIB+t}" in t) ;; *) echo >&2 "$0: KEYSLIB unset"; exit 1 ;; esac | |
28 | . "$KEYSLIB"/keyfunc.sh | |
29 | ||
30 | defhelp <<HELP | |
31 | [-Ha] [-C COLUMN,...] [-u USER] [PATTERN ...] | |
32 | List stored keys. If PATTERNs are given, only list keys whose labels match | |
33 | at least one PATTERN. | |
34 | ||
35 | Options: | |
36 | -H Don't show the column headings (useful for scripts). | |
37 | -C COLUMN,... Select the columns to show. | |
38 | -a Show keys owned by all users. | |
39 | -u USER Show keys owned by USER. | |
40 | ||
41 | A COLUMN spec consists of a column name and an optional column width, | |
42 | separated by a colon. The widths of omitted columns are computed | |
43 | automatically. | |
44 | ||
45 | Columns: | |
46 | flags Various flags for the key. (Unset flags are shown as \`.') | |
47 | R key has recovery information | |
48 | ! key nub needs recovery | |
49 | label The key's label (relative to its owner). | |
50 | profile The key's profile name. | |
51 | recov Recovery key labels, comma-separated. | |
52 | HELP | |
53 | ||
54 | ###-------------------------------------------------------------------------- | |
55 | ### Column types. | |
56 | ||
57 | ALLCOLS="" | |
58 | defcol () { ALLCOLS=${ALLCOLS:+$ALLCOLS,}$1; } | |
59 | ||
60 | defcol flags | |
61 | col_flags () { | |
62 | label=$1 | |
63 | flags="" | |
64 | ||
65 | rflag=. | |
66 | for i in recov/*/current/$label.recov; do | |
67 | if [ -f "$i" ]; then rflag=R; break; fi | |
68 | done | |
69 | flags=$flags$rflag | |
70 | ||
71 | bangflag=! | |
72 | if [ -f nub/$label ]; then bangflag=.; fi | |
73 | flags=$flags$bangflag | |
74 | ||
75 | echo "$flags" | |
76 | } | |
77 | ||
78 | defcol label | |
79 | col_label () { | |
80 | label=$1 | |
81 | ||
82 | case $all,$label in | |
83 | nil,$USERV_USER*) plabel=${label#*/} ;; | |
84 | t,*) plabel=${label%%/*}:${label#*/} ;; | |
85 | esac | |
86 | echo "$plabel" | |
87 | } | |
88 | ||
89 | defcol profile | |
90 | col_profile () { | |
91 | label=$1 | |
92 | ||
93 | readmeta store/$label | |
94 | echo "$profile" | |
95 | } | |
96 | ||
97 | defcol recov | |
98 | col_recov () { | |
99 | label=$1 | |
100 | recov="" | |
101 | ||
102 | for i in recov/*; do | |
103 | if [ -f "$i/current/$label.recov" ]; then | |
104 | recov=${recov:+$recov,}${i#recov/} | |
105 | fi | |
106 | done | |
107 | echo "$recov" | |
108 | } | |
109 | ||
110 | ###-------------------------------------------------------------------------- | |
111 | ### Main program. | |
112 | ||
113 | ## Parse the command-line options. Remaining arguments are glob patterns. | |
114 | header=t | |
115 | cols=$ALLCOLS | |
116 | all=nil | |
117 | user=$USERV_USER | |
118 | while getopts "HaC:u:" opt; do | |
119 | case "$opt" in | |
120 | a) all=t ;; | |
121 | H) header=nil ;; | |
122 | C) cols=$OPTARG ;; | |
123 | u) user=$OPTARG ;; | |
124 | *) usage_err ;; | |
125 | esac | |
126 | done | |
127 | shift $(( $OPTIND - 1 )) | |
128 | case $# in 0) set "*" ;; esac | |
129 | cd $KEYS | |
130 | ||
131 | ## First pass: validate the column specifications. Translate all bare column | |
132 | ## names into explicit `NAME+0' forms. Decide whether we need a width- | |
133 | ## measuring pass. | |
134 | calcwd=nil | |
135 | cc=$cols | |
136 | wdcols="" | |
137 | while :; do | |
138 | ||
139 | ## Pick off the next column name. If none are left, leave the loop. | |
140 | case "$cc" in | |
141 | *,*) col=${cc%%,*} cc=${cc#*,} ;; | |
142 | ?*) col=$cc cc="" ;; | |
143 | *) break ;; | |
144 | esac | |
145 | ||
146 | ## Extract the column name for later. | |
147 | name=${col%[:=+]*} | |
148 | ||
149 | ## If we have a minimum width or no width, we need a measuring pass. | |
150 | case "$col" in *[:=]*) ;; *) calcwd=t ;; esac | |
151 | ||
152 | ## Check the column width is valid. Build the new column list with | |
153 | ## explicit widths. | |
154 | case "$col" in | |
155 | *[:=+]*) | |
156 | wd=${col#*[:=+]} | |
157 | wdcols=${wdcols:+$wdcols,}$col | |
158 | checknumber "column width" "$wd" | |
159 | ;; | |
160 | *) | |
161 | wdcols=${wdcols:+$wdcols,}$col+0 | |
162 | ;; | |
163 | esac | |
164 | ||
165 | ## Check the column name. | |
166 | case ,$ALLCOLS, in | |
167 | *,"$name",*) ;; | |
168 | *) echo >&2 "$quis: unknown column \`$name'"; exit 1 ;; | |
169 | esac | |
170 | done | |
171 | ||
172 | ## Second and third pass: find the keys, compute their properties and either | |
173 | ## measure column widths or display the results. | |
174 | while :; do | |
175 | ||
176 | ## Decide whether we need to display a header. (We need this on both | |
177 | ## passes, because it may contribute to width.) | |
178 | doheader=$header | |
179 | ||
180 | ## Find the metadata files. This tells us where the keys are. | |
181 | case $all in | |
182 | t) dir=store ;; | |
183 | nil) dir=store/$user ;; | |
184 | esac | |
185 | metas=$(find store -type f -name meta) | |
186 | ||
187 | ## Work through the keys we found. | |
188 | while :; do | |
189 | ||
190 | ## If we're not doing a header line, read the next metadata file name. | |
191 | ## Check that it matches at least one pattern. | |
192 | case $doheader in | |
193 | nil) | |
194 | if ! read meta; then break; fi | |
195 | label=${meta#store/}; label=${label%/meta} | |
196 | matchp=nil | |
197 | for pat in "$@"; do | |
198 | case "$label" in $pat) matchp=t; break ;; esac | |
199 | done | |
200 | case $matchp in nil) continue ;; esac | |
201 | ;; | |
202 | esac | |
203 | ||
204 | ## Now iterate over the columns. If we're calculating widths, use the | |
205 | ## ones we worked out last time, and clear the list so we can build a new | |
206 | ## one as we go. | |
207 | case $calcwd in t) cols=$wdcols ;; esac | |
208 | cc=$cols wdcols="" sep="" | |
209 | while :; do | |
210 | ||
211 | ## Pick off the next column spec. | |
212 | case "$cc" in | |
213 | *,*) col=${cc%%,*} cc=${cc#*,} ;; | |
214 | ?*) col=$cc cc="" ;; | |
215 | *) break ;; | |
216 | esac | |
217 | ||
218 | ## Work out the column name. | |
219 | name=${col%[:=+]*} wd=${col#*[:=+]} | |
220 | ||
221 | ## Work out the value. If this is a header line, then it's just the | |
222 | ## column name in upper case; otherwise we have work to do. | |
223 | case $doheader in | |
224 | t) value=$(echo $name | tr a-z A-Z) ;; | |
225 | nil) value=$(col_$name $label) ;; | |
226 | esac | |
227 | ||
228 | ## Work out what to do about it. If we're measuring, then update our | |
229 | ## idea of the column width. If we're printing, work out a format. | |
230 | case $calcwd,$col in | |
231 | t,*[:=]*) | |
232 | wdcols=${wdcols:+$wdcols,}$col | |
233 | ;; | |
234 | t,*+*) | |
235 | colwd=$(( $(echo "$value" | wc -c) - 1 )) | |
236 | if [ $colwd -gt $wd ]; then wd=$colwd; fi | |
237 | wdcols=${wdcols:+$wdcols,}$name+$wd | |
238 | ;; | |
239 | nil,*[=+]*) | |
240 | fmt="%-${wd}.${wd}s" | |
241 | ;; | |
242 | nil,*:*) | |
243 | fmt="%-${wd}s" | |
244 | ;; | |
245 | esac | |
246 | ||
247 | ## If we're printing, then print something. Leave space between the | |
248 | ## columns. | |
249 | case $calcwd in nil) printf "$sep$fmt" "$value"; sep=" " ;; esac | |
250 | done | |
251 | ||
252 | ## The next line will certainly not be a header. | |
253 | doheader=nil | |
254 | ||
255 | ## Start a new line if we're printing. | |
256 | case $calcwd in nil) printf "\n" ;; esac | |
257 | done <<EOF | |
258 | $metas | |
259 | EOF | |
260 | ||
261 | ## If we were measuring, go round again and print; otherwise we're done. | |
262 | case $calcwd in | |
263 | t) calcwd=nil ;; | |
264 | nil) break ;; | |
265 | esac | |
266 | done | |
267 | ||
268 | ###----- That's all, folks -------------------------------------------------- |