* Ispravak za cp_mail: pokusava se pozvati sendmail wrapper cak i kad ne
[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 -nb $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: $(LC_ALL=C /bin/date --rfc-2822)
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     if [ -x /usr/sbin/sendmail ]; then
342       echo "$CP_NOTICE" | /usr/sbin/sendmail -t -oi &
343       sleep 1
344     fi
345   fi
346 }
347
348 # by ddzeko, Mon, 21 Mar 2005 11:31:59 +0100
349 cp_mv () {
350   [ "$CP_SCRIPT_DEBUG" ] && set -vx
351
352   local new old
353   if [ -z "$2" ]; then
354     return 1
355   fi
356   new="$1"
357   old="$2"
358   if [ -e "$old" ]; then
359     chown --reference "$old" "$new"
360     chmod --reference "$old" "$new"
361     cp -pf "$old" "$old.cn-old"
362   fi
363   mv "$new" "$old"
364 }
365
366 # by ddzeko, Mon, 21 Mar 2005 13:35:42 +0100
367 cp_yes_no () {
368   [ "$CP_SCRIPT_DEBUG" ] && set -vx
369   local prompt answer
370   prompt="$1"
371   [ "$prompt" ] || prompt="Are you sure?"
372   RET=""
373
374   # check to prevent user from using this when debconf is active
375   # (it would break communication with its backend - uses stdin/out)
376   if [ "$DEBCONF_REDIR" ]; then
377     echo "cp_yes_no: debconf redirection detected" >&2
378     return 1
379   fi
380
381   echo -n "$prompt (y)es/(n)o: "
382   read answer
383   case "$answer" in
384     Y*)
385       echo
386       RET=y
387       ;;
388     N*)
389       echo
390       RET=n
391       ;;
392     y*)
393       echo
394       RET=y
395       ;;
396     n*)
397       echo
398       RET=n
399       ;;
400     *)
401       echo
402       echo "Please read the message and choose y or n"
403       cp_yes_no "$prompt"
404       ;;
405   esac
406 }
407
408 # by ddzeko, Tue, 29 Mar 2005 17:37:52 +0200
409 #
410 # db_get seems to return error messages if the requested variable 
411 # is not found - we do not find that desirable, and checking $? with
412 # set -e turned on seems to be a bit of a problem
413 # --> that's why we wrap the db_get call to return unset RET variable
414 #     instead of some gibberish error message that our script does
415 #     not expect
416 cp_db_get() {
417   [ "$CP_SCRIPT_DEBUG" ] && set -vx
418
419   local var
420   var="$1"
421   
422   # check to prevent user from using this before activating debconf
423   # confmodule needs to be loaded before accessing db_* functions
424   if [ -z "$DEBCONF_REDIR" ]; then
425     echo "cp_db_get: debconf not activated!" >&2
426     return 1
427   fi
428  
429   if ! db_get "$var"; then
430     case "$RET" in
431         *doesn\'t\ exist)
432           RET=""
433           ;;
434         [0-9][0-9]\ ?*) # other errors
435           RET=""
436           ;;
437     esac
438   fi
439 }
440
441 # by ico, Wed, 20 Apr 2005 21:09:54 +0200
442 cp_get_ldap_suffix() {
443   [ "$CP_SCRIPT_DEBUG" ] && set -vx
444
445   local echo_return
446   echo_return="$CP_ECHO_RETURN" # since we're making our own calls
447   # in our own way we need to set CP_ECHO_RETURN the way we want it
448   # but preserving initial state so it could be used afterwards
449   CP_ECHO_RETURN=""
450
451   if [ ! -f /etc/ldap/slapd.conf ]; then
452     echo "cp_get_ldap_suffix: /etc/ldap/slapd.conf: No such file" >&2
453     return 2
454   fi
455   
456   RET="`awk  '/^suffix/      { exit }
457               END            { gsub(/"/, "", $2); print $2 }' \
458              < /etc/ldap/slapd.conf`"
459
460   if [ "`echo $RET | sed 's/,/ /g' | wc -w`" -gt 2 ]; then
461     RET=""
462     echo "cp_get_ldap_suffix: Invalid LDAP suffix in /etc/ldap/slapd.conf" >&2
463     return 2
464   fi
465     
466   [ -z "$RET" ] && echo "cp_get_ldap_suffix: No LDAP suffix in /etc/ldap/slapd.conf" >&2
467   [ -z "$echo_return" ] || echo $RET
468   CP_ECHO_RETURN="$echo_return"
469 }
470
471 # by ico, Wed, 20 Apr 2005 21:09:54 +0200
472 cp_get_ldap_realm() {
473   [ "$CP_SCRIPT_DEBUG" ] && set -vx
474
475   local echo_return
476   echo_return="$CP_ECHO_RETURN" # since we're making our own calls
477   # in our own way we need to set CP_ECHO_RETURN the way we want it
478   # but preserving initial state so it could be used afterwards
479   CP_ECHO_RETURN=""
480
481   if [ ! -f /etc/ldap/slapd.conf ]; then
482     echo "cp_get_ldap_realm: /etc/ldap/slapd.conf: No such file" >&2
483     return 2
484   fi
485  
486   cp_get_ldap_suffix || true
487   RET="`echo $RET | awk -F, '{print $1}' | awk -F= '{print $2}'`"
488
489   [ -z "$RET" ] && echo "cp_get_ldap_realm: No LDAP REALM in /etc/ldap/slapd.conf" >&2
490 }
491
492 # if fqdn is name.dom3.dom2.dom1.hr, check if this host is MX for
493 # either dom3.dom2.dom1.hr, dom2.dom1.hr or dom1.hr and dump highest level
494 # domain on stdout
495 cp_get_mx_domain() {
496   [ "$CP_SCRIPT_DEBUG" ] && set -vx
497
498   local domains d host
499
500   host=$(hostname -f)
501   RET="$host"
502   if ! echo "$host" | grep -q '\.'; then
503     return
504   fi
505   if [ ! -x /usr/bin/host ]; then
506     # no host command
507     return
508   fi
509   domains=$(/bin/hostname -f | awk -F. '
510     {
511       for (i=2; i<NF; i++) { 
512         for (j=i; j<NF; j++) {
513           printf "%s", $(j)"."
514         };
515         print $NF
516       }
517     }'    )
518   for d in $domains
519   do
520     mxes=$(/usr/bin/host -t mx $d)
521     # handle output of both /usr/bin/host providers
522     mxes=$(echo "$mxes"|\
523            awk '/mail is handled by/ || /MX/ {print $NF}'|sed 's/\.$//')
524     if echo "$mxes" |egrep -q "^$host$"; then
525       RET="$d"
526     fi
527   done
528
529   [ -z "$CP_ECHO_RETURN" ] || echo "$RET"
530 }
531
532 _cp_customize() {
533   [ "$CP_SCRIPT_DEBUG" ] && set -vx
534   # < input functions > output_functions
535   # new-prefix list-of-functions
536   perl -e '
537     $prefix = shift; %keep = (); $output = "";
538     $keep{$_} = 1 for @ARGV;
539     # add dependent functions
540     %deps = (
541       get_ifaddr       => [ "get_ifdefault" ],
542       get_netaddr      => [ "get_ifdefault", "get_ifaddr", "get_ifmask" ],
543       check_and_backup => [ "backup_conffile" ],
544       check_and_sed    => [ "mv" ],
545       get_ldap_realm   => [ "get_ldap_suffix" ],
546     );
547     foreach my $f (keys(%keep)) {
548       if (exists($deps{$f})) {
549         $keep{$_} = 1 for (@{$deps{$f}});
550       }
551     }
552     while (<STDIN>) {
553       if (/^_?cp_(\w+) *\(\) *\{/) {
554         if (! exists($keep{$1})) {
555           while (<STDIN>) { last if /^\}/; } # skip it
556           next;
557         } else {
558           $output .= "\n";
559         }
560       }
561       next if /^\s*(\#|$)/;
562       $output .= $_;
563     }
564     $output =~ s/\b(_?)cp_/$1${prefix}_/sg;
565     $prefix = uc($prefix);
566     $output =~ s/\b(_?)CP_/$1${prefix}_/sg;
567     print $output;
568   ' -- $*
569 }