r100: _cp_customize, with function dependancies
[carnet-tools-cn.git] / functions.sh
1 # Initialize "public" CP_ECHO_RETURN variable once
2 if [ -z "$_CP_INIT_ECHO_RETURN" ]; then
3   _CP_INIT_ECHO_RETURN=1
4   CP_ECHO_RETURN=""
5 fi
6
7 # by ddzeko & ico, Fri, 18 Mar 2005 14:44:08 +0100
8 cp_get_ifaddr() {
9   [ "$CP_SCRIPT_DEBUG" ] && set -vx
10
11   local ifaddr interface echo_return
12   echo_return="$CP_ECHO_RETURN" # since we're making our own calls
13   # in our own way we need to set CP_ECHO_RETURN the way we want it
14   # but preserving initial state so it could be used afterwards
15   CP_ECHO_RETURN=""
16
17   interface="$1"
18   if [ -z "$interface" ]; then
19     cp_get_ifdefault dev
20     interface="$RET"
21     [ -z "$interface" ] && interface=lo
22   fi
23
24   if ! ifconfig $interface 2> /dev/null >> /dev/null; then
25     echo "cp_get_ifaddr: $interface: No such interface" 1>&2
26     CP_ECHO_RETURN="$echo_return"
27     return 2
28   fi
29
30   ifaddr="`/sbin/ifconfig $interface | awk '/inet/{ printf("%s\n",substr($2,index($2,":")+1)) }'`"
31
32   if [ -z $ifaddr ]; then
33     echo "cp_get_ifaddr: $interface: No ip address found" 1>&2
34     CP_ECHO_RETURN="$echo_return"
35     return 1
36   fi
37
38   RET="$ifaddr"
39   [ -z "$echo_return" ] || echo $RET
40   CP_ECHO_RETURN="$echo_return"
41 }
42
43 # by ddzeko & ico, Fri, 18 Mar 2005 14:44:08 +0100
44 cp_get_ifmask() {
45   [ "$CP_SCRIPT_DEBUG" ] && set -vx
46
47   local ifmask interface echo_return
48   echo_return="$CP_ECHO_RETURN" # since we're making our own calls
49   # in our own way we need to set CP_ECHO_RETURN the way we want it
50   # but preserving initial state so it could be used afterwards
51   CP_ECHO_RETURN=""
52
53   interface="$1"
54   if [ -z "$interface" ]; then
55     cp_get_ifdefault dev
56     interface="$RET"
57     [ -z "$interface" ] && interface=lo
58   fi
59
60   if ! ifconfig $interface 2> /dev/null >> /dev/null; then
61     echo "cp_get_ifmask: $interface: No such interface" 1>&2
62     CP_ECHO_RETURN="$echo_return"
63     return 1
64   fi
65
66   ifmask="`/sbin/ifconfig $interface | awk '/Mask/{if($3~/Mask/)a=$3;else if ($4~/Mask/)a=$4;printf ("%s\n", substr(a,index(a,":")+1))}'`"
67
68   if [ -z "$ifmask" ]; then
69     echo "cp_get_ifmask: $interface: No netmask found" 1>&2
70     CP_ECHO_RETURN="$echo_return"
71     return 1
72   fi
73
74   RET="$ifmask"
75   [ -z "$echo_return" ] || echo $RET
76   CP_ECHO_RETURN="$echo_return"
77 }
78
79 # by ddzeko, Mon, 21 Mar 2005 07:00:22 +0100
80 cp_get_ifdefault() {
81   [ "$CP_SCRIPT_DEBUG" ] && set -vx
82
83   local echo_return
84   echo_return="$CP_ECHO_RETURN" # since we're making our own calls
85   # in our own way we need to set CP_ECHO_RETURN the way we want it
86   # but preserving initial state so it could be used afterwards
87   CP_ECHO_RETURN=""
88
89   RET=""
90   case $1 in
91     dev)
92       RET=`route -n | awk 'BEGIN {m = 2^32}
93                     /^0\.0\.0\.0[ \t]/ {if ($5 < m) {r = $8; m = $5}}
94                              END {print r}'`
95       ;;
96     addr)
97       RET=`route -n | awk 'BEGIN {m = 2^32}
98                     /^0\.0\.0\.0[ \t]/ {if ($5 < m) {r = $2; m = $5}}
99                              END {print r}'`
100       ;;
101     *)
102       echo "cp_get_ifdefault: Argument required (dev or addr)" >&2
103       ;;
104   esac
105
106   [ -z "$RET" -a "$1" ] && echo "cp_get_ifdefault: No default route" >&2
107
108   [ -z "$echo_return" ] || echo $RET
109   CP_ECHO_RETURN="$echo_return"
110   [ -n "$RET" ] || return 1
111 }
112
113 # by ico, Tue, 15 Mar 2005 14:04:21 +0100
114 cp_get_netaddr() {
115   [ "$CP_SCRIPT_DEBUG" ] && set -vx
116
117   local netmask ipaddress interface cidr echo_return
118   echo_return="$CP_ECHO_RETURN" # since we're making our own calls
119   # in our own way we need to set CP_ECHO_RETURN the way we want it
120   # but preserving initial state so it could be used afterwards
121   CP_ECHO_RETURN=""
122
123   interface="$1"
124   if [ -z "$interface" ]; then
125     cp_get_ifdefault dev
126     interface="$RET"
127     [ -z "$interface" ] && interface=lo
128   fi
129
130   if ! ifconfig $interface 2> /dev/null >> /dev/null; then
131     echo "cp_get_netaddr: $interface: No such interface" 1>&2
132     CP_ECHO_RETURN="$echo_return"
133     return 1
134   fi
135
136   cp_get_ifaddr "$interface"
137   ipaddress="$RET"
138   if [ -z $ipaddress ]; then
139     echo "cp_get_netaddr: $interface: No IP address found" 1>&2
140     CP_ECHO_RETURN="$echo_return"
141     return 1
142   fi
143   cp_get_ifmask "$interface"
144   netmask="$RET"
145   if [ -z $netmask ]; then
146     echo "cp_get_netaddr: $interface: No netmask found" 1>&2
147     CP_ECHO_RETURN="$echo_return"
148     return 1
149   fi
150
151   if [ "$netmask" = "255.255.255.255" ]; then
152     cidr="$ipaddress/32"
153   else 
154     cidr="`ipcalc -ncb $ipaddress $netmask | awk '/^Network:/{print $2}'`"
155   fi
156   
157   RET="$cidr"
158   [ -z "$echo_return" ] || echo $RET
159   CP_ECHO_RETURN="$echo_return"
160 }
161
162 cp_check_and_backup() {
163   [ "$CP_SCRIPT_DEBUG" ] && set -vx
164
165   cp_backup_conffile -r "$@"
166 }
167
168 # by ico, Tue, 15 Mar 2005 14:04:21 +0100
169 cp_backup_conffile() {
170   [ "$CP_SCRIPT_DEBUG" ] && set -vx
171
172   local dir ext file_bak check did opt_p opt_d
173   
174   dir=/var/backups
175   ext=.bak
176   
177   while echo "x$1" |grep -q '^x-'; do
178     case "$1" in
179     -r)
180       shift
181       check=1
182       ;;
183     -p)
184       shift
185       opt_p=1
186       ;;
187     -d)
188       shift
189       opt_d=1
190       # Is argument to -d full path or relative?
191       if echo "$1" |grep -q '^/'; then
192         dir="$1"
193       else
194         dir="$dir/$1"
195       fi
196       shift
197       ;;
198     -n)
199       shift
200       ext=
201       ;;
202     esac
203   done
204   if [ "$opt_d" ]; then
205     if [ ! -e "$dir" -a "$opt_p" ]; then
206       mkdir "$dir"
207     fi
208     if [ $? -ne 0 ]; then
209       echo "cp_backup_conffile: Error creating backup directory $dir" 1>&2
210       return 3
211     fi
212   fi
213   if [ ! -d "$dir" ]; then
214     echo "cp_backup_conffile: Invalid backup directory $dir" 1>&2
215     return 3
216   fi
217   if [ -z "$1" ]; then
218     return 1
219   fi
220   if [ ! -f "$1" ]; then
221     echo "cp_backup_conffile: $1: No such file" 1>&2
222     return 2
223   fi
224   if [ -z "$2" ]; then
225     file_bak="$dir/`basename $1`$ext"
226   else
227     file_bak="$dir/`basename $2`$ext"
228   fi
229
230   if [ ! -f "$file_bak" ]; then
231     cp -pf "$1" "$file_bak"
232     did=1
233   else
234     if ! cmp -s "$1" "$file_bak"; then
235       /usr/bin/savelog -p -c 7 "$file_bak" > /dev/null 2> /dev/null
236       cp -pf "$1" "$file_bak"
237       did=1
238     fi
239   fi
240
241   [ -z "$check" ] && return 0
242
243   if [ "$check" -a ! "$did" ]; then
244     return 3
245   else
246     return 0
247   fi
248 }
249
250 # by jelly, Tue, 15 Mar 2005 14:04:21 +0100
251 # modified by ico, Mon,  6 Jun 2005 11:58:08 +0200
252 # A sed wrapper, to use instead of perl -pi -e
253 #  - relatively safe in-place s///g
254 #  - takes care of symlinks and ownership
255 # returns true if changed, false if nothing happened
256 #
257 cp_check_and_sed() {
258   [ "$CP_SCRIPT_DEBUG" ] && set -vx
259
260   local s sedcmd grepret ret i
261   if [ -z "$3" ]; then
262     return 1
263   fi
264   s="$1"
265   shift
266   sedcmd="$1"
267   shift
268   ret=2
269   for i in "$@"
270   do
271     [ -e "$i" ]        || continue
272     if ! egrep -q "$s" "$i"; then
273       grepret=1
274       continue
275     fi
276     [ -h "$i" ]        && i=$(readlink -f "$i")
277     sed "$sedcmd" "$i" > "$i.dpkg-tmp"
278     if [ $? -ne 0 ]; then
279       rm "$i.dpkg-tmp"
280       echo "cp_check_and_sed: Problem with sed" 1>&2
281       return 5
282     fi
283     if ! cmp -s "$i" "$i.dpkg-tmp" 2>&1 >/dev/null; then
284       cp_mv "$i.dpkg-tmp" "$i"
285     else
286       rm "$i.dpkg-tmp"
287     fi
288     ret=0
289   done
290   [ "$ret" -eq 2 -a "$grepret" ] && ret=1
291   return $ret
292 }
293
294 # by jelly, Sun, 20 Mar 2005 20:12:19 +0100
295 cp_echo () {
296   [ "$CP_SCRIPT_DEBUG" ] && set -vx
297
298   if [ "x$1" = "x-mailonly" -o "x$1" = "x-m" ]; then
299     shift
300   else   
301     echo "$*"
302   fi
303   CP_NOTICE="$CP_NOTICE$1"
304   if [ `echo -n "$*" | wc -l` -eq 0 ]; then
305     CP_NOTICE="$CP_NOTICE
306 "
307   fi
308 }   
309
310 # by jelly, Sun, 20 Mar 2005 20:12:19 +0100
311 cp_mail () {
312   [ "$CP_SCRIPT_DEBUG" ] && set -vx
313
314   local pkg version quiet
315   if [ "x$1" = "x-q" ]; then
316     quiet=1
317     shift
318   fi
319   if [ -n "$1" ]; then
320     pkg="$1"
321   else
322     return 1 # must have at least the package name as argument
323   fi
324   [ -n "$2" ] && version=" $2"
325   if [ "$(echo $CP_NOTICE|wc -w)" -gt 0 ]; then
326     [ -n "$quiet" ] || echo "Mailing upgrade output to root."
327     CP_NOTICE="From: $pkg postinst script <root>
328 To: root
329 Subject: $pkg$version package install log
330 Date: $(/bin/date +'%a, %d %b %Y %H:%M:%S %z')
331  
332 Hello!
333
334 The $pkg package has been successfully installed on your computer.
335 For your convenience, a partial output of the last $pkg installation
336 is included below.
337
338 ----------
339 ${CP_NOTICE}----------"
340   
341     echo "$CP_NOTICE" | /usr/sbin/sendmail -t &
342     sleep 1
343   fi
344 }
345
346 # by ddzeko, Mon, 21 Mar 2005 11:31:59 +0100
347 cp_mv () {
348   [ "$CP_SCRIPT_DEBUG" ] && set -vx
349
350   local new old
351   if [ -z "$2" ]; then
352     return 1
353   fi
354   new="$1"
355   old="$2"
356   if [ -e "$old" ]; then
357     chown --reference "$old" "$new"
358     chmod --reference "$old" "$new"
359   fi
360   mv "$new" "$old"
361 }
362
363 # by ddzeko, Mon, 21 Mar 2005 13:35:42 +0100
364 cp_yes_no () {
365   [ "$CP_SCRIPT_DEBUG" ] && set -vx
366   local prompt answer
367   prompt="$1"
368   [ "$prompt" ] || prompt="Are you sure?"
369   RET=""
370
371   # check to prevent user from using this when debconf is active
372   # (it would break communication with its backend - uses stdin/out)
373   if [ "$DEBCONF_REDIR" ]; then
374     echo "cp_yes_no: debconf redirection detected" >&2
375     return 1
376   fi
377
378   echo -n "$prompt (y)es/(n)o: "
379   read answer
380   case "$answer" in
381     y*)
382       echo
383       RET=y
384       ;;
385     n*)
386       echo
387       RET=n
388       ;;
389     *)
390       echo
391       echo "Please read the message and choose y or n"
392       cp_yes_no
393       ;;
394   esac
395 }
396
397 # by ddzeko, Tue, 29 Mar 2005 17:37:52 +0200
398 #
399 # db_get seems to return error messages if the requested variable 
400 # is not found - we do not find that desirable, and checking $? with
401 # set -e turned on seems to be a bit of a problem
402 # --> that's why we wrap the db_get call to return unset RET variable
403 #     instead of some gibberish error message that our script does
404 #     not expect
405 cp_db_get() {
406   [ "$CP_SCRIPT_DEBUG" ] && set -vx
407
408   local var
409   var="$1"
410   
411   # check to prevent user from using this before activating debconf
412   # confmodule needs to be loaded before accessing db_* functions
413   if [ -z "$DEBCONF_REDIR" ]; then
414     echo "cp_db_get: debconf not activated!" >&2
415     return 1
416   fi
417  
418   if ! db_get "$var"; then
419     case "$RET" in
420         *doesn\'t\ exist)
421           RET=""
422           ;;
423         [0-9][0-9]\ ?*) # other errors
424           RET=""
425           ;;
426     esac
427   fi
428 }
429
430 # by ico, Wed, 20 Apr 2005 21:09:54 +0200
431 cp_get_ldap_suffix() {
432   [ "$CP_SCRIPT_DEBUG" ] && set -vx
433
434   local echo_return
435   echo_return="$CP_ECHO_RETURN" # since we're making our own calls
436   # in our own way we need to set CP_ECHO_RETURN the way we want it
437   # but preserving initial state so it could be used afterwards
438   CP_ECHO_RETURN=""
439
440   if [ ! -f /etc/ldap/slapd.conf ]; then
441     echo "cp_get_ldap_suffix: /etc/ldap/slapd.conf: No such file" >&2
442     return 2
443   fi
444   
445   RET="`awk  '/^suffix/      { exit }
446               END            { gsub(/"/, "", $2); print $2 }' \
447              < /etc/ldap/slapd.conf`"
448
449   if [ "`echo $RET | sed 's/,/ /g' | wc -w`" -gt 2 ]; then
450     RET=""
451     echo "cp_get_ldap_suffix: Invalid LDAP suffix in /etc/ldap/slapd.conf" >&2
452     return 2
453   fi
454     
455   [ -z "$RET" ] && echo "cp_get_ldap_suffix: No LDAP suffix in /etc/ldap/slapd.conf" >&2
456   [ -z "$echo_return" ] || echo $RET
457   CP_ECHO_RETURN="$echo_return"
458 }
459
460 # by ico, Wed, 20 Apr 2005 21:09:54 +0200
461 cp_get_ldap_realm() {
462   [ "$CP_SCRIPT_DEBUG" ] && set -vx
463
464   local echo_return
465   echo_return="$CP_ECHO_RETURN" # since we're making our own calls
466   # in our own way we need to set CP_ECHO_RETURN the way we want it
467   # but preserving initial state so it could be used afterwards
468   CP_ECHO_RETURN=""
469
470   if [ ! -f /etc/ldap/slapd.conf ]; then
471     echo "cp_get_ldap_realm: /etc/ldap/slapd.conf: No such file" >&2
472     return 2
473   fi
474  
475   cp_get_ldap_suffix || true
476   RET="`echo $RET | awk -F, '{print $1}' | awk -F= '{print $2}'`"
477
478   [ -z "$RET" ] && echo "cp_get_ldap_realm: No LDAP REALM in /etc/ldap/slapd.conf" >&2
479   [ -z "$echo_return" ] || echo $RET
480   CP_ECHO_RETURN="$echo_return"
481 }
482
483 _cp_customize() {
484   [ "$CP_SCRIPT_DEBUG" ] && set -vx
485   # < input functions > output_functions
486   # new-prefix list-of-functions
487   perl -e '
488     $prefix = shift; %keep = (); $output = "";
489     $keep{$_} = 1 for @ARGV;
490     # add dependent functions
491     %deps = (
492       get_ifaddr       => [ "get_ifdefault" ],
493       get_netaddr      => [ "get_ifdefault", "get_ifaddr", "get_ifmask" ],
494       check_and_backup => [ "backup_conffile" ],
495       check_and_sed    => [ "mv" ],
496       get_ldap_realm   => [ "get_ldap_suffix" ],
497     );
498     foreach my $f (keys(%keep)) {
499       if (exists($deps{$f})) {
500         $keep{$_} = 1 for (@{$deps{$f}});
501       }
502     }
503     while (<STDIN>) {
504       if (/^_?cp_(\w+) *\(\) *\{/) {
505         if (! exists($keep{$1})) {
506           while (<STDIN>) { last if /^\}/; } # skip it
507           next;
508         } else {
509           $output .= "\n";
510         }
511       }
512       next if /^\s*(\#|$)/;
513       $output .= $_;
514     }
515     $output =~ s/\b(_?)cp_/$1${prefix}_/sg;
516     $prefix = uc($prefix);
517     $output =~ s/\b(_?)CP_/$1${prefix}_/sg;
518     print $output;
519   ' -- $*
520 }