chiark / gitweb /
extract-profile: Add manpage.
[distorted-keys] / cryptop.list
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; 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.
49
50 Columns names:
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,"$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
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.
143 cd $KEYS
144 metas=$(find $dir -type f -name meta | sort)
145 case "x$metas" in x) echo >&2 "$quis: no keys"; exit 1 ;; esac
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
151 cc=$cols cols=""
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#*[:=+]}
172       cols=${cols:+$cols,}$col
173       checknumber "column width" "$wd"
174       ;;
175     *)
176       cols=${cols:+$cols,}$col+0
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
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.
215     cc=$cols sep=""
216     case $calcwd in t) cols="" ;; esac
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,*[:=]*)
240           cols=${cols:+$cols,}$col
241           ;;
242         t,*+*)
243           colwd=$(( $(echo "$value" | wc -c) - 1 ))
244           if [ $colwd -gt $wd ]; then wd=$colwd; fi
245           cols=${cols:+$cols,}$name+$wd
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 --------------------------------------------------