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