Reported by Trent Creekmore
[dahdi/tools.git] / dahdi_span_assignments
1 #! /bin/sh
2 #
3 # /usr/sbin/dahdi_span_assignments:
4 #
5 # this script can be used both from udev and
6 # from the command line to assign/unassign and list
7 # current span assignments.
8 #
9 # It uses a configuration file: $DAHDICONFDIR/assigned-spans.conf
10 # (default DAHDICONFDIR=/etc/dahdi)
11 #
12 # The first argument is an action:
13 #   "auto"       - trigger driver auto_assign attribute for given devices
14 #                  (no configuration file is used)
15 #   "add"        - assign (spans which are not already assigned), according
16 #                  to /etc/dahdi/assigned-spans.conf configuration file
17 #   "remove"     - unassign spans which are not already unassigned
18 #   "list"       - human-readable list of all spans (with/without assignments)
19 #   "dumpconfig" - dump current assignments in a /etc/dahdi/assigned-spans.conf
20 #                  compatible format
21 #
22 # Without further arguments, it operates on all existing spans
23 # With one or more sysfs dahdi_devices it is limited to those.
24 #
25 # We may use alternative "keys" for device matching:
26 # * Available keys:
27 #   - "hwid"       - Hardware id attribute from sysfs
28 #   - "@location"  - Location attribute from sysfs (embeded inside '<>')
29 #   - "/devpath"   - The sysfs absolute devpath
30 #
31 # * During "dumpconfig", for each device we take the first available key:
32 #   - The preference is: "hwid" or else "@location" or else "/devpath"
33 #   - This can be overriden via the SPAN_ASSIGNMENTS_KEY environment variable
34 #     or the '{-k|--key} key' command line option.
35 #
36 # * During "add":
37 #   - Any key match is valid (hwid/location/devpath)
38 #   - Shell globs (wildcards: '*', '?', '[...]') may be optionally used.
39 #
40 # Command line options:
41 #  - The '-h|--help' show a usage message.
42 #  - The '-n|--dry-run' affects the "add" and "remove" operations.
43 #  - The '-v|--verbose' currently shows device matches during "add" operation.
44 #  - The '-k <key>|--key <key>' overrides the SPAN_ASSIGNMENTS_KEY environment
45 #    variable.
46 #
47 # Examples:
48 #    dahdi_span_assignments list
49 #    dahdi_span_assignments add # all unassigned devices
50 #    dahdi_span_assignments add       /sys/bus/dahdi_devices/devices/astribanks:xbus-00
51 #    dahdi_span_assignments remove      # all assigned devices
52 #    dahdi_span_assignments -k location dumpconfig
53 #
54
55 devbase='/sys/bus/dahdi_devices/devices'
56 DAHDICONFDIR="${DAHDICONFDIR:-/etc/dahdi}"
57 DAHDISASSIGNEDSPANSCONF="${DAHDIASSIGNEDSPANSCONF:-"${DAHDICONFDIR}/assigned-spans.conf"}"
58 SPAN_ASSIGNMENTS_KEY=${SPAN_ASSIGNMENTS_KEY:-hwid}
59 dry_run=
60 verbose=
61
62 usage() {
63         echo >&2 "Usage: $0 [options] action [devpath ...]"
64         echo >&2 "       action:"
65         echo >&2 "         auto       - trigger driver auto_assign attribute for given devices"
66         echo >&2 "         add        - assign spans, according to /etc/dahdi/assigned-spans.conf"
67         echo >&2 "         remove     - unassign spans"
68         echo >&2 "         list       - human-readable list of all spans"
69         echo >&2 "         matched    - found spans matched in configuration"
70         echo >&2 "         unmatched  - found spans not matched in configuration"
71         echo >&2 "         dumpconfig - dump current state as new configuration"
72         echo >&2 ""
73         echo >&2 "       options:"
74         echo >&2 "         -h|--help      - Show this help"
75         echo >&2 "         -n|--dry-run   - For 'add/remove' actions"
76         echo >&2 "         -v|--versbose  - Show matches during 'add' action"
77         echo >&2 "         -k|--key <k>   - Override prefered key during dumpconfig action"
78         exit 1
79 }
80
81 # Parse command line options
82 TEMP=`getopt -o hnvk: --long help,dry-run,verbose,key: -n "$0" -- "$@"`
83 if [ $? != 0 ]; then
84         echo >&2 "Bad options"
85         usage
86 fi
87
88 # Note the quotes around `$TEMP': they are essential!
89 eval set -- "$TEMP"
90
91 while true ; do
92         case "$1" in
93         -h|--help)
94                 usage
95                 ;;
96         -n|--dry-run)
97                 dry_run='true'
98                 shift
99                 ;;
100         -v|--verbose)
101                 verbose='true'
102                 shift
103                 ;;
104         -k|--key)
105                 SPAN_ASSIGNMENTS_KEY="$2"
106                 shift
107                 shift
108                 ;;
109         --)
110                 shift
111                 break
112                 ;;
113         *)
114                 echo >&2 "Internal error!"
115                 exit 1
116                 ;;
117         esac
118 done
119
120 if [ "$#" -eq 0 ]; then
121         echo >&2 "Missing action argument"
122         usage
123 fi
124 action="$1"
125 shift
126
127 # Validate SPAN_ASSIGNMENTS_KEY
128 case "$SPAN_ASSIGNMENTS_KEY" in
129 hwid|location|devpath)
130         ;;
131 *)
132         echo >&2 "Bad SPAN_ASSIGNMENTS_KEY='$SPAN_ASSIGNMENTS_KEY' (should be: hwid|location|devpath)"
133         usage
134         ;;
135 esac
136
137 if [ ! -d "$devbase" ]; then
138         echo >&2 "$0: Missing '$devbase' (DAHDI driver unloaded?)"
139         exit 1
140 fi
141
142 # Use given devices or otherwise, all existing devices
143 if [ "$#" -gt 0 ]; then
144         DEVICES="$@"
145 else
146         DEVICES=`ls -d $devbase/* 2>/dev/null`
147 fi
148
149 # Beware of special characters in attributes
150 attr_clean() {
151         cat "$1" 2>/dev/null | tr -d '\n' | tr '!' '/' | tr -c 'a-zA-Z0-9/:.-' '_'
152 }
153
154 show_devices() {
155
156         for device in $DEVICES
157         do
158                 devpath=`cd "$device" && pwd -P`
159                 location='@'`attr_clean "$device/location"`
160                 hardware_id=`attr_clean "$device/hardware_id"`
161                 for local_spanno in `cut -d: -f1 "$device/spantype"`
162                 do
163                         span=`grep 2>/dev/null -Hw "$local_spanno" "$device/span-"*"/local_spanno" | \
164                                 sed -e 's,/local_spanno:.*,,' -e 's,.*/,,'`
165                         if [ "$span" != '' ]; then
166                                 spanno=`echo $span | sed 's/^.*-//'`
167                                 name=`cat 2>/dev/null "$device/$span/name"`
168                                 basechan=`cat 2>/dev/null "$device/$span/basechan"`
169                         else
170                                 spanno='-'
171                                 basechan='-'
172                         fi
173                         printf "%-8s %-14s %s %s\n" "$local_spanno:$spanno:$basechan" "[$hardware_id]" "$location" "$devpath"
174                 done | sort -n
175         done
176 }
177
178 dump_config() {
179         echo '#'
180         echo "# Autogenerated by $0 on `date`"
181         echo "# Map devices + local spans to span + base channel number"
182         echo ''
183         for device in $DEVICES
184         do
185                 devpath=`cd "$device" && pwd -P`
186                 location=`attr_clean "$device/location"`
187                 hardware_id=`attr_clean "$device/hardware_id"`
188                 if [ "$SPAN_ASSIGNMENTS_KEY" = 'hwid' -a "$hardware_id" != '' ]; then
189                         id="$hardware_id"
190                 elif [ "$SPAN_ASSIGNMENTS_KEY" = 'location' -a "$location" != '' ]; then
191                         id="@$location"
192                 else
193                         id="$devpath"
194                 fi
195                 echo "# Device: [$hardware_id] @$location $devpath"
196                 for local_spanno in `cut -d: -f1 "$device/spantype"`
197                 do
198                         span=`grep 2>/dev/null -Hw "$local_spanno" "$device/span-"*"/local_spanno" | \
199                                 sed -e 's,/local_spanno:.*,,' -e 's,.*/,,'`
200                         if [ "$span" != '' ]; then
201                                 spanno=`echo $span | sed 's/^.*-//'`
202                                 name=`cat 2>/dev/null "$device/$span/name"`
203                                 basechan=`cat 2>/dev/null "$device/$span/basechan"`
204                                 printf "%-30s %s\n" "$id" "$local_spanno:$spanno:$basechan"
205                         else
206                                 echo "#   Skipped unassigned local span $local_spanno"
207                         fi
208                 done | sort
209                 echo ''
210         done
211 }
212
213 unassign_all_spans() {
214         for device in $DEVICES
215         do
216                 find "$device" -follow -maxdepth 1 -name 'span-*' -type d | \
217                         sort | while read spandir; do
218                         local_spanno=`cat "$spandir/local_spanno"`
219                         if [ "$dry_run" = true ]; then
220                                 echo >&2 "(dry-run) unassign $device $local_spanno"
221                                 continue
222                         fi
223                         echo >&2 "unassign $device $local_spanno"
224                         if ! echo "$local_spanno" > "$device/unassign_span"; then
225                                 echo >&2 "$0: failed unassigning '$local_spanno' in '$device'"
226                         fi
227                 done
228         done
229 }
230
231 # Allow comments and empty lines in config file
232 filter_conf() {
233         sed -e 's/#.*//' -e '/^[ \t]*$/d' "$DAHDISASSIGNEDSPANSCONF"
234 }
235
236 assign_device_spans() {
237         device="$1"
238         for s in $spanspecs
239         do
240                 local_spanno=`echo "$s" | cut -d: -f1`
241                 spanno=`echo "$s" | cut -d: -f2`
242                 span="$device/span-$spanno"
243                 if [ "$dry_run" = true ]; then
244                         echo "(dry-run) assign $device: $s"
245                         continue
246                 fi
247                 if [ -d "$span" ]; then
248                         span_local_spanno=`cat "$span/local_spanno"`
249                         if [ "$span_local_spanno" != "$local_spanno" ]; then
250                                 echo >&2 "WARNING: $span_local_spanno != $local_spanno"
251                         fi
252                         echo >&2 "$device [$local_spanno] already assigned to span $spanno. Skipping..."
253                         continue
254                 fi
255                 echo >&2 "assign $device: $s"
256                 if ! echo "$s" > "$device/assign_span"; then
257                         echo >&2 "$0: failed assigning '$s' to '$device'"
258                 fi
259         done
260 }
261
262 match_device() {
263         device="$1"
264         devpath=`cd "$device" && pwd -P`
265         location='@'`attr_clean "$device/location"`
266         hardware_id=`attr_clean "$device/hardware_id"`
267         filter_conf | while read id spanspecs
268         do
269                 # We use case to enable shell-style globbing in configuration
270                 case "$hardware_id" in
271                 $id)
272                         [ "$verbose" = true ] && echo >&2 "match by hwid ($id ~ $hardware_id): $spanspecs"
273                         assign_device_spans "$device"
274                         ;;
275                 esac
276                 # We use case to enable shell-style globbing in configuration
277                 case "$location" in
278                 $id)
279                         [ "$verbose" = true ] && echo >&2 "match by location ($id ~ $location): $spanspecs"
280                         assign_device_spans "$device"
281                         ;;
282                 esac
283                 # We use case to enable shell-style globbing in configuration
284                 case "$devpath" in
285                 $id)
286                         [ "$verbose" = true ] && echo >&2 "match by devpath ($id ~ $devpath): $spanspecs"
287                         assign_device_spans "$device"
288                         ;;
289                 esac
290         done
291 }
292
293 assign_devices() {
294         if [ ! -f "$DAHDISASSIGNEDSPANSCONF" ]; then
295                 echo >&2 "$0: Missing '$DAHDISASSIGNEDSPANSCONF'"
296                 exit 1
297         fi
298         echo >&2 "using '$DAHDISASSIGNEDSPANSCONF'"
299         for device in $DEVICES
300         do
301                 match_device "$device"
302         done
303 }
304
305 auto_assign_devices() {
306         for device in $DEVICES
307         do
308                 echo >&2 "auto-assign $device"
309                 if [ "$dry_run" != true ]; then
310                         echo 1 > "$device/auto_assign"
311                 fi
312         done
313 }
314
315 dev_match_conf() {
316         local devpath="$1"
317         local location="$2"
318         local hardware_id="$3"
319         local local_spanno="$4"
320         filter_conf | while read id spanspecs
321         do
322                 spanno=`echo "$spanspecs" | cut -d: -f1`
323                 match_dev=no
324                 # We use case to enable shell-style globbing in configuration
325                 case "$hardware_id" in
326                 $id)
327                         match_dev=yes
328                         ;;
329                 esac
330                 # We use case to enable shell-style globbing in configuration
331                 case "$location" in
332                 $id)
333                         match_dev=yes
334                         ;;
335                 esac
336                 # We use case to enable shell-style globbing in configuration
337                 case "$devpath" in
338                 $id)
339                         match_dev=yes
340                         ;;
341                 esac
342                 if [ "$match_dev" = 'yes' -a "$local_spanno" = "$spanno" ]; then
343                         #printf "%-8s (%s) %-14s %s %s\n" "$local_spanno" "$spanno" "[$hardware_id]" "$location" "$devpath"
344                         echo "[$hardware_id]:$local_spanno"
345                 fi
346         done
347 }
348
349 list_devices() {
350         wanted="$1"
351         if [ ! -f "$DAHDISASSIGNEDSPANSCONF" ]; then
352                 echo >&2 "$0: Missing '$DAHDISASSIGNEDSPANSCONF'"
353                 exit 1
354         fi
355         echo >&2 "using '$DAHDISASSIGNEDSPANSCONF'"
356         for device in $DEVICES
357         do
358                 devpath=`cd "$device" && pwd -P`
359                 location='@'`attr_clean "$device/location"`
360                 hardware_id=`attr_clean "$device/hardware_id"`
361                 for local_spanno in `cut -d: -f1 "$device/spantype"`
362                 do
363                         found=`dev_match_conf "$devpath" "$location" "$hardware_id" "$local_spanno"`
364                         if [ "$wanted" = "unmatched" ]; then
365                                 [ -z "$found" ] && echo "[$hardware_id]:$local_spanno"
366                         else
367                                 [ -z "$found" ] || echo "[$hardware_id]:$local_spanno"
368                         fi
369                 done
370         done
371 }
372
373 case "$action" in
374 auto)
375         auto_assign_devices
376         ;;
377 add)
378         assign_devices
379         ;;
380 remove)
381         unassign_all_spans
382         ;;
383 list)
384         show_devices
385         ;;
386 dumpconfig)
387         dump_config
388         ;;
389 matched)
390         list_devices "matched"
391         ;;
392 unmatched)
393         list_devices "unmatched"
394         ;;
395 *)
396         echo >&2 "Bad action='$action'"
397         usage
398         ;;
399 esac