added start,stop,restart,reload,force-reload - Service functions
[grml-shlib.git] / sh-lib
1 #!/bin/sh
2 # Filename:      sh-lib
3 # Purpose:       Shellscript library
4 # Authors:       grml-team (grml.org), (c) Michael Gebetsroither <gebi@grml.org>
5 # Bug-Reports:   see http://grml.org/bugs/
6 # License:       This file is licensed under the GPL v2.
7 # Latest change: Mon May 02 00:17:44 CEST 2005 [gebi]
8 ################################################################################
9
10
11 VERBOSE__=0
12 VERBOSE_TMP__=0
13
14 # FIXME maybe PROG_PATH__ for better error reporting?
15 PROG_NAME__=""    # initialised within init section
16
17 # >= level and the function will print the message
18 EPRINT__=1    # eprint (error print)
19 EEPRINT__=2   # 2print (intern error print)
20 DPRINT__=3    # dprint (debug print)
21
22 EXIT_FUNCTION__="_syslog"    # function to call upon die (can be set by user)
23
24 SYSLOG__="YES"
25
26 CMD_LINE__=""   # /proc/cmdline
27
28 LANG__="$LANG"
29 LC_ALL__="$LC_ALL"
30
31
32 # CONFIG FUNCTIONS  {{{
33
34 function setProgName  { PROG_NAME__="$1"; }
35
36 function setExitFunction  { EXIT_FUNCTION__="$1"; }
37
38 function disableSyslog  { SYSLOG__="NO";  }
39 function enableSyslog   { SYSLOG__="YES"; }
40
41 function saveLang { LANG__="$LANG"; LC_ALL__="$LC_ALL"; }
42 function restoreLang { LANG="$LANG__"; LC_ALL="$LC_ALL__"; }
43 function setCLang { saveLang; LANG="C"; LC_ALL="C"; }
44 # }}}
45
46
47 # DEBUG FRAMEWORK  {{{
48
49 function setVerbose     { VERBOSE__=${1:-1}; }
50 function unsetVerbose   { VERBOSE_TMP__=$VERBOSE__; VERBOSE__=0; }
51 function restoreVerbose { VERBOSE__=$VERBOSE_TMP__; }
52 function getVerbose     { echo "$VERBOSE__"; }
53
54 function setDebug       { setVerbose "$DPRINT__"; }
55 function unsetDebug     { restoreVerbose; }
56
57 function setExitFunction    { EXIT_FUNCTION__="$1"; }
58 function resetExitFunction  { EXIT_FUNCTION__="_syslog"; }
59 # }}}
60
61
62 # ERROR REPORTING FUNCTIONS  {{{
63
64 # default print backend (there may be other functions)
65 function vprint
66 {
67   local level_="$1"
68   local type_="$2"
69   local message_="$3"
70   
71   if [ $VERBOSE__ -ge $level_ -a -n "$message_" ]; then
72     echo -n "$type_" >&2
73     echo "$message_" >&2
74   fi
75 }
76
77 # print error output
78 function eprint
79 {
80   # FIXME vprint should be a var, because we want to call user-defined functions
81   # global var (there should be a syslog, and vprint + syslog function)
82   vprint $EPRINT__ "Error - " "$1"
83 }
84
85 # should be used for intern silentExecutes
86 function eeprint
87 {
88   vprint $EEPRINT__ "  Error2 - " "$1"
89 }
90
91 # print debug output (function intern errors)
92 function dprint
93 {
94   vprint $DPRINT__ "Debug - " "$1"
95 }
96
97 # for program notice messages
98 function notice
99 {
100   vprint $EPRINT__ "Notice - " "$1"
101 }
102
103 function die
104 {
105   local error_message_="$1"   # print this error message
106   local exit_code_="$2"  # command exited with this exit code
107
108   echo -n "PANIC: $error_message_" >&2
109   if [ -n "$2" ]; then
110     echo "; ret($exit_code_)" >&2
111   else
112     echo >&2
113   fi
114
115   if [ -n "$EXIT_FUNCTION__" ]; then
116     $EXIT_FUNCTION__ "$error_message_" "$exit_code_" >&2
117   fi
118   kill $$
119 }
120
121 function warn
122 {
123   local error_message_="$1"   # print this error message
124   local exit_code_="$2"  # command exits with this exit code
125
126   echo -n "WARN: $error_message_" >&2
127   if [ -n "$exit_code_" ]; then
128     echo "; ret($exit_code_)" >&2
129   else
130     echo >&2
131   fi
132 }
133
134 function _syslog
135 {
136   local message_="$1"   # error message
137   local exit_code_="$2"
138
139   if [ "$SYSLOG__" = "YES" ]; then
140     if [ -n "$exit_code_" ]; then
141       logger -p user.alert -t "$PROG_NAME__" -i "$message_ ret($exit_code_)" >&2
142     else
143       logger -p user.alert -t "$PROG_NAME__" -i "$message_" >&2
144     fi
145   fi
146 }
147
148 function syslog
149 {
150   local message_="$1"   # error message
151   local exit_code_="$2"
152   
153   if [ -n "$exit_code_" ]; then
154     logger -p user.alert -t "$PROG_NAME__" -i "$message_ ret($exit_code_)" >&2
155   else
156     logger -p user.alert -t "$PROG_NAME__" -i "$message_" >&2
157   fi
158 }
159
160 function warnLog
161 {
162   local error_message_="$1"   # print this error message
163   local exit_code_="$2"  # command exits with this exit code
164
165   warn "$error_message_" "$exit_code_"
166   syslog "$error_message_" "$exit_code_"
167 }
168 # }}}
169
170
171 ###
172 #
173 # CORE FUNCTIONS
174 #
175 ###
176
177 # i don't want to write exit status controle stuff every time
178 function execute
179 {
180   local to_exec_="$1"   # command to execute
181   local error_function_=${2:-"eprint"}    # function to call on error
182   local message_="$3"   # user supplied error message
183
184   local ret_=''
185
186   eval "$to_exec_"
187   ret_=$?
188
189   if [ $ret_ -eq 127 ]; then
190     syslog "problems executing ( $to_exec_ )" $ret_
191   fi
192   if [ $ret_ -ne 0 ]; then
193     if [ -z "$message_" ]; then
194       $error_function_ "problems executing ( $to_exec_ )" "$ret_"
195     else
196       $error_function_ "$message_" "$ret_"
197     fi
198   fi
199   dprint "exec-$error_function_: ( $to_exec_ ) ret($ret_)"
200   return $ret_
201 }
202
203 function silentExecute
204 {
205   unsetVerbose
206   execute "$@"
207   local ret_=$?
208   restoreVerbose
209   return $ret_
210 }
211
212
213 ###
214 #
215 # TEST FUNCTIONS
216 #
217 ###
218
219 # if the file DOES exist, everything is fine
220 function isExistent
221 {
222   local file_to_test_="$1"    # file to test
223   local error_function_=${2:-"eprint"}    # function to call on error
224   local message_="$3"    # user supplied error message
225
226   if [ ! -e "$file_to_test_" ]; then
227     if [ -z "$message_" ]; then
228       $error_function_ "file does not exist \"$file_to_test_\"" 66
229     else
230       $error_function_ "$message_"
231     fi
232     return 1
233   fi
234   dprint "isExistent(): file \"$1\" does exist => ready to go"
235   return 0
236 }
237
238 function isNotExistent
239 {
240   local file_to_test_="$1"    # file to test
241   local error_function_=${2:-"eprint"}    # function to call on error
242   local message_="$3"    # user supplied error message
243
244   if [ -e "$file_to_test_" ]; then
245     if [ -z "$message_" ]; then
246       $error_function_ "file does allready exist \"$file_to_test_\"" 67
247     else
248       $error_function_ "$message_"
249     fi
250     return 1
251   fi
252   dprint "isNotExistent(): file \"$1\" does not exist => ready to go"
253   return 0
254 }
255
256
257 function checkUser
258 {
259   local to_check_="$1"    # username to check against running process
260   local error_function_=${2:-"eprint"}    # function to call on error
261   local message_="$3"    # user supplied error message
262
263   local user_=''
264
265   user_=`id -un`
266   if [ $user_ != "$to_check_" ]; then
267     if [ -z "$message_" ]; then
268       $error_function_ "username \"$user_\" is not \"$to_check_\"" 77 $exit_function_
269     else
270       $error_function_ "$message_"
271     fi
272     return 1
273   else
274     dprint "checkUser(): accepted, username matches \"$to_check_\""
275     return 0
276   fi
277 }
278
279 function checkId
280 {
281   local to_check_="$1"    # user-id to check against running process
282   local error_function_=${2:-"eprint"}    # function to call on error
283   local message_="$3"    # user supplied error message
284
285   local user_id_=''
286
287   user_id_=`id -u`
288   if [ $user_id_ != "$to_check_" ]; then
289     if [ -z "$message_" ]; then
290       $error_function_ "UID \"$user_id_\" is not \"$to_check_\"" 77
291     else
292       $error_function_ "$message_"
293     fi
294     return 1
295   else
296     dprint "checkId(): accepted, UID matches \"$to_check_\""
297     return 0
298   fi
299 }
300
301 function checkRoot
302 {
303   checkId 0 "$1" "$2"
304 }
305
306
307 function runsFromHd
308 {
309   if [ -e "/etc/grml_cd" ]; then
310     dprint "runsFromHd(): grml is on CD"
311     return 1
312   else
313     dprint "runsFromHd(): grml is on HD"
314     return 0
315   fi
316 }
317
318 function runsFromCd
319 {
320   if [ -e "/etc/grml_cd" ]; then
321     dprint "runsFromCd(): grml is on CD"
322     return 0
323   else
324     dprint "runsFromCd(): grml is on HD"
325     return 1
326   fi
327 }
328
329
330 # secure input from console
331 function secureInput
332 {
333   local to_secure_="$1"
334   
335   local secured_=''
336
337   secured_=`echo -n "$to_secure_" |tr -c '[:alnum:]/.\-,\(\)' '_'`
338   dprint "secureInput(): \"$to_secure_\" => \"$secured_\""
339   echo "$secured_"
340 }
341
342
343 # convert all possible path formats to absolute paths
344 function relToAbs
345 {
346   local relpath_="$1"
347
348   local D_=''
349   local B_=''
350   local abspath_=''
351   local end_path_=''
352
353   D_=`dirname "$relpath_"`
354   B_=`basename "$relpath_"`
355   abspath_=`cd "$D_" 2>/dev/null && pwd || echo "$D_"`/$B_
356   end_path_=`echo "$abspath_" |tr --squeeze-repeats /`
357   dprint "relToAbs(): \"$relpath_\" => \"$end_path_\""
358   echo "$end_path_"
359 }
360
361 # Simple shell grep
362 function stringInFile
363 {
364   local to_test_="$1"   # matching pattern
365   local source_="$2"    # source-file to grep
366
367   if [ ! -e "$source_" ]; then
368     eprint "stringInFile(): \"$source_\" does not exist"
369     return 1
370   fi
371
372   case "$(cat $source_)" in *$to_test_*) return 0;; esac
373   return 1
374 }
375
376 # same for strings
377 function stringInString
378 {
379   local to_test_="$1"   # matching pattern
380   local source_="$2"    # string to search in
381
382   case "$source_" in *$to_test_*) return 0;; esac
383   return 1
384 }
385
386 # get value for bootparam given as first param
387 function getBootParam
388 {
389   local param_to_search_="$1"
390   local result_=''
391
392   stringInString " $param_to_search_=" "$CMD_LINE__" || return 1
393   result_="${CMD_LINE__##*$param_to_search_=}"
394   result_="${result_%%[   ]*}"
395   echo "$result_"
396   return 0
397 }
398
399 # Check boot commandline for specified option
400 function checkBootParam
401 {
402   stringInString " $1" "$CMD_LINE__"
403   return "$?"
404 }
405
406
407 # NETWORK  {{{
408
409 # validates an IP FIXME
410 function netValidIp
411 {
412   local ip_="$1"    # ip addresse to validate
413   local error_function_=${2:-"eprint"}    # function to call on error
414   local message_="$3"    # user supplied error message
415   
416   local ret_=''
417
418   echo "$ip_" | grep -E -q -e '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}.[0-9]{1,3}' \
419     &>/dev/null
420   ret_=$?
421   if [ $ret_ -ne 0 ]; then
422     if [ -z "$message_" ]; then
423       "$error_function_" "ip-addresse \"$ip_\" is NOT valied" $ret_
424     else
425       "$error_function_" "$message_" $ret_
426     fi
427     return 1
428   fi
429
430   dprint "ip-addresse \"$ip_\" is valied" $ret_
431   return $ret_
432 }
433
434 function netGetIfaces
435 {
436   local error_function_=${1:-"eprint"}    # function to call on error
437   local message_="$2"    # user supplied error message
438   local if_=''
439   local ret_=''
440
441   #ip a|grep 'inet ' |awk '$NF !~ /lo/{print $NF}'
442   if_="`ip a|grep 'inet ' |awk '{print $NF}'`"
443   ret_=$?
444   if [ -z "$if_" ]; then
445     if [ -z "$message_" ]; then
446       "$error_function_" "no interfaces found" $ret_
447     else
448       "$error_function_" "$message_" $ret_
449     fi
450     return 1
451   fi
452   dprint "interfaces found" $ret_
453   echo "$if_"
454 }
455
456 # FIXME
457 function netGetDefaultGateway
458 {
459   local error_function_=${1:-"eprint"}    # function to call on error
460   local message_="$2"    # user supplied error message
461   
462   local ip_=''
463   local ret_=''
464   
465   setCLang
466   ip_=`route -n | awk '/^0\.0\.0\.0/{print $2; exit}'`
467   ret_=$?
468   restoreLang
469   if [ -z "$ip_" ]; then
470     if [ -z "$message_" ]; then
471       "$error_function_" "no default gateway found" $ret_
472     else
473       "$error_function_" "$message_" $ret_
474     fi
475     return 1
476   fi
477   dprint "default gateway is \"$ip_\"" $ret_
478   echo "$ip_"
479   return 0
480 }
481
482 # FIXME
483 function netGetNetmask
484 {
485   local iface_="$1"
486   local error_function_=${2:-"eprint"}    # function to call on error
487   local message_="$3"    # user supplied error message
488   
489   local nm_=''
490   local ret_=''
491   
492   setCLang
493   nm_=`ifconfig "$iface_" | awk '/[Mm]ask/{FS="[:   ]*"; $0=$0; print $8; exit}'`
494   ret_=$?
495   restoreLang
496   if [ -z "$nm_" ]; then
497     if [ -z "$message_" ]; then
498       "$error_function_" "could not find a netmask for \"$iface_\"" $ret_
499     else 
500       "$error_function_" "$message_" $ret_
501     fi
502     return 1
503   fi
504   dprint "netmask on \"$iface_\" is \"$nm_\"" $ret_
505   echo "$nm_"
506   return 0
507 }
508
509 # FIXME
510 function netGetIp
511 {
512   local iface_="$1"
513   local error_function_=${2:-"eprint"}    # function to call on error
514   local message_="$3"    # user supplied error message
515
516   local ip_=""
517   local ret_=""
518
519   setCLang
520   #ip_=`ip addr list eth0 |mawk '/inet/{split($2,A,"/"); print A[1]}'`
521   ip_=`ifconfig "$iface_" | awk '/[Ii]net [Aa]ddr/{FS="[:  ]*"; $0=$0; print $4; exit}'`
522   ret_=$?
523   restoreLang
524   if [ -z "$ip_" ]; then
525     if [ -z "$message_" ]; then
526       "$error_function_" "no ip for \"$iface_\" found" $ret_
527     else
528       "$error_function_" "$message_" $ret_
529     fi
530     return 1
531   fi
532   dprint "addresse for \"$iface_\" is \"$ip_\"" $ret_
533   echo "$ip_"
534   return 0
535
536
537 function netGetNameservers
538 {
539   local error_function_=${1:-"eprint"}    # function to call on error
540   local message_="$2"    # user supplied error message
541   
542   local file_="/etc/resolv.conf"
543   local ns_=""
544
545   if [ ! -e $file_ ]; then
546     warn "file \"$file_\" does not exist, could not get nameservers"
547     return 1
548   fi
549   
550   setCLang
551   ns_=`awk '/^nameserver/{printf "%s ",$2}' $file_`
552   restoreLang
553   if [ -z "$ns_" ]; then
554     if [ -z "$message_" ]; then
555       "$error_function_" "no nameservers found" $ret_
556     else
557       "$error_function_" "$message_" $ret_
558     fi
559     return 1
560   fi
561   dprint "nameservers: \"$ns_\"" $ret_
562   echo "$ns_"
563   return 0
564 }
565
566 # }}}
567
568 # SERVICES {{{
569 function _touchService
570 {
571   local action_="${1:-"start"}"
572   local service_="$2"
573   local error_function_=${3:-"eprint"}    # function to call on error
574
575   local i=""
576   for i in "start" "stop" "restart" "reload" "force-reload"; do
577     if [[ $i == $action_ ]]; then
578       break
579     fi
580     $error_function_ "unknown action: \"$action\""
581     return 1
582   done
583
584   if [ ! -e "$service_" ]; then
585     $error_function_ "service does not exist: \"$service_\""
586     return 1
587   fi
588   if [ ! -x "$service_" ]; then
589     $error_function_ "service is not executable: \"$service_\""
590   fi
591   
592   /etc/init.d/$service_ $action_
593 }
594
595 function _createServiceFunctions
596 {
597   for i in "start" "stop" "restart" "reload" "force-reload"; do
598     eval "\
599 function ${i}Service
600 {
601   local service_=\"\$1\"
602   local error_function_=\${2:-\"eprint\"}    # function to call on error
603   local message_=\"\$3\"    # user supplied error message
604   
605   local ret_=\"\"
606   _touchService ${i} \"\$service_\"
607   ret_=\$?
608   if [[ \$ret_ != 0 ]]; then
609     if [ -z \"\$message_\" ]; then
610       \"\$error_function_\" \"Problems ${i}ing service \"\$service_\"\" \$ret_
611     else
612       \"\$error_function_\" \"\$message_\" \$ret_
613     fi
614     return 1
615   fi
616 }"
617   done
618 }
619 _createServiceFunctions
620
621 # }}}
622
623 # prints the next free /dev/loop* to stdout
624 function findNextFreeLoop
625 {
626   local error_function_=${1:-"eprint"}    # function to call on error
627   local message_="$2"    # user supplied error message
628
629   local tmp_=''   # tmp
630   local i=''      # counter
631   local ret_=''   # saved return value
632   
633   for i in 'losetup' 'losetup.orig'; do
634     tmp_=`$i -f 2>/dev/null`
635     if [ $? -eq 0 ]; then
636       echo $tmp_
637       return 0
638     fi
639   done
640
641   # we have to search
642   dprint 'findNextFreeLoop(): losetup does not recognice option -f, searching next free loop device'
643   for i in `seq 0 100`; do
644     test -e /dev/loop$i || continue
645     losetup /dev/loop$i &>/dev/null
646     ret_=$?
647     case "$ret_" in
648       2) continue ;;  # losetup could not get status of loopdevice (EPERM)
649       0) continue ;;  # device exist
650       1) echo "/dev/loop$i"; return 0 ;;  # device does not exist and no error
651       ?) continue ;;  # return value not available in 'man losetup'
652     esac
653   done
654
655   # hmm... could not find a loopdevice
656   if [ -z "$message_" ]; then
657     $error_function_ "could not find a free loop device"
658   else
659     $error_function_ "$message_"
660   fi
661   return 1
662 }
663
664
665 # INIT {{{
666
667 function _initProgName
668 {
669   local name_="$1"    # program name
670   
671   local tmp_name_=`basename "$name_"` || \
672     logger -p user.alert -i "Init-initProgName: problems executing ( basename \"$name_\" ) ret($?)" >/dev/null
673   
674   secureInput "$tmp_name_"
675 }
676 PROG_NAME__=`_initProgName "$0"`
677
678
679 function _checkExecutables
680 {
681   local tmp_=""
682   for i in tr dirname basename id logger kill cat grep route awk ifconfig; do
683     type -p $i &>/dev/null || tmp_="${tmp_}$i "
684   done
685   if [ -n "$tmp_" ]; then
686     eprint "Init-checkExecutables: following executables not found or not executable:\n$tmp_"
687     #syslog "Init-checkExecutables: following executables not found or not executable: $tmp_"
688   fi
689 }
690 _checkExecutables
691
692
693 function _checkBootParam
694 {
695   local path_="/proc/cmdline"
696   if [ -e "$path_" ]; then
697     CMD_LINE__=`execute "cat $path_" warnLog`
698     return 0
699   fi
700   warnLog "$path_ does not exist, thus sh-lib may not work reliable!"
701   return 1
702 }
703 _checkBootParam
704
705
706 function _setDebugLevel
707 {
708   local debug_="${DEBUG:-0}"
709   VERBOSE__="$debug_"
710 }
711 _checkBootParam
712 # }}}
713
714 # END OF FILE
715 ################################################################################
716 # vim:foldmethod=marker expandtab shiftwidth=2 tabstop=2