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 | |
d5fe0926 | 50 | Columns 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 | |
88 | nil,$USERV_USER*) plabel=${label#*/} ;; | |
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 | |
134 | cd $KEYS | |
135 | ||
136 | ## First pass: validate the column specifications. Translate all bare column | |
137 | ## names into explicit `NAME+0' forms. Decide whether we need a width- | |
138 | ## measuring pass. | |
139 | calcwd=nil | |
140 | cc=$cols | |
141 | wdcols="" | |
142 | while :; do | |
143 | ||
144 | ## Pick off the next column name. If none are left, leave the loop. | |
145 | case "$cc" in | |
146 | *,*) col=${cc%%,*} cc=${cc#*,} ;; | |
147 | ?*) col=$cc cc="" ;; | |
148 | *) break ;; | |
149 | esac | |
150 | ||
151 | ## Extract the column name for later. | |
152 | name=${col%[:=+]*} | |
153 | ||
154 | ## If we have a minimum width or no width, we need a measuring pass. | |
155 | case "$col" in *[:=]*) ;; *) calcwd=t ;; esac | |
156 | ||
157 | ## Check the column width is valid. Build the new column list with | |
158 | ## explicit widths. | |
159 | case "$col" in | |
160 | *[:=+]*) | |
161 | wd=${col#*[:=+]} | |
162 | wdcols=${wdcols:+$wdcols,}$col | |
163 | checknumber "column width" "$wd" | |
164 | ;; | |
165 | *) | |
166 | wdcols=${wdcols:+$wdcols,}$col+0 | |
167 | ;; | |
168 | esac | |
169 | ||
170 | ## Check the column name. | |
171 | case ,$ALLCOLS, in | |
172 | *,"$name",*) ;; | |
173 | *) echo >&2 "$quis: unknown column \`$name'"; exit 1 ;; | |
174 | esac | |
175 | done | |
176 | ||
177 | ## Second and third pass: find the keys, compute their properties and either | |
178 | ## measure column widths or display the results. | |
179 | while :; do | |
180 | ||
181 | ## Decide whether we need to display a header. (We need this on both | |
182 | ## passes, because it may contribute to width.) | |
183 | doheader=$header | |
184 | ||
185 | ## Find the metadata files. This tells us where the keys are. | |
186 | case $all in | |
187 | t) dir=store ;; | |
188 | nil) dir=store/$user ;; | |
189 | esac | |
d8c2ee90 | 190 | metas=$(find $dir -type f -name meta | sort) |
f5673211 MW |
191 | |
192 | ## Work through the keys we found. | |
193 | while :; do | |
194 | ||
195 | ## If we're not doing a header line, read the next metadata file name. | |
196 | ## Check that it matches at least one pattern. | |
197 | case $doheader in | |
198 | nil) | |
199 | if ! read meta; then break; fi | |
200 | label=${meta#store/}; label=${label%/meta} | |
201 | matchp=nil | |
202 | for pat in "$@"; do | |
203 | case "$label" in $pat) matchp=t; break ;; esac | |
204 | done | |
205 | case $matchp in nil) continue ;; esac | |
206 | ;; | |
207 | esac | |
208 | ||
209 | ## Now iterate over the columns. If we're calculating widths, use the | |
210 | ## ones we worked out last time, and clear the list so we can build a new | |
211 | ## one as we go. | |
212 | case $calcwd in t) cols=$wdcols ;; esac | |
213 | cc=$cols wdcols="" sep="" | |
214 | while :; do | |
215 | ||
216 | ## Pick off the next column spec. | |
217 | case "$cc" in | |
218 | *,*) col=${cc%%,*} cc=${cc#*,} ;; | |
219 | ?*) col=$cc cc="" ;; | |
220 | *) break ;; | |
221 | esac | |
222 | ||
223 | ## Work out the column name. | |
224 | name=${col%[:=+]*} wd=${col#*[:=+]} | |
225 | ||
226 | ## Work out the value. If this is a header line, then it's just the | |
227 | ## column name in upper case; otherwise we have work to do. | |
228 | case $doheader in | |
229 | t) value=$(echo $name | tr a-z A-Z) ;; | |
230 | nil) value=$(col_$name $label) ;; | |
231 | esac | |
232 | ||
233 | ## Work out what to do about it. If we're measuring, then update our | |
234 | ## idea of the column width. If we're printing, work out a format. | |
235 | case $calcwd,$col in | |
236 | t,*[:=]*) | |
237 | wdcols=${wdcols:+$wdcols,}$col | |
238 | ;; | |
239 | t,*+*) | |
240 | colwd=$(( $(echo "$value" | wc -c) - 1 )) | |
241 | if [ $colwd -gt $wd ]; then wd=$colwd; fi | |
242 | wdcols=${wdcols:+$wdcols,}$name+$wd | |
243 | ;; | |
244 | nil,*[=+]*) | |
245 | fmt="%-${wd}.${wd}s" | |
246 | ;; | |
247 | nil,*:*) | |
248 | fmt="%-${wd}s" | |
249 | ;; | |
250 | esac | |
251 | ||
252 | ## If we're printing, then print something. Leave space between the | |
253 | ## columns. | |
254 | case $calcwd in nil) printf "$sep$fmt" "$value"; sep=" " ;; esac | |
255 | done | |
256 | ||
257 | ## The next line will certainly not be a header. | |
258 | doheader=nil | |
259 | ||
260 | ## Start a new line if we're printing. | |
261 | case $calcwd in nil) printf "\n" ;; esac | |
262 | done <<EOF | |
263 | $metas | |
264 | EOF | |
265 | ||
266 | ## If we were measuring, go round again and print; otherwise we're done. | |
267 | case $calcwd in | |
268 | t) calcwd=nil ;; | |
269 | nil) break ;; | |
270 | esac | |
271 | done | |
272 | ||
273 | ###----- That's all, folks -------------------------------------------------- |