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