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