]> TLD Linux GIT Repositories - rc-scripts.git/blob - lib/functions
04e7f29332e7ee316b75de17381e6c655fb4fea5
[rc-scripts.git] / lib / functions
1 #!/bin/sh - keep it for file(1) to get bourne shell script result
2 # functions     This file contains functions to be used by most or all
3 #               shell scripts in the /etc/rc.d/init.d directory.
4 #
5 #
6 # Author:       Miquel van Smoorenburg, <miquels@drinkel.nl.mugnet.org>
7 # Hacked by:    Greg Galloway and Marc Ewing
8 # Modified for TLD Linux by:
9 #               Marek Obuchowicz <elephant@pld-linux.org>
10 #               Arkadiusz Miśkiewicz <misiek@pld-linux.org>
11 #               Michał Kochanowicz <mkochano@pld-linux.org>
12 #               Łukasz Pawelczyk <havner@pld-linux.org>
13
14 # First set up a default search path.
15 export PATH="/sbin:/usr/sbin:/bin:/usr/bin"
16
17 # Set defaults
18 if [ -z "$COLUMNS" -o -z "$LINES" ]; then
19         _setterm() {
20                 set -- $(stty size 2>/dev/null)
21                 LINES=${LINES:-$1}
22                 COLUMNS=${COLUMNS:-$2}
23         }
24         _setterm
25         unset _setterm
26 fi
27 [ -z "$LINES" ] || [ "$LINES" -le 0 ] && LINES=40
28 [ -z "$COLUMNS" ] || [ "$COLUMNS" -le 0 ] && COLUMNS=80
29 export LINES COLUMNS
30 INIT_COL=$((COLUMNS - 13))
31
32 # Set colors
33 RED=1
34 GREEN=2
35 YELLOW=3
36 BLUE=4
37 MAGENTA=5
38 CYAN=6
39 WHITE=7
40 NORMAL=15
41 # Bold definition (second parameter to termput setaf)
42 BOLD=1
43 NOBOLD=0
44 # Default colors
45 CBRACKETS="$CYAN"       # brackets [ ] color
46 CDONE="$GREEN"          # DONE and WORK color
47 CBUSY="$MAGENTA"        # BUSY color
48 CFAIL="$RED"            # FAIL and DIED color
49 CPOWEREDBY="$CYAN"      # "Powered by" color
50 CTLD="$GREEN"           # "TLD Linux" color
51 CI="$RED"               # Capital I color (press I to enter interactive startup)
52 CRESMAN="$GREEN"        # "Resource Manager" color
53 CHARS=""                # Characters displayed on the beginning of show line
54 CCHARS="$NORMAL"        # Color of these characters (look at /etc/sysconfig/init-colors.gentoo example)
55
56 # Source configuration if available - may override default values
57 [ -r /etc/sysconfig/init-colors ] && . /etc/sysconfig/init-colors
58 [ -r /etc/sysconfig/system ] && . /etc/sysconfig/system
59 [ -r /etc/sysconfig/bootsplash ] && . /etc/sysconfig/bootsplash
60
61 if [ -z "$VSERVER" -o "$VSERVER" = "detect" ]; then
62         {
63                 while read _f _ctx; do
64                         [ "$_f" = "VxID:" -o "$_f" = "s_context:" ] && break
65                 done </proc/self/status
66         } 2>/dev/null
67         if [ -z "$_ctx" -o "$_ctx" = "0" ]; then
68                 VSERVER=no
69         else
70                 VSERVER=yes
71         fi
72         unset _f _ctx
73 fi
74
75 # VSERVER_ISOLATION_NET = isolation only inside of vserver guests
76 if [ -z "$VSERVER_ISOLATION_NET" -o "$VSERVER_ISOLATION_NET" = "detect" ]; then
77         VSERVER_ISOLATION_NET=no
78         if [ "$VSERVER" = "yes" ]; then
79                 if [ -f /proc/self/nsproxy ]; then
80                         # older kernels
81                         {
82                                 while read _t _data; do
83                                         [ "$_t" = "net:" ] && break
84                                 done < /proc/self/nsproxy
85                         } 2> /dev/null
86                         if [ "${_data##*\(}" = "I)" ]; then
87                                 VSERVER_ISOLATION_NET=yes
88                         fi
89                 elif [ -f /proc/self/ninfo ]; then
90                         # newer kernels
91                         {
92                                 while read _t _data; do
93                                         [ "$_t" = "NCaps:" ] && break
94                                 done < /proc/self/ninfo
95                         } 2> /dev/null
96                         if [ "${_t}" = "NCaps:" ]; then
97                                 VSERVER_ISOLATION_NET=yes
98                         fi
99                 else
100                         # assume (very?) old kernel mode
101                         VSERVER_ISOLATION_NET=yes
102                 fi
103                 unset _f _data
104         fi
105 fi
106
107 # we need to know in functions if we were called from a terminal
108 if [ -z "$ISATTY" ]; then
109         [ -t ] && ISATTY=yes || ISATTY=no
110         export ISATTY
111 fi
112
113 is_yes() {
114         # Test syntax
115         if [ $# = 0 ]; then
116                 msg_usage " is_yes {value}"
117                 return 2
118         fi
119
120         # Check value
121         case "$1" in
122         yes|Yes|YES|true|True|TRUE|on|On|ON|Y|y|1)
123                 # true returns zero
124                 return 0
125                 ;;
126         *)
127                 # false returns one
128                 return 1
129                 ;;
130         esac
131 }
132
133 is_no() {
134         # Test syntax
135         if [ $# = 0 ]; then
136                 msg_usage " is_no {value}"
137                 return 2
138         fi
139
140         case "$1" in
141         no|No|NO|false|False|FALSE|off|Off|OFF|N|n|0)
142                 # true returns zero
143                 return 0
144                 ;;
145         *)
146                 # false returns one
147                 return 1
148                 ;;
149         esac
150 }
151
152 # checks if file is empty
153 # empty lines and lines beginning with hash are ignored
154 is_empty_file() {
155         [ -s "$1" ] || return 0
156         grep -vqE "^(#|[[:blank:]]*$)" "$1" && return 1 || return 0
157 }
158
159 # returns OK if $1 contains $2
160 strstr() {
161         [ "${1#*$2*}" = "$1" ] && return 1
162         return 0
163 }
164
165 # Apply sysctl settings, including files in /etc/sysctl.d
166 apply_sysctl() {
167         if [ -x /lib/systemd/systemd-sysctl ]; then
168                 /lib/systemd/systemd-sysctl
169                 return
170         fi
171
172         local file
173         for file in /usr/lib/sysctl.d/*.conf; do
174                 [ -f /run/sysctl.d/${file##*/} ] && continue
175                 [ -f /etc/sysctl.d/${file##*/} ] && continue
176                 test -f "$file" && sysctl -q -e -p "$file"
177         done
178         for file in /run/sysctl.d/*.conf; do
179                 [ -f /etc/sysctl.d/${file##*/} ] && continue
180                 test -f "$file" && sysctl -q -e -p "$file"
181         done
182         for file in /etc/sysctl.d/*.conf; do
183                 test -f "$file" && sysctl -q -e -p "$file"
184         done
185         sysctl -q -e -p /etc/sysctl.conf
186 }
187
188 if is_yes "$FASTRC" || is_yes "$IN_SHUTDOWN"; then
189         RC_LOGGING=no
190 fi
191
192 if is_no "$RC_LOGGING"; then
193         initlog() {
194                 RESULT=0
195                 while [ "$1" != "${1##-}" ]; do
196                         case $1 in
197                         -c)
198                                 shift
199                                 $1
200                                 RESULT=$?
201                                 break
202                                 ;;
203                         *)
204                                 shift
205                                 ;;
206                         esac
207                 done
208                 return $RESULT
209         }
210 fi
211
212 kernelver() {
213         local _x _y _z v v1 old_IFS ver
214         {
215                 read _x _y v _z
216                 old_IFS=$IFS
217                 # strip _* or -* from versions like: "2.6.25_vanilla-1", "2.6.25-1"
218                 IFS='_-'
219                 set -- $v
220                 v1=${1}
221                 IFS='.'
222                 set -- $v1
223                 IFS=$old_IFS
224
225                 ver=${3}
226                 while [ ${#ver} -lt 3 ]; do ver="0$ver"; done
227                 ver="$2$ver"
228                 while [ ${#ver} -lt 6 ]; do ver="0$ver"; done
229                 ver="$1$ver"
230                 while [ ${#ver} -lt 9 ]; do ver="0$ver"; done
231                 echo $ver
232         } < /proc/version
233 }
234
235 kernelverser() {
236         local _x _y _z v v1 old_IFS ver
237         {
238                 read _x _y v _z
239                 old_IFS=$IFS
240                 # strip _* or -* from versions like: "2.6.25_vanilla-1", "2.6.25-1"
241                 IFS='_-'
242                 set -- $v
243                 v1=${1}
244                 IFS='.'
245                 set -- $v1
246                 IFS=$old_IFS
247                 ver=$2
248                 while [ ${#ver} -lt 3 ]; do ver="0$ver"; done
249                 ver="$1$ver"
250                 while [ ${#ver} -lt 6 ]; do ver="0$ver"; done
251                 echo $ver
252         } </proc/version
253 }
254
255 kernelvermser() {
256         local _x _y _z v v1 old_IFS ver
257         {
258                 read _x _y v _z
259                 old_IFS=$IFS
260                 # strip _* or -* from versions like: "2.6.25_vanilla-1", "2.6.25-1"
261                 IFS='_-'
262                 set -- $v
263                 v1=${1}
264                 IFS='.'
265                 set -- $v1
266                 IFS=$old_IFS
267                 ver="$1"
268                 while [ ${#ver} -lt 3 ]; do ver="0$ver"; done
269                 echo $ver
270         } </proc/version
271 }
272
273 # Colors workaround
274 termput() {
275         is_yes "$ISATTY" || return
276
277         if is_yes "$FASTRC" || is_no "$TPUT"; then
278                 case "$1" in
279                 hpa)
280                         echo -ne "\033[$(($2+1))G"
281                         ;;
282                 cuu*)
283                         echo -ne "\033[${2}A"
284                         ;;
285                 el)
286                         echo -ne "\033[0K"
287                         ;;
288                 setaf)
289                         local ISBOLD
290                         if [ -n "$3" ]; then
291                                 ISBOLD="$3"
292                         else
293                                 ISBOLD="$NOBOLD";
294                         fi
295                         is_yes "$COLOR_INIT" && echo -ne "\033[${ISBOLD};3${2}m"
296                         ;;
297                 op)
298                         termput setaf $NORMAL
299                         ;;
300                 esac
301         else
302                 case "$1" in
303                 hpa | cuu* | el)
304                         tput "$@"
305                         ;;
306                 setaf)
307                         if [ "$3" = "1" ]; then tput bold; else tput sgr0; fi
308                         is_yes "$COLOR_INIT" && tput setaf "$2"
309                         ;;
310                 op)
311                         termput setaf $NORMAL
312                         ;;
313                 esac
314         fi
315 }
316
317 if [ ! -x /bin/printf ]; then
318         # printf equivalent
319         # FIXME: buggy when single or double quotes in message!
320         printf() {
321                 local text m
322                 text="$1"
323                 shift
324                 if [ $# -gt 0 ]; then
325                         m="$1"
326                         shift
327                         while [ $# -gt 0 ]; do
328                                 m="$m\",\"$1"
329                                 shift
330                         done
331                 fi
332                 awk "BEGIN {printf \"$text\", \"$m\"; }"
333         }
334 fi
335
336 # National language support function
337 nls() {
338         local msg_echo nls_domain text message
339         msg_echo='\n'
340         nls_domain="$NLS_DOMAIN"
341         while [ "$1" != "${1##-}" ]; do
342                 case "$1" in
343                 --nls-domain)
344                         shift
345                         nls_domain="$1"
346                         shift
347                         ;;
348                 -n)
349                         msg_echo=''
350                         shift
351                         ;;
352                 esac
353         done
354         message="$1"
355         shift
356
357         # empty message, so we return --misiek
358         if [ -z "$message" ]; then
359                 echo -en "$msg_echo"
360                 return
361         fi
362
363         if is_yes "$GETTEXT"; then
364                 message=$(TEXTDOMAINDIR="/etc/sysconfig/locale" gettext -e --domain="${nls_domain:-rc-scripts}" "$message")
365         fi
366
367         printf "$message" "$@"
368         echo -en "$msg_echo"
369 }
370
371 rc_splash() {
372         local action="$1"
373
374         if ! is_no "$BOOT_SPLASH" && ! is_yes "$VSERVER"; then
375                 [ -x /bin/splash ] && /bin/splash "$action"
376         fi
377
378         : $((progress++))
379 }
380
381 msg_network_down() {
382         nls "ERROR: Networking is down. %s can't be run." "$1" >&2
383 }
384
385 msg_starting() {
386         show "Starting %s service" "$1"
387 }
388
389 msg_already_running() {
390         nls "%s service is already running." "$1"
391 }
392
393 msg_stopping() {
394         show "Stopping %s service" "$1"
395 }
396
397 msg_not_running() {
398         nls "%s service is not running." "$1"
399 }
400
401 msg_reloading() {
402         show "Reloading %s service" "$1"
403 }
404
405 msg_usage() {
406         nls "Usage: %s" "$*"
407 }
408
409 # Some functions to handle TLD Linux-style messages
410 show() {
411         local text len time
412
413         if is_yes "$RC_UPTIME"; then
414                 time=$(awk '{printf("[%8.2f] ", $1)}' /proc/uptime)
415         fi
416
417         if is_no "$FASTRC" && is_yes "$GETTEXT"; then
418                 text=$time$(nls -n "$@")
419         else
420                 text=$time$(printf "$@")
421         fi
422         len=${#text}
423         while [ $((len++)) -lt $INIT_COL ]; do
424                 text="$text."
425         done
426         if [ -n "$CHARS" ]; then
427                 termput setaf $CCHARS
428                 echo -n "$CHARS"
429                 termput op
430         fi
431         echo -n "$text"
432 }
433
434 deltext() {
435         termput hpa $INIT_COL
436 }
437
438 # Displays message in square brackests ("[ DONE ]"). Takes two arguments.
439 # First is the text to display, second is color number to use (argument to
440 # tput setaf). If second argument is not given, default (2, green) will be
441 # used).
442 progress() {
443         local COLOR
444         if [ -n "$2" ]; then
445                 COLOR="$2"
446         else
447                 COLOR="$CDONE"
448         fi
449         deltext
450         echo -n "$(termput setaf $CBRACKETS)[$(termput setaf $COLOR) $(nls --nls-domain rc-scripts "$1") $(termput setaf $CBRACKETS)]$(termput op)"
451 }
452
453 busy() {
454         echo -n "$_busy"
455 }
456
457 ok() {
458         echo "$_ok"
459 }
460
461 started() {
462         echo "$_started"
463 }
464
465 fail() {
466         echo "$_fail"
467         return 1
468 }
469
470 died() {
471         echo "$_died"
472         return 1
473 }
474
475 # Check if $pid (could be plural) are running
476 checkpid() {
477         while [ "$1" ]; do
478                 [ -d "/proc/$1" ] && return 0
479                 shift
480         done
481         return 1
482 }
483
484 # - outside chroot get only those processes, which are outside chroot.
485 # - inside chroot get only those processes, which are inside chroot.
486 # - don't filter out pids which do not have corresponding running processes (process died etc)
487 # (note: some processes like named are chrooted but run outside chroot)
488 # - do nothing inside vserver
489 filter_chroot() {
490         # no pids, exit early
491         [ $# -eq 0 ] && return
492
493         # filter by pid namespace if such dir exists for current process
494         # we do filter in containers as stacked containers are possible with LXC
495         if [ -d /proc/$$/ns ]; then
496                 local pids
497                 pids=$(filter_ns "$@") && set -- "$pids"
498         fi
499
500         if is_yes "$VSERVER"; then
501                 echo $@
502                 return
503         fi
504
505         if [ $# -lt 1 -o ! -d /proc/1 ]; then
506                 echo $@
507                 return
508         fi
509
510         local root_dir good_pids="" good_add_pid
511         for root_pid in $@; do
512                 root_dir=$(resolvesymlink /proc/${root_pid}/root)
513                 if [ -n "$root_dir" ]; then
514                         good_add_pid=1
515                         if [ -n "${SYSTEM_CHROOTS}" ]; then
516                                 for r_dir in ${SYSTEM_CHROOTS}; do
517                                         echo "$root_dir" | grep -q "^${r_dir}" && good_add_pid=0
518                                 done
519                         fi
520                         [ "$good_add_pid" -eq 1 ] && good_pids="$good_pids $root_pid"
521                 elif [ ! -d "/proc/$root_pid" ]; then
522                         good_pids="$good_pids $root_pid"
523                 fi
524         done
525         echo $good_pids
526 }
527
528 # similar to filter_chroot, but filter based on /proc/PID/ns/pid value
529 filter_ns() {
530         local cur_ns=$(resolvesymlink /proc/$$/ns/pid)
531         [ "$cur_ns" ] || return 1
532
533         local pid ns pids=""
534         # add pids if it matches current pid namespace
535         # we should add pids what do not exist (dead processes),
536         # but not add pids whose namespace does not match
537         # (processes belonging to different NS do exist in /proc)
538         for pid in "$@"; do
539                 if [ ! -d /proc/$pid ]; then
540                         pids="$pids $pid"
541                         continue
542                 fi
543                 ns=$(resolvesymlink /proc/$pid/ns/pid)
544                 if [ "$ns" = "$cur_ns" ]; then
545                         pids="$pids $pid"
546                 fi
547         done
548         echo $pids
549         return 0
550 }
551
552 # Usage:
553 # run_cmd Message command_to_run
554 # run_cmd -a Message command_to_run
555 # run_cmd --user "username" "Message" command_to_run
556 run_cmd() {
557         local force_err=0 exit_code=0 errors user
558         while [ $# -gt 0 ]; do
559                 case "$1" in
560                 -a)
561                         force_err=1
562                         ;;
563                 --user)
564                         shift
565                         user=$1
566                         ;;
567                 *)
568                         break
569                 esac
570                 shift
571         done
572
573         local message=$1; shift
574         show "$message"; busy
575
576         if errors=$(
577                 cd /
578                 export HOME=/tmp TMPDIR=/tmp
579                 if is_no "$RC_LOGGING"; then
580                         ${user:+setuidgid -s $user} "$@" 2>&1
581                 else
582                         ${user:+setuidgid -s $user} initlog -c "$*" 2>&1
583                 fi
584                 ); then
585                 ok
586                 log_success "$1 $message"
587         else
588                 fail
589                 log_failed "$1 $message"
590                 exit_code=1
591         fi
592         [ -n "$errors" ] && [ $exit_code -eq 1 -o $force_err -eq 1 ] && echo "$errors"
593         return $exit_code
594 }
595
596 _daemon_set_ulimits() {
597         local opt val ksh=${KSH_VERSION:+1}
598         set -- ${SERVICE_LIMITS:-$DEFAULT_SERVICE_LIMITS}
599         while [ $# -gt 0 ]; do
600                 opt=$1
601                 val=$2
602                 if [ "$ksh" ]; then
603                         case "$opt" in
604                         -Hu)
605                                 opt=-Hp
606                         ;;
607                         -Su)
608                                 opt=-Sp
609                         ;;
610                         -u)
611                                 opt=-p
612                         ;;
613                         esac
614                 fi
615                 ulimit $opt $val
616                 shift 2
617         done
618 }
619
620 # A function to start a program (now it's useful on read-only filesystem too)
621 daemon() {
622         local errors="" prog="" end="" waitname="" waittime=""
623         local exit_code=0
624         local nice=$SERVICE_RUN_NICE_LEVEL
625         local fork user closefds redirfds pidfile makepid chdir=/
626
627         # NOTE: if you wonder how the shellish (by syntax) $prog works in ssd mode,
628         # then the answer is: it totally ignores $prog and uses "$@" itself.
629
630         while [ $# -gt 0 ]; do
631                 case $1 in
632                 '')
633                 msg_usage " daemon [--check] [--user user] [--fork] [--chdir directory] [--closefds] [--redirfds] [--waitforname procname] [--waitfortime seconds] [--pidfile file] [--makepid] [+/-nicelevel] {program} <program args>"
634                         return 2
635                         ;;
636                 --check)
637                         # for compatibility with redhat/mandrake
638                         nls "warning: --check option is ignored!"
639                         shift
640                         ;;
641                 --user)
642                         shift
643                         user=$1
644                         ;;
645                 --fork)
646                         fork=1
647                         end='&'
648                         ;;
649                 --chdir)
650                         shift
651                         chdir=$1
652                         ;;
653                 --closefds)
654                         closefds=1
655                         ;;
656                 --redirfds)
657                         redirfds=1
658                         ;;
659                 --waitforname)
660                         shift
661                         waitname="$1"
662                         ;;
663                 --waitfortime)
664                         shift
665                         waittime="$1"
666                         ;;
667                 --pidfile=?*)
668                         pidfile="${1#--pidfile=}"
669                         case "$pidfile" in /*);; *) pidfile="/var/run/$pidfile";; esac
670                         ;;
671                 --pidfile)
672                         shift
673                         pidfile="$1"
674                         case "$pidfile" in /*);; *) pidfile="/var/run/$pidfile";; esac
675                         ;;
676                 --makepid)
677                         makepid=1
678                         ;;
679                 -*|+*)
680                         nice=$1
681                         shift
682                         break
683                         ;;
684                 *)
685                         break
686                         ;;
687                 esac
688                 shift
689         done
690         if [ -n "$user" -a "$user" != "root" ]; then
691                 prog="/bin/su $user -s /bin/sh -c \""
692         fi
693         if [ "$fork" = "1" ]; then
694                 prog="/usr/bin/setsid ${prog:-sh -c \"}"
695         fi
696         # If command to execute ends with quotation mark, add remaining
697         # arguments and close quotation.
698         if [ "$prog" != "${prog%\"}" ]; then
699                 prog="$prog $*$end\""
700         else
701                 prog="$prog $*$end"
702         fi
703
704         _daemon_set_ulimits
705
706         [ -z "$DEFAULT_SERVICE_UMASK" ] && DEFAULT_SERVICE_UMASK=022
707         [ -z "$DEFAULT_SERVICE_RUN_NICE_LEVEL" ] && DEFAULT_SERVICE_RUN_NICE_LEVEL=0
708
709         # And start it up.
710         busy
711         cd $chdir
712         [ -n "$SERVICE_CPUSET" ] && is_yes "$CPUSETS" && echo $$ > "/dev/cpuset/${SERVICE_CPUSET}/tasks"
713         if errors=$(
714                 umask ${SERVICE_UMASK:-$DEFAULT_SERVICE_UMASK};
715                 export USER=root HOME=/tmp TMPDIR=/tmp
716
717                 nice=${nice:-$DEFAULT_SERVICE_RUN_NICE_LEVEL}
718                 nice=${nice:-0}
719
720                 # make nice level absolute, not to be dependant of nice level of shell where service started
721                 nice=$(($nice - $(nice)))
722
723                 if [ "$closefds" = 1 ]; then
724                         exec 1>&-
725                         exec 2>&-
726                         exec 0<&-
727                 elif [ "$redirfds" = 1 ]; then
728                         exec 1>/dev/null
729                         exec 2>/dev/null
730                         exec 0</dev/null
731                 else
732                         exec 2>&1
733                         exec 0</dev/null
734                 fi
735
736                 if is_no "$RC_LOGGING"; then
737                         prog=$1; shift
738                         if [ ! -x $prog ]; then
739                                 logger -t rc-scripts -p daemon.debug "daemon: Searching PATH for $prog, consider using full path in initscript"
740                                 local a o=$IFS
741                                 IFS=:
742                                 for a in $PATH; do
743                                         if [ -x $a/$prog ]; then
744                                                 prog=$a/$prog
745                                                 break
746                                         fi
747                                 done
748                                 IFS=$o
749                         fi
750                         set -- "$prog" "$@"
751
752                         # use setsid to detach from terminal,
753                         # needs pidfile or ssd would check setsid program instead of real program
754                         if [ "$pidfile" ]; then
755                                 set -- /usr/bin/setsid "$@"
756                         fi
757
758                         prog=$1; shift
759                         /sbin/start-stop-daemon -q --start \
760                                 --nicelevel $nice \
761                                 ${pidfile:+--pidfile $pidfile} \
762                                 ${makepid:+--make-pidfile} \
763                                 ${user:+--chuid $user} \
764                                 ${chdir:+--chdir "$chdir"} \
765                                 ${fork:+--background} \
766                                 ${SERVICE_DROPCAPS:+--dropcap $SERVICE_DROPCAPS} \
767                                 --exec "$prog" \
768                                 -- "$@"
769                 else
770                         nice -n $nice initlog -c "$prog" 2>&1 </dev/null
771                 fi
772                 ); then
773
774                 # wait for process (or pidfile) to be created
775                 if [ "$waittime" -gt 0 ]; then
776                         # waitname can be empty, as if pidfile is in use, it is not relevant
777                         waitproc "$waittime" "$waitname" "$pidfile"
778                 fi
779                 log_success "$1 startup"
780                 ok
781         else
782                 exit_code=1
783                 fail
784                 log_failed "$1 startup"
785                 [ -n "$errors" ] && echo >&2 "$errors"
786         fi
787         return $exit_code
788 }
789
790 # wait (in seconds) for process (or pidfile) to be created
791 # example: waitproc 30 httpd /var/run/httpd.pid
792 waitproc() {
793         local waittime=$1 procname=$2 pidfile=$3
794         local pid
795         local now=$(date +%s)
796         local maxtime=$(($now + $waittime))
797
798         if [ -z "$procname" -a -z "$pidfile" ]; then
799                 msg_usage "waitproc: procname or pidfile must be specified"
800                 return 2
801         fi
802
803         while [ "$(date +%s)" -lt "$maxtime" ]; do
804                 pid=$(pidofproc "$procname" "$pidfile")
805                 [ -n "$pid" ] && break
806
807                 # start-stop-daemon uses same delay
808                 usleep 20000
809         done
810 }
811
812 # A function to stop a program.
813 killproc() {
814         local notset killlevel base pid pidfile result delay=3 try
815         # Test syntax.
816         if [ $# = 0 ]; then
817                 msg_usage " killproc [--pidfile|-p PIDFILE] [-d DELAY] {program} [-SIGNAME]"
818                 return 2
819         fi
820
821         while [ "$1" != "${1##-}" ]; do
822                 case $1 in
823                 -d)
824                         delay="$2"
825                         shift 2
826                         ;;
827                 --pidfile|-p)
828                         pidfile="$2"
829                         case "$pidfile" in /*);; *) pidfile="/var/run/$pidfile";; esac
830                         shift 2
831                         ;;
832                 --waitforname)
833                         waitname="$2"
834                         shift 2
835                         ;;
836                 --waitfortime)
837                         waittime="$2"
838                         shift 2
839                         ;;
840                 esac
841         done
842
843         busy
844
845         local notset=0
846         # check for second arg to be kill level
847         if [ -n "$2" ]; then
848                 killlevel=$2
849         else
850                 notset=1
851         fi
852
853         # experimental start-stop-daemon based killing.
854         # works only with pidfile
855         if is_no "$RC_LOGGING" && [ "$pidfile" ]; then
856                 local sig=${killlevel:--TERM} retry
857                 # do not retry if signal is specified,
858                 # as otherwise impossible to send HUP if process pid stays in pidfile.
859                 # however, do retry if --waitfortime was specified
860                 if [ "${killlevel+set}" = "set" ] && [ -z "$waittime" ]; then
861                         # if we send HUP it's ok if process does not die
862                         retry="--oknodo"
863                 else
864                         local waitretry
865                         : ${waittime=10}
866                         : ${waitretry=$(($waittime * 2))}
867
868                         # 1. kill with $sig, wait $delay
869                         # 2. kill with $sig, wait $waittime
870                         # 3. kill with KILL, wait $waitretry
871                         retry="--retry ${sig#-}/${delay}/${sig#-}/${waittime}/KILL/${waitretry}"
872                 fi
873                 /sbin/start-stop-daemon -q --stop \
874                         $retry \
875                         ${waitname:+--name $waitname} \
876                         -s ${sig#-} \
877                         ${pidfile:+--pidfile $pidfile}
878                 result=$?
879                 if [ "$result" -eq 0 ]; then
880                         ok
881                 else
882                         fail
883                 fi
884                 return $result
885         fi
886
887
888         # Save basename.
889         base=${1##*/}
890
891         # Find pid.
892         pid=$(pidofproc "$1" "$pidfile")
893         [ -z "$pid" ] && pid=$(pidofproc "$base" "$pidfile")
894
895         # Kill it.
896         if [ -n "$pid" -a "$pid" != "$$" ] && checkpid $pid 2>&1; then
897                 if [ "$notset" = "1" ]; then
898                         if checkpid $pid 2>&1; then
899                                 # TERM first, then KILL if not dead
900                                 kill -TERM $pid
901                                 usleep 50000
902
903                                 try=0
904                                 while [ $try -lt $delay ]; do
905                                         checkpid $pid || break
906                                         sleep 1
907                                         try=$((try+1))
908                                 done
909                                 if checkpid $pid; then
910                                         # XXX: SIGKILL is sent already on 4th second!
911                                         # HARMFUL for example to mysqld (which is already workarounded)
912                                         kill -KILL $pid
913                                         usleep 50000
914                                 fi
915                         fi
916                         checkpid $pid
917                         result=$?
918                         if [ "$result" -eq 0 ]; then
919                                 fail
920                                 log_failed "$1 shutdown"
921                         else
922                                 ok
923                                 log_success "$1 shutdown"
924                         fi
925                         result=$(( ! $result ))
926                 else
927                         # use specified level only
928                         if checkpid $pid > /dev/null 2>&1; then
929                                 kill $killlevel $pid
930                                 result=$?
931                                 if [ "$result" -eq 0 ]; then
932                                         ok
933                                         log_success "$1 got $killlevel"
934                                 else
935                                         result=7
936                                         fail
937                                         log_failed "$1 didn't get $killlevel"
938                                 fi
939                         else
940                                 result=7
941                                 died
942                                 log_failed "$1 shutdown"
943                         fi
944                 fi
945         else
946                 died
947                 log_failed "$1 shutdown"
948                 result=7
949         fi
950
951         if [ -n "$waitname" -a -n "$waittime" ]; then
952                 # Save basename.
953                 base=${waitname##*/}
954                 # Find pid.
955                 pid=$(pidofproc "$waitname" "$pidfile")
956                 [ -z "$pid" ] && pid=$(pidofproc "$base" "$pidfile")
957                 i=0
958                 while [ "$i" -lt "$waittime" ]; do
959                         i=$(( i + 1 ))
960                         checkpid $pid && sleep 1 || break
961                 done
962         fi
963
964         # Remove pid file if any.
965         if [ "$notset" = "1" ]; then
966                 rm -f /var/run/${base}.pid
967         fi
968
969         return $result
970 }
971
972 # A function to find the pid of a program.
973 pidofproc() {
974         local pid pidfile base=${1##*/}
975         pidfile="$base.pid"
976         [ -n "$2" ] && pidfile="$2"
977
978         # Test syntax.
979         if [ $# = 0 ]; then
980                 msg_usage " pidofproc {program}"
981                 return 2
982         fi
983
984         # First try pidfile or "/var/run/*.pid"
985         case "$pidfile" in
986                 /*)pidfile="${pidfile}";;
987                 *) pidfile="/var/run/$pidfile";;
988         esac
989         if [ -f "${pidfile}" ]; then
990                 local p
991                 for p in $(< "${pidfile}"); do
992                         [ -z "$(echo "$p" | awk '{gsub(/[0-9]/,"");print;}')" ] && pid="$pid $p"
993                 done
994         fi
995
996         # Next try "pidof" if pidfile is not specified
997         if [ -z "$pid" ] && [ -z "$pidfile" ]; then
998                 pid=$(pidof -o $$ -o $PPID -o %PPID -x "$1")
999         fi
1000
1001         pid=$(filter_chroot $pid)
1002         echo $pid
1003 }
1004
1005 # status [--pidfile PIDFILE] {subsys} [{daemon}]"
1006 status() {
1007         local pid subsys daemon cpuset_msg pidfile
1008         if [ "$1" = "--pidfile" -o "$1" = "-p" ]; then
1009                 pidfile=$2
1010                 case "$pidfile" in /*);; *) pidfile="/var/run/$pidfile";; esac
1011                 shift 2
1012         fi
1013
1014         subsys=$1
1015         daemon=${2:-$subsys}
1016
1017         # Test syntax.
1018         if [ $# = 0 ]; then
1019                 msg_usage " status [--pidfile PIDFILE] {subsys} [{daemon}]"
1020                 return 2
1021         fi
1022
1023         # if pidfile specified, pid must be there
1024         if [ "$pidfile" ]; then
1025                 [ -f "$pidfile" ] && read pid < $pidfile
1026                 # filter_chroot does not filter out dead pids, so this extra check, see t/status-pidfile.sh
1027                 if [ ! -d "/proc/$pid" ]; then
1028                         pid=
1029                 fi
1030         else
1031                 pid=$(pidof -o $$ -o $PPID -o %PPID -x $daemon)
1032         fi
1033         pid=$(filter_chroot $pid)
1034
1035         if [ "$pid" ]; then
1036                 cpuset_msg="..."
1037                 if [ -n "$SERVICE_CPUSET" ] && is_yes "$CPUSETS"; then
1038                         if grep -q "$pid" "/dev/cpuset/${SERVICE_CPUSET}/tasks"; then
1039                                 cpuset_msg=$(nls " in cpuset %s..." "$SERVICE_CPUSET")
1040                         else
1041                                 cpuset_msg=$(nls " outside of configured cpuset %s..." "$SERVICE_CPUSET")
1042                         fi
1043                 fi
1044                 nls "%s (pid %s) is running%s" "$daemon" "$pid" "$cpuset_msg"
1045                 return 0
1046         fi
1047
1048         # Next try "/var/run/*.pid" files; if pidfile is not set
1049         local base=${daemon##*/}
1050         if [ -z "$pidfile" -a -f /var/run/${base}.pid ]; then
1051                 read pid < /var/run/${base}.pid
1052                 pid=$(filter_chroot $pid)
1053                 if [ "$pid" ]; then
1054                         nls "%s dead but pid file (%s) exists" "$subsys" /var/run/${base}.pid
1055                         return 1
1056                 fi
1057         fi
1058
1059         # See if /var/lock/subsys/$subsys exists
1060         if [ -f /var/lock/subsys/$subsys ]; then
1061                 nls "daemon %s dead but subsys (%s) locked" "$daemon" "$subsys"
1062                 return 2
1063         fi
1064         nls "%s is stopped" "$subsys"
1065         return 3
1066 }
1067
1068 # Confirm whether we really want to run this service
1069 confirm() {
1070         local answer
1071         nls -n "Start service %s (Y)es/(N)o/(C)ontinue? [Y] " "$1"
1072         read answer
1073         case $answer in
1074         y|Y|t|T|j|J|"")
1075                 return 0
1076                 ;;
1077         c|C|k|K|w|W)
1078                 return 2
1079                 ;;
1080         n|N)
1081                 return 1
1082                 ;;
1083         *)
1084                 confirm $1
1085                 return $?
1086                 ;;
1087         esac
1088 }
1089
1090 # module is needed (ie. is requested, is available and isn't loaded already)
1091 is_module() {
1092         # module name without .o at end
1093         if ! lsmod | grep -q "$1"; then
1094                 if ls -1R /lib/modules/$(uname -r)/ 2> /dev/null | grep -q "^${1}.\(\|k\)o\(\|.gz\)"; then
1095                         # true
1096                         return 0
1097                 fi
1098         fi
1099         # false
1100         return 1
1101 }
1102
1103 _modprobe() {
1104         local parsed single die args foo result
1105         parsed=no
1106         while is_no "$parsed"; do
1107                 case "$1" in
1108                 "single")
1109                         single=yes
1110                         shift
1111                         ;;
1112                 "die")
1113                         die=yes
1114                         shift
1115                         ;;
1116                 -*)
1117                         args="$args $1"
1118                         shift
1119                         ;;
1120                 *)
1121                         parsed=yes
1122                         ;;
1123                 esac
1124         done
1125         if is_yes "${single}"; then
1126                 foo="$@"
1127                 show "Loading %s kernel module(s)" "$foo"
1128                 busy
1129         fi
1130         if [ -x /sbin/modprobe ]; then
1131                 /sbin/modprobe -s $args "$@"
1132                 result=$?
1133         else
1134                 deltext; fail
1135                 result=1
1136         fi
1137         if is_yes "${single}"; then
1138                 deltext
1139                 if [ $result = "0" ]; then
1140                         is_yes "$single" && ok
1141                 else
1142                         fail
1143                         if is_yes "$die"; then
1144                                 nls "Could not load %s kernel module(s)" "$@"
1145                                 exit 1
1146                         fi
1147                 fi
1148         fi
1149 }
1150
1151 if is_no "$RC_LOGGING"; then
1152         log_success() {
1153                 :
1154         }
1155
1156         log_failed() {
1157                 :
1158         }
1159 else
1160         log_success() {
1161                 initlog -n $0 -s "$1 $2" -e 1
1162         }
1163
1164         log_failed() {
1165                 initlog -n $0 -s "$1 $2" -e 2
1166         }
1167 fi
1168
1169 # Check if any flavor of portmapper is running
1170 check_portmapper() {
1171         if [ -x /usr/sbin/rpcinfo ]; then
1172                 if /usr/sbin/rpcinfo -p localhost >/dev/null 2>/dev/null; then
1173                         return 0
1174                 else
1175                         return 1
1176                 fi
1177         elif [ -z "$(pidof portmap)" -a -z "$(pidof rpcbind)" ]; then
1178                 return 1
1179         fi
1180         return 0
1181 }
1182
1183 # is_fsmounted fstype mntpoint
1184 # Check if filesystem fstype is mounted on mntpoint
1185 is_fsmounted() {
1186         local fstype=$1
1187         local mntpoint=$2
1188
1189         [ -n "$fstype" -a -n "$mntpoint" ] || return 1
1190
1191         if [ -r /proc/mounts ]; then
1192                 grep -qE "[[:blank:]]$mntpoint[[:blank:]]+$fstype[[:blank:]]" /proc/mounts
1193                 return $?
1194         else
1195                 if [ "$(stat -L -f -c %T $mntpoint 2>/dev/null)" = "$fstype" ]; then
1196                         return 0
1197                 else
1198                         return 1
1199                 fi
1200         fi
1201 }
1202
1203 # __umount_loop awk_program fstab_file first_msg retry_msg umount_args
1204 # awk_program should process fstab_file and return a list of fstab-encoded
1205 # paths; it doesn't have to handle comments in fstab_file.
1206 __umount_loop() {
1207         local remaining sig=
1208         local retry=3 count
1209
1210         remaining=$(LC_ALL=C awk "/^#/ {next} $1" "$2" | sort -r)
1211         while [ -n "$remaining" -a "$retry" -gt 0 ]; do
1212                 if [ "$retry" -eq 3 ]; then
1213                         run_cmd "$3" fstab-decode umount $5 $remaining
1214                 else
1215                         run_cmd "$4" fstab-decode umount $5 $remaining
1216                 fi
1217                 count=4
1218                 remaining=$(LC_ALL=C awk "/^#/ {next} $1" "$2" | sort -r)
1219                 while [ "$count" -gt 0 ]; do
1220                         [ -z "$remaining" ] && break
1221                         count=$(($count-1))
1222                         usleep 500000
1223                         remaining=$(LC_ALL=C awk "/^#/ {next} $1" "$2" | sort -r)
1224                 done
1225                 [ -z "$remaining" ] && break
1226                 fstab-decode /bin/fuser -k -m $sig $remaining >/dev/null
1227                 sleep 3
1228                 retry=$(($retry -1))
1229                 sig=-9
1230         done
1231 }
1232
1233 # Similar to __umount loop above, specialized for loopback devices
1234 __umount_loopback_loop() {
1235         local remaining devremaining sig=
1236         local retry=3
1237
1238         remaining=$(awk '$1 ~ /^\/dev\/loop/ && $2 != "/" {print $2}' /proc/mounts)
1239         devremaining=$(awk '$1 ~ /^\/dev\/loop/ && $2 != "/" {print $1}' /proc/mounts)
1240         while [ -n "$remaining" -a "$retry" -gt 0 ]; do
1241                 if [ "$retry" -eq 3 ]; then
1242                         run_cmd "Unmounting loopback filesystems: " \
1243                                 fstab-decode umount $remaining
1244                 else
1245                         run_cmd "Unmounting loopback filesystems (retry):" \
1246                                 fstab-decode umount $remaining
1247                 fi
1248                 for dev in $devremaining ; do
1249                         losetup $dev > /dev/null 2>&1 && \
1250                                 run_cmd "Detaching loopback device $dev: " \
1251                                 losetup -d $dev
1252                 done
1253                 remaining=$(awk '$1 ~ /^\/dev\/loop/ && $2 != "/" {print $2}' /proc/mounts)
1254                 devremaining=$(awk '$1 ~ /^\/dev\/loop/ && $2 != "/" {print $1}' /proc/mounts)
1255                 [ -z "$remaining" ] && break
1256                 fstab-decode /bin/fuser -k -m $sig $remaining >/dev/null
1257                 sleep 3
1258                 retry=$(($retry -1))
1259                 sig=-9
1260         done
1261 }
1262
1263 rc_cache_init() {
1264         # If we have cachefile, use it.
1265         # If we don't, create memory variables and try to save silently,
1266         local cachefile='/var/cache/rc-scripts/msg.cache'
1267
1268         local term
1269         if is_yes "$ISATTY"; then
1270                 term=$TERM
1271         else
1272                 term=dumb
1273         fi
1274
1275         # We create $check variable which is used to invalidate the cache.
1276         # The $check contains user locale and terminal.
1277         local check="$term.$LC_MESSAGES.$INIT_COL"
1278
1279         if [ -f "$cachefile" -a "$cachefile" -nt /etc/sysconfig/system -a "$cachefile" -nt /etc/sysconfig/init-colors ]; then
1280                 if . "$cachefile" 2>/dev/null; then
1281                         if [ "$check" = "$_check" ]; then
1282                                 return
1283                         fi
1284                 fi
1285         fi
1286
1287         # primitive caching
1288         _busy=$(progress "BUSY" "$CBUSY")
1289         _ok=$(progress "DONE")
1290         _started=$(progress "WORK")
1291         _fail=$(progress "FAIL" "$CFAIL")
1292         _died=$(progress "DIED" "$CFAIL")
1293
1294         # we don't use heredoc, as ksh attempts to create tempfile then
1295         (> "$cachefile" ) 2>/dev/null || return
1296         echo "_busy='$_busy';" >> "$cachefile"
1297         echo "_ok='$_ok';" >> "$cachefile"
1298         echo "_started='$_started';" >> "$cachefile"
1299         echo "_fail='$_fail';" >> "$cachefile"
1300         echo "_died='$_died';" >> "$cachefile"
1301         echo "_check='$check';" >> "$cachefile"
1302 }
1303
1304 rc_gettext_init() {
1305         if [ -z "$GETTEXT" ]; then
1306                 if [ -x /bin/gettext -o -x /usr/bin/gettext ]; then
1307                         GETTEXT=yes
1308                 else
1309                         GETTEXT=no
1310                 fi
1311         fi
1312
1313         if [ -z "$TPUT" ]; then
1314                 if [ -d /usr/share/terminfo ] && [ -x /usr/bin/tput -o -x /bin/tput ]; then
1315                         TPUT=yes
1316                         # check if we are on proper terminal
1317                         tput longname >/dev/null 2>&1 || TPUT=no
1318                 else
1319                         TPUT=no
1320                 fi
1321         fi
1322 }
1323
1324 use_upstart () {
1325         return 1
1326 }
1327 emit () {
1328         return 0
1329 }
1330 is_upstart_task() {
1331         return 1
1332 }
1333 is_upstart_running() {
1334         return 1
1335 }
1336 upstart_start() {
1337         return 1
1338 }
1339 upstart_stop() {
1340         return 1
1341 }
1342 upstart_reload() {
1343         return 0
1344 }
1345 upstart_status() {
1346         return 1
1347 }
1348 _upstart_controlled() {
1349         return 0
1350 }
1351 alias upstart_controlled='_upstart_controlled $0 "$@"'
1352
1353 rc_gettext_init
1354 rc_cache_init
1355
1356 #/*
1357 # * Local variables:
1358 # * mode: sh
1359 # * indent-tabs-mode: notnil
1360 # * End:
1361 # *
1362 # */