f8a22ba08beca37ce91473ed0a26586cf803156e
[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" && echo "$1 : OK" || { echo "$1 : FAIL"; TEST_ERR=1; }
64 }
65
66 run_test_suite()
67 {
68         TEST_ERR=0
69         TEST_DIR=/tmp/$(basename $0)-test-$$
70
71         SYSPATH=$TEST_DIR/leds
72         mkdir -p $SYSPATH/led1
73         touch $SYSPATH/led1/attr1
74         touch $SYSPATH/led1/attr2
75         touch $SYSPATH/led1/attr3
76         mkdir -p $SYSPATH/led2
77         touch $SYSPATH/led2/attr1
78         touch $SYSPATH/led2/attr2
79         mkdir -p $SYSPATH/led\ 3
80         touch $SYSPATH/led\ 3/attr1
81         mkdir -p $SYSPATH/led\ 4
82         touch $SYSPATH/led\ 4/attr1
83         find $SYSPATH -type d -exec chmod 500 '{}' +
84
85         CONFILE=$TEST_DIR/conf
86         cat > $CONFILE <<- EOF
87                 {mode1}
88                 led1            =value
89
90                 {mode2}
91                 led1            attr1=
92
93                 {mode3}
94                 *               attr1=3
95                 led[0-9]        attr2=3
96
97                 {mode4}
98                 led\ [0-9]      attr1=4
99
100                 {mode5}
101                 #{mode6}
102                 led1            attr1=5 attr2=5 attr3=5
103                 led2            attr1=5 attr2=5 # some comments
104                 #led3           attr1=5
105         EOF
106
107         run_test 'non-defined led mode' \
108                 'set_led_mode nomatch 2>&1 | grep -q "no mode"'
109
110         run_test 'match empty attribute name' \
111                 'set_led_mode mode1 2>&1 | grep -q "invalid setting"'
112
113         run_test 'match empty attribute value' \
114                 'set_led_mode mode2 2>&1 | grep -q "invalid setting"'
115
116         run_test 'led name with wildcard and globbing' 'set_led_mode mode3'
117         run_test '  led1, set attr1=3' '[ "$(cat $SYSPATH/led1/attr1)" = 3 ]'
118         run_test '  led2, set attr1=3' '[ "$(cat $SYSPATH/led2/attr1)" = 3 ]'
119         run_test '  led 3, set attr1=3' '[ "$(cat $SYSPATH/led\ 3/attr1)" = 3 ]'
120         run_test '  led1, set attr2=3' '[ "$(cat $SYSPATH/led1/attr2)" = 3 ]'
121         run_test '  led2, set attr2=3' '[ "$(cat $SYSPATH/led2/attr2)" = 3 ]'
122
123         run_test 'led name with whitespace and globbing' 'set_led_mode mode4'
124         run_test '  led 3, set attr1=4' '[ "$(cat $SYSPATH/led\ 3/attr1)" = 4 ]'
125         run_test '  led 4, set attr1=4' '[ "$(cat $SYSPATH/led\ 4/attr1)" = 4 ]'
126
127         run_test 'multiple attributes and discarded comments' \
128                 'set_led_mode mode5'
129         run_test '  led1, set attr1=5' '[ "$(cat $SYSPATH/led1/attr1)" = 5 ]'
130         run_test '  led1, set attr2=5' '[ "$(cat $SYSPATH/led1/attr2)" = 5 ]'
131         run_test '  led1, set attr3=5' '[ "$(cat $SYSPATH/led1/attr3)" = 5 ]'
132         run_test '  led2, set attr1=5' '[ "$(cat $SYSPATH/led2/attr1)" = 5 ]'
133         run_test '  led2, set attr2=5' '[ "$(cat $SYSPATH/led2/attr1)" = 5 ]'
134
135         run_test 'commented-out led mode' \
136                 'set_led_mode mode6 2>&1 | grep -q "no mode"'
137
138         chmod -R u+w $SYSPATH
139         rm -fr $TEST_DIR
140
141         return $TEST_ERR
142 }
143
144 usage()
145 {
146         cat <<- EOF
147                 Usage: $(basename $0) [options] [mode]
148                   Configure LEDs for specified mode as defined in $CONFILE.
149                   List all modes if none is provided.
150
151                 Options:
152                   --config|-c  use an alternate configuration file
153                   --debug |-d  print debug messages
154                   --tests |-t  run non destructive internal tests
155                   --help  |-h  display this help
156         EOF
157 }
158
159 #
160 # Main
161 #
162
163 while [ $# -gt 0 ]; do
164         case $1 in
165                 --config|-c) CONFILE=$2; shift ;;
166                 --debug |-d) DEBUG=true ;;
167                 --tests |-t) TESTS=true ;;
168                 --help  |-h) HELP=true ;;
169                 -*         ) log_and_die "unknown argument: $1\n\n$(usage)" ;;
170                 *          ) MODE=$1 ;;
171         esac
172         shift
173 done
174
175 $HELP && usage
176 $TESTS && run_test_suite
177 { $HELP || $TESTS ;} && exit 0
178
179 [ -n "$(ls -A $SYSPATH 2>/dev/null)" ] || \
180         log_and_die "missing or empty sysfs LED directory: $SYSPATH"
181 [ -e $CONFILE ] || log_and_die "no configuration file: $CONFILE\n\n$(usage)"
182
183 if [ -n "$MODE" ]; then
184         set_led_mode $MODE
185 else
186         list_led_modes
187 fi