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 | ||
d5fe0926 MW |
41 | A COLUMN spec consists of a column name and an optional column width; the |
42 | separator character determines the behaviour as shown below. The default is | |
43 | \`+0'. | |
44 | NAME=WIDTH Exact width: truncate the contents to fit if necessary. | |
45 | NAME:WIDTH Minimum width: spill into the next column (breaking the | |
46 | alignment) if necessary. | |
47 | NAME+WIDTH Minimum width: if a value won't fit then make the entire | |
48 | column wider. | |
f5673211 | 49 | |
ef84343d | 50 | Column names: |
f5673211 MW |
51 | flags Various flags for the key. (Unset flags are shown as \`.') |
52 | R key has recovery information | |
53 | ! key nub needs recovery | |
54 | label The key's label (relative to its owner). | |
55 | profile The key's profile name. | |
56 | recov Recovery key labels, comma-separated. | |
57 | HELP | |
58 | ||
59 | ###-------------------------------------------------------------------------- | |
60 | ### Column types. | |
61 | ||
62 | ALLCOLS="" | |
63 | defcol () { ALLCOLS=${ALLCOLS:+$ALLCOLS,}$1; } | |
64 | ||
65 | defcol flags | |
66 | col_flags () { | |
67 | label=$1 | |
68 | flags="" | |
69 | ||
70 | rflag=. | |
71 | for i in recov/*/current/$label.recov; do | |
72 | if [ -f "$i" ]; then rflag=R; break; fi | |
73 | done | |
74 | flags=$flags$rflag | |
75 | ||
76 | bangflag=! | |
77 | if [ -f nub/$label ]; then bangflag=.; fi | |
78 | flags=$flags$bangflag | |
79 | ||
80 | echo "$flags" | |
81 | } | |
82 | ||
83 | defcol label | |
84 | col_label () { | |
85 | label=$1 | |
86 | ||
87 | case $all,$label in | |
2c973cfd | 88 | nil,"$user"/*) plabel=${label#*/} ;; |
f5673211 MW |
89 | t,*) plabel=${label%%/*}:${label#*/} ;; |
90 | esac | |
91 | echo "$plabel" | |
92 | } | |
93 | ||
94 | defcol profile | |
95 | col_profile () { | |
96 | label=$1 | |
97 | ||
98 | readmeta store/$label | |
99 | echo "$profile" | |
100 | } | |
101 | ||
102 | defcol recov | |
103 | col_recov () { | |
104 | label=$1 | |
105 | recov="" | |
106 | ||
107 | for i in recov/*; do | |
108 | if [ -f "$i/current/$label.recov" ]; then | |
109 | recov=${recov:+$recov,}${i#recov/} | |
110 | fi | |
111 | done | |
112 | echo "$recov" | |
113 | } | |
114 | ||
115 | ###-------------------------------------------------------------------------- | |
116 | ### Main program. | |
117 | ||
118 | ## Parse the command-line options. Remaining arguments are glob patterns. | |
119 | header=t | |
120 | cols=$ALLCOLS | |
121 | all=nil | |
122 | user=$USERV_USER | |
123 | while getopts "HaC:u:" opt; do | |
124 | case "$opt" in | |
125 | a) all=t ;; | |
126 | H) header=nil ;; | |
127 | C) cols=$OPTARG ;; | |
128 | u) user=$OPTARG ;; | |
129 | *) usage_err ;; | |
130 | esac | |
131 | done | |
132 | shift $(( $OPTIND - 1 )) | |
133 | case $# in 0) set "*" ;; esac | |
f00b260e MW |
134 | |
135 | ## Find where to look for keys, and check that there might be some. | |
136 | case $all in | |
137 | t) dir=store ;; | |
138 | nil) dir=store/$user ;; | |
139 | esac | |
140 | if [ ! -d $KEYS/$dir ]; then echo >&2 "$quis: no keys"; exit 1; fi | |
141 | ||
142 | ## Find the metadata files. This tells us where the keys are. | |
f5673211 | 143 | cd $KEYS |
f00b260e MW |
144 | metas=$(find $dir -type f -name meta | sort) |
145 | case "x$metas" in x) echo >&2 "$quis: no keys"; exit 1 ;; esac | |
f5673211 MW |
146 | |
147 | ## First pass: validate the column specifications. Translate all bare column | |
148 | ## names into explicit `NAME+0' forms. Decide whether we need a width- | |
149 | ## measuring pass. | |
150 | calcwd=nil | |
a22ca62e | 151 | cc=$cols cols="" |
f5673211 MW |
152 | while :; do |
153 | ||
154 | ## Pick off the next column name. If none are left, leave the loop. | |
155 | case "$cc" in | |
156 | *,*) col=${cc%%,*} cc=${cc#*,} ;; | |
157 | ?*) col=$cc cc="" ;; | |
158 | *) break ;; | |
159 | esac | |
160 | ||
161 | ## Extract the column name for later. | |
162 | name=${col%[:=+]*} | |
163 | ||
164 | ## If we have a minimum width or no width, we need a measuring pass. | |
165 | case "$col" in *[:=]*) ;; *) calcwd=t ;; esac | |
166 | ||
167 | ## Check the column width is valid. Build the new column list with | |
168 | ## explicit widths. | |
169 | case "$col" in | |
170 | *[:=+]*) | |
171 | wd=${col#*[:=+]} | |
a22ca62e | 172 | cols=${cols:+$cols,}$col |
f5673211 MW |
173 | checknumber "column width" "$wd" |
174 | ;; | |
175 | *) | |
a22ca62e | 176 | cols=${cols:+$cols,}$col+0 |
f5673211 MW |
177 | ;; |
178 | esac | |
179 | ||
180 | ## Check the column name. | |
181 | case ,$ALLCOLS, in | |
182 | *,"$name",*) ;; | |
183 | *) echo >&2 "$quis: unknown column \`$name'"; exit 1 ;; | |
184 | esac | |
185 | done | |
186 | ||
187 | ## Second and third pass: find the keys, compute their properties and either | |
188 | ## measure column widths or display the results. | |
189 | while :; do | |
190 | ||
191 | ## Decide whether we need to display a header. (We need this on both | |
192 | ## passes, because it may contribute to width.) | |
193 | doheader=$header | |
194 | ||
f5673211 MW |
195 | ## Work through the keys we found. |
196 | while :; do | |
197 | ||
198 | ## If we're not doing a header line, read the next metadata file name. | |
199 | ## Check that it matches at least one pattern. | |
200 | case $doheader in | |
201 | nil) | |
202 | if ! read meta; then break; fi | |
203 | label=${meta#store/}; label=${label%/meta} | |
204 | matchp=nil | |
205 | for pat in "$@"; do | |
206 | case "$label" in $pat) matchp=t; break ;; esac | |
207 | done | |
208 | case $matchp in nil) continue ;; esac | |
209 | ;; | |
210 | esac | |
211 | ||
212 | ## Now iterate over the columns. If we're calculating widths, use the | |
213 | ## ones we worked out last time, and clear the list so we can build a new | |
214 | ## one as we go. | |
a22ca62e MW |
215 | cc=$cols sep="" |
216 | case $calcwd in t) cols="" ;; esac | |
f5673211 MW |
217 | while :; do |
218 | ||
219 | ## Pick off the next column spec. | |
220 | case "$cc" in | |
221 | *,*) col=${cc%%,*} cc=${cc#*,} ;; | |
222 | ?*) col=$cc cc="" ;; | |
223 | *) break ;; | |
224 | esac | |
225 | ||
226 | ## Work out the column name. | |
227 | name=${col%[:=+]*} wd=${col#*[:=+]} | |
228 | ||
229 | ## Work out the value. If this is a header line, then it's just the | |
230 | ## column name in upper case; otherwise we have work to do. | |
231 | case $doheader in | |
232 | t) value=$(echo $name | tr a-z A-Z) ;; | |
233 | nil) value=$(col_$name $label) ;; | |
234 | esac | |
235 | ||
236 | ## Work out what to do about it. If we're measuring, then update our | |
237 | ## idea of the column width. If we're printing, work out a format. | |
238 | case $calcwd,$col in | |
239 | t,*[:=]*) | |
a22ca62e | 240 | cols=${cols:+$cols,}$col |
f5673211 MW |
241 | ;; |
242 | t,*+*) | |
243 | colwd=$(( $(echo "$value" | wc -c) - 1 )) | |
244 | if [ $colwd -gt $wd ]; then wd=$colwd; fi | |
a22ca62e | 245 | cols=${cols:+$cols,}$name+$wd |
f5673211 MW |
246 | ;; |
247 | nil,*[=+]*) | |
248 | fmt="%-${wd}.${wd}s" | |
249 | ;; | |
250 | nil,*:*) | |
251 | fmt="%-${wd}s" | |
252 | ;; | |
253 | esac | |
254 | ||
255 | ## If we're printing, then print something. Leave space between the | |
256 | ## columns. | |
257 | case $calcwd in nil) printf "$sep$fmt" "$value"; sep=" " ;; esac | |
258 | done | |
259 | ||
260 | ## The next line will certainly not be a header. | |
261 | doheader=nil | |
262 | ||
263 | ## Start a new line if we're printing. | |
264 | case $calcwd in nil) printf "\n" ;; esac | |
265 | done <<EOF | |
266 | $metas | |
267 | EOF | |
268 | ||
269 | ## If we were measuring, go round again and print; otherwise we're done. | |
270 | case $calcwd in | |
271 | t) calcwd=nil ;; | |
272 | nil) break ;; | |
273 | esac | |
274 | done | |
275 | ||
276 | ###----- That's all, folks -------------------------------------------------- |