a0c6e3baba0a5b7d87ecdcdaf66a55450a645404
[nas-tools.git] / led_ctrl / led_ctrl
1 #!/bin/sh -e
2
3 SYSPATH=/sys/class/leds
4 CONFILE=/etc/led_ctrl.conf
5 DEBUG=false
6 TESTS=false
7 unset MODE
8
9 log_and_exec()
10 {
11         $DEBUG && echo "$@" >&2
12         eval "$@"
13 }
14
15 log_and_die()
16 {
17         printf "$@\n" >&2
18         exit 1
19 }
20
21 set_led_attr() # <led> <attribute> <value>
22 {
23         local attr err=0
24
25         IFS_ORIG="$IFS"
26         IFS=$'\n'
27         for attr in $(ls -1 $SYSPATH/$1/$2); do
28                 log_and_exec "echo $3 > \"$attr\"" || { err=1; break; }
29         done
30         IFS="$IFS_ORIG"
31
32         return $err
33 }
34
35 set_led_mode() # <mode>
36 {
37         local section leds settings setting attr value
38
39         section=$(sed -n -e "s/#.*//" -e "/{$1}/,/{.*}/p" $CONFILE)
40         [ -n "$section" ] || \
41                 log_and_die "no mode $1 in $CONFILE"
42
43         echo "$section" | grep '=' | while read leds settings; do
44                 for setting in $settings; do
45                         attr=$(echo $setting | cut -d'=' -f1)
46                         value=$(echo $setting | cut -d'=' -f2)
47                         [ -n "$attr" -a -n "$value" ] || \
48                                 log_and_die "$CONFILE: mode=$1 leds=$leds, invalid setting $setting"
49                         set_led_attr "$leds" $attr $value || \
50                                 log_and_die "$CONFILE: unable to apply $attr=$value for $leds"
51                 done
52         done || return $?
53 }
54
55 list_led_modes()
56 {
57         sed -n 's/{\(.*\)}/\1/p' $CONFILE
58 }
59
60 run_test() # <message> <test>
61 {
62         eval "$2" && \
63                 echo "$1 : OK" || \
64                 { echo "$1 : FAIL"; TEST_ERR=1; } 
65 }
66
67 run_test_suite()
68 {
69         TEST_ERR=0
70
71         SYSPATH=/tmp/$(basename $0)-test-$$
72         CONFILE=$SYSPATH/conf
73
74         rm -fr $SYSPATH
75         mkdir -p $SYSPATH/led1
76         touch $SYSPATH/led1/attr1
77         touch $SYSPATH/led1/attr2
78         touch $SYSPATH/led1/attr3
79         mkdir -p $SYSPATH/led2
80         touch $SYSPATH/led2/attr1
81         touch $SYSPATH/led2/attr2
82         mkdir -p $SYSPATH/led\ 3
83         touch $SYSPATH/led\ 3/attr1
84         mkdir -p $SYSPATH/led\ 4
85         touch $SYSPATH/led\ 4/attr1
86
87         cat > $CONFILE <<- EOF
88                 {mode1}
89                 led1            =value
90
91                 {mode2}
92                 led1            attr1=
93
94                 {mode3}
95                 *               attr1=3
96                 led[0-9]        attr2=3
97
98                 {mode4}
99                 led\ [0-9]      attr1=4
100
101                 {mode5}
102                 #{mode6}
103                 led1            attr1=5 attr2=5 attr3=5
104                 led2            attr1=5 attr2=5 # some comments
105                 #led3           attr1=5
106         EOF
107
108         chmod 500 $SYSPATH/led1
109         chmod 500 $SYSPATH/led2
110         chmod 500 $SYSPATH/led\ 3
111         chmod 500 $SYSPATH/led\ 4
112         chmod 500 $SYSPATH
113
114         run_test 'non-defined led mode' \
115                 'set_led_mode nomatch 2>&1 | grep -q "no mode"'
116
117         run_test 'match empty attribute name' \
118                 'set_led_mode mode1 2>&1 | grep -q "invalid setting"'
119
120         run_test 'match empty attribute value' \
121                 'set_led_mode mode2 2>&1 | grep -q "invalid setting"'
122
123         run_test 'led name with wildcard and globbing' 'set_led_mode mode3'
124         run_test '  led1, set attr1=3' '[ "$(cat $SYSPATH/led1/attr1)" = 3 ]'
125         run_test '  led2, set attr1=3' '[ "$(cat $SYSPATH/led2/attr1)" = 3 ]'
126         run_test '  led 3, set attr1=3' '[ "$(cat $SYSPATH/led\ 3/attr1)" = 3 ]'
127         run_test '  led1, set attr2=3' '[ "$(cat $SYSPATH/led1/attr2)" = 3 ]'
128         run_test '  led2, set attr2=3' '[ "$(cat $SYSPATH/led2/attr2)" = 3 ]'
129
130         run_test 'led name with whitespace and globbing' 'set_led_mode mode4'
131         run_test '  led 3, set attr1=4' '[ "$(cat $SYSPATH/led\ 3/attr1)" = 4 ]'
132         run_test '  led 4, set attr1=4' '[ "$(cat $SYSPATH/led\ 4/attr1)" = 4 ]'
133
134         run_test 'multiple attributes and discarded comments' \
135                 'set_led_mode mode5'
136         run_test '  led1, set attr1=5' '[ "$(cat $SYSPATH/led1/attr1)" = 5 ]'
137         run_test '  led1, set attr2=5' '[ "$(cat $SYSPATH/led1/attr2)" = 5 ]'
138         run_test '  led1, set attr3=5' '[ "$(cat $SYSPATH/led1/attr3)" = 5 ]'
139         run_test '  led2, set attr1=5' '[ "$(cat $SYSPATH/led2/attr1)" = 5 ]'
140         run_test '  led2, set attr2=5' '[ "$(cat $SYSPATH/led2/attr1)" = 5 ]'
141
142         run_test 'commented-out led mode' \
143                 'set_led_mode mode6 2>&1 | grep -q "no mode"'
144
145         chmod -R 700 $SYSPATH
146         rm -fr $SYSPATH
147
148         return $TEST_ERR
149 }
150
151 usage()
152 {
153         cat <<- EOF
154                 Usage: $(basename $0) [options] [mode]
155                   Configure LEDs for specified mode as defined in $CONFILE.
156                   List all modes if none is provided.
157
158                 Options:
159                   --config|-c  use an alternate configuration file
160                   --debug |-d  print debug messages
161                   --tests |-t  run non destructive internal tests
162                   --help  |-h  display this help
163         EOF
164 }
165
166 #
167 # Main
168 #
169
170 while [ $# -gt 0 ]; do
171         case $1 in
172           --config|-c)
173                 CONFILE=$2
174                 shift
175                 ;;
176           --debug|-d)
177                 DEBUG=true
178                 ;;
179           --tests|-t)
180                 TESTS=true
181                 ;;
182           --help|-h)
183                 usage
184                 exit 0
185                 ;;
186           -*)
187                 log_and_die "unknown argument: $1\n\n$(usage)"
188                 ;;
189           *)
190                 MODE=$1
191                 ;;
192         esac
193         shift
194 done
195
196 $TESTS && { run_test_suite; exit $?; }
197
198 [ -n "$(ls -A $SYSPATH 2>/dev/null)" ] || \
199         log_and_die "missing or empty sysfs LED directory: $SYSPATH"
200 [ -e $CONFILE ] || \
201         log_and_die "no configuration file: $CONFILE\n\n$(usage)"
202
203 if [ -n "$MODE" ]; then
204         set_led_mode $MODE
205 else
206         list_led_modes
207 fi