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