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