tab to space fix
[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
569 # prints the next free /dev/loop* to stdout
570 function findNextFreeLoop
571 {
572   local error_function_=${1:-"eprint"}    # function to call on error
573   local message_="$2"    # user supplied error message
574
575   local tmp_=''   # tmp
576   local i=''      # counter
577   local ret_=''   # saved return value
578   
579   for i in 'losetup' 'losetup.orig'; do
580     tmp_=`$i -f 2>/dev/null`
581     if [ $? -eq 0 ]; then
582       echo $tmp_
583       return 0
584     fi
585   done
586
587   # we have to search
588   dprint 'findNextFreeLoop(): losetup does not recognice option -f, searching next free loop device'
589   for i in `seq 0 100`; do
590     test -e /dev/loop$i || continue
591     losetup /dev/loop$i &>/dev/null
592     ret_=$?
593     case "$ret_" in
594       2) continue ;;  # losetup could not get status of loopdevice (EPERM)
595       0) continue ;;  # device exist
596       1) echo "/dev/loop$i"; return 0 ;;  # device does not exist and no error
597       ?) continue ;;  # return value not available in 'man losetup'
598     esac
599   done
600
601   # hmm... could not find a loopdevice
602   if [ -z "$message_" ]; then
603     $error_function_ "could not find a free loop device"
604   else
605     $error_function_ "$message_"
606   fi
607   return 1
608 }
609
610
611 # INIT {{{
612
613 function _initProgName
614 {
615   local name_="$1"    # program name
616   
617   local tmp_name_=`basename "$name_"` || \
618     logger -p user.alert -i "Init-initProgName: problems executing ( basename \"$name_\" ) ret($?)" >/dev/null
619   
620   secureInput "$tmp_name_"
621 }
622 PROG_NAME__=`_initProgName "$0"`
623
624
625 function _checkExecutables
626 {
627   local tmp_=""
628   for i in tr dirname basename id logger kill cat grep route awk ifconfig; do
629     type -p $i &>/dev/null || tmp_="${tmp_}$i "
630   done
631   if [ -n "$tmp_" ]; then
632     eprint "Init-checkExecutables: following executables not found or not executable:\n$tmp_"
633     #syslog "Init-checkExecutables: following executables not found or not executable: $tmp_"
634   fi
635 }
636 _checkExecutables
637
638
639 function _checkBootParam
640 {
641   local path_="/proc/cmdline"
642   if [ -e "$path_" ]; then
643     CMD_LINE__=`execute "cat $path_" warnLog`
644     return 0
645   fi
646   warnLog "$path_ does not exist, thus sh-lib may not work reliable!"
647   return 1
648 }
649 _checkBootParam
650
651
652 function _setDebugLevel
653 {
654   local debug_="${DEBUG:-0}"
655   VERBOSE__="$debug_"
656 }
657 _checkBootParam
658 # }}}
659
660 # END OF FILE
661 ################################################################################
662 # vim:foldmethod=marker expandtab shiftwidth=2 tabstop=2