/[baselayout]/trunk/sbin/rc
Gentoo

Contents of /trunk/sbin/rc

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2151 - (show annotations) (download)
Wed Jul 12 16:11:04 2006 UTC (8 years, 1 month ago) by uberlord
File size: 11968 byte(s)
    Add bootmisc as a CRITICAL_SERVICE as too many init scripts don't
    depend on it, which means that /var/run and others could get cleaned after
    daemons write important things there - like pidfiles - when using parallel
    startup.
1 #!/sbin/runscript
2 # Copyright 1999-2006 Gentoo Foundation
3 # Distributed under the terms of the GNU General Public License v2
4
5 trap ":" INT QUIT TSTP
6
7 source /sbin/functions.sh
8
9 # Only source this when this is a livecd booting ...
10 [[ -f /sbin/livecd-functions.sh ]] && source /sbin/livecd-functions.sh
11
12 umask 022
13
14 # Quick test to see if we can be interactive or not
15 if [[ ${RC_INTERACTIVE:-yes} == "yes" ]] ; then
16 if tty -s && [[ $(stty -a) =~ " icanon" ]] ; then
17 RC_INTERACTIVE="yes"
18 else
19 RC_INTERACTIVE="no"
20 fi
21 fi
22
23 # void noblock_read(var)
24 #
25 # reads a line of input into var like regular read
26 # but it does not block waiting for input
27 #
28 noblock_read() {
29 local old_tty_settings=$(stty -g)
30 stty -icanon min 0 time 0
31 read "$@"
32 stty "${old_tty_settings}"
33 }
34
35 # bool user_want_interactive(void)
36 #
37 # return 0 if user wants interactive mode
38 #
39 user_want_interactive() {
40 [[ ${RC_INTERACTIVE} != "yes" ]] && return 1
41
42 local user_input
43 noblock_read user_input
44 [[ ${user_input} == *"I"* || ${user_input} == *"i"* ]]
45 }
46
47 # void do_interactive
48 #
49 # starts, skips, continues or drops to the shell
50 # depending on user selection
51 #
52 do_interactive() {
53 local service="$2"
54
55 user_want_interactive && svcinteractive="yes"
56 if [[ ${svcinteractive} != "yes" || ! -e "/etc/init.d/${service}" ]] ; then
57 "$@"
58 return $?
59 fi
60
61 local start_text="Start service"
62 local skip_text="Skip service"
63 local continue_text="Continue boot process"
64 local shell_text="Exit to shell"
65
66 echo
67 echo "About to start the service ${service}"
68 PS3="Enter your selection: "
69 select action in "${start_text}" "${skip_text}" "${continue_text}" \
70 "${shell_text}"
71 do
72 case ${action} in
73 "${start_text}")
74 "$@"
75 break
76 ;;
77 "${skip_text}")
78 break
79 ;;
80 "${continue_text}")
81 svcinteractive="no"
82 "$@"
83 break
84 ;;
85 "${shell_text}")
86 echo
87 sulogin "${CONSOLE}"
88 ;;
89 esac
90 done
91 }
92
93 # void get_critical_services()
94 #
95 # Get critical services needed for bootup, and exports CRITICAL_SERVICES
96 #
97 get_critical_services() {
98 local x=
99 CRITICAL_SERVICES=
100
101 if [[ -f "/etc/runlevels/${BOOTLEVEL}/.critical" ]] ; then
102 for x in $(< "/etc/runlevels/${BOOTLEVEL}/.critical") ; do
103 CRITICAL_SERVICES="${CRITICAL_SERVICES} ${x##*/}"
104 done
105 else
106 CRITICAL_SERVICES="checkroot modules checkfs localmount clock bootmisc"
107 fi
108
109 export CRITICAL_SERVICES
110
111 return 0
112 }
113
114 # void check_critical_services()
115 #
116 # Ensure that critical services are in the boot runlevel
117 #
118 check_critical_services() {
119 local x
120
121 for x in ${CRITICAL_SERVICES} ; do
122 if [[ ! -L "/etc/runlevels/${BOOTLEVEL}/${x}" ]] ; then
123 ewarn "WARNING: Adding critical service ${x} to the ${BOOTLEVEL} runlevel"
124 ln -snf "/etc/init.d/${x}" "/etc/runlevels/${BOOTLEVEL}/${x}"
125 fi
126 done
127 }
128
129 # Save $1
130 argv1=$1
131
132 # First time boot stuff goes here. Note that 'sysinit' is an internal runlevel
133 # used to bring up local filesystems, and should not be started with /sbin/rc
134 # directly ...
135 if [[ ( ${RUNLEVEL} == "S" || ${RUNLEVEL} == "1" ) && ${argv1} = "sysinit" ]]
136 then
137 source "${svclib}"/sh/init.sh || {
138 echo "Could not source init.sh !?"
139 exit 1
140 }
141
142 exit 0
143 fi # Sysinit ends here
144
145 if [[ ( ${RUNLEVEL} == "S" || ${RUNLEVEL} == "1" ) && ${argv1} == "boot" ]]
146 then
147 setup_defaultlevels
148
149 if [[ -n ${DEFAULTLEVEL} && ${DEFAULTLEVEL} != "default" ]] ; then
150 # Setup our default runlevel runlevel that will be run
151 # the first time /sbin/rc is called with argv1 != sysinit|boot
152 echo "${DEFAULTLEVEL}" > "${svcdir}/ksoftlevel"
153 fi
154
155 # $BOOT can be used by rc-scripts to test if it is the first time
156 # the 'boot' runlevel is executed
157 export BOOT="yes"
158
159 # We reset argv1 to the bootlevel given on the kernel command line
160 # if there is one
161 argv1="${BOOTLEVEL}"
162
163 elif [[ ${RUNLEVEL} != "S" && ${RUNLEVEL} != "1" && -e "${svcdir}/ksoftlevel" ]]
164 then
165 argv1=$(<"${svcdir}"/ksoftlevel)
166 rm -f "${svcdir}/ksoftlevel"
167 elif [[ ${RUNLEVEL} != "S" && ${RUNLEVEL} != "1" && ${argv1} == "single" ]]
168 then
169 /sbin/telinit S
170 exit 0
171 elif [[ ( ${RUNLEVEL} == "S" || ${RUNLEVEL} == "1" ) && ${argv1} != "single" ]]
172 then
173 level=$(awk -v level="${argv1}" '
174 $2 == level {
175 split($0, fields, ":")
176 print fields[2]
177 exit
178 }' /etc/inittab 2>/dev/null)
179 [[ -z ${level} ]] && level=3
180 /sbin/telinit "${level}"
181 exit 0
182 fi
183
184 # Ensure all critical services have are in the boot runlevel
185 get_critical_services
186 check_critical_services
187 source "${svclib}/sh/rc-services.sh"
188
189 if [[ -f "${svcdir}/softlevel" ]] ; then
190 # Set OLDSOFTLEVEL if we had a valid SOFTLEVEL
191 export OLDSOFTLEVEL=$(<"${svcdir}/softlevel")
192 else
193 export OLDSOFTLEVEL=
194 fi
195
196 if [[ -z ${argv1} ]] ; then
197 if [[ -f "${svcdir}/softlevel" ]] ; then
198 export SOFTLEVEL=$(<"${svcdir}/softlevel")
199 else
200 export SOFTLEVEL="${BOOTLEVEL}"
201 fi
202 else
203 export SOFTLEVEL="${argv1}"
204 fi
205
206 if [[ ! -f "${svcdir}/softlevel" ]] ; then
207 echo "${SOFTLEVEL}" > "${svcdir}/softlevel"
208 fi
209
210 [[ -e "${svcdir}/interactive" ]] && \
211 svcinteractive=$(<"${svcdir}/interactive")
212
213 # For keeping a list of services that fails during boot/halt
214 if [[ ! -d "${svcdir}/failed" ]] ; then
215 mkdir -p -m 0755 "${svcdir}/failed"
216 else
217 rm -rf "${svcdir}"/failed/*
218 fi
219
220 splash "rc_init" "${argv1}"
221
222 if [[ ${SOFTLEVEL} == "reboot" || ${SOFTLEVEL} == "shutdown" ]] ; then
223 myscripts=
224 elif [[ ${SOFTLEVEL} = "single" ]] ; then
225 myscripts="${CRITICAL_SERVICES}"
226 elif [[ ! -d "/etc/runlevels/${SOFTLEVEL}" ]] ; then
227 eerror "ERROR: runlevel ${SOFTLEVEL} does not exist; exiting ..."
228 exit 1
229 else
230 myscripts=
231
232 if [[ ${SOFTLEVEL} != "${BOOTLEVEL}" ]] ; then
233 # Normal runlevels *include* boot scripts
234 mylevels=$(dolisting "/etc/runlevels/${SOFTLEVEL}/")
235 mylevels="${mylevels} $(dolisting "/etc/runlevels/${BOOTLEVEL}/")"
236 else
237 # Non-normal runlevels don't include boot scripts as default
238 mylevels=$(dolisting "/etc/runlevels/${SOFTLEVEL}/")
239
240 # As we're in the bootlevel, add any services that failed due
241 # to /dev/.rcsysinit existing to the list
242 if [[ -d /dev/.rcboot ]] ; then
243 COLDPLUG_SERVICES=
244 for x in $(dolisting /dev/.rcboot/) ; do
245 [[ -L ${x} ]] && COLDPLUG_SERVICES="${COLDPLUG_SERVICES} ${x##*/}"
246 done
247 for x in ${COLDPLUG_SERVICES} ; do
248 if [[ ! -e /etc/runlevels/"${BOOTLEVEL}"/"${x}" \
249 && ! -e /etc/runlevels/"${DEFAULTLEVEL}"/"${x}" ]] ; then
250 myscripts="${myscripts} ${x}"
251 mark_service_coldplugged "${x}"
252 fi
253 done
254 einfo "Device initiated services:${HILITE}${myscripts}${NORMAL}"
255 rm -rf /dev/.rcboot
256 fi
257 fi
258
259 for x in ${mylevels} ; do
260 [[ -L ${x} ]] && myscripts="${myscripts} ${x##*/}"
261 done
262 fi
263
264 # The softscripts dir contains all scripts that belong to the
265 # runlevel specified in ${svcdir}/softlevel
266 # It needs to be a new directory, else when stopping the services
267 # and the old directory is not intact, things get broken
268
269 mkdir -p -m 0755 "${svcdir}/softscripts.new"
270
271 for x in ${myscripts} ; do
272 if [[ ! -e "/etc/init.d/${x}" ]] ; then
273 ewarn "WARNING: /etc/init.d/${x} missing; skipping ..."
274 continue
275 fi
276 # The -f eliminates a warning if the symlink already exists,
277 # which can happen if a service is in both the boot level and
278 # the current "normal" runlevel
279 ln -snf "/etc/init.d/${x}" "${svcdir}/softscripts.new/${x}"
280 done
281
282 get_stop_services() {
283 local x list
284
285 for x in $(dolisting "${svcdir}/inactive/") \
286 $(dolisting "${svcdir}/started/") ; do
287 list="${list} ${x##*/}"
288 done
289
290 reverse_list $(trace_dependencies ${list})
291 }
292
293 dep_stop() {
294 local x dep needsme depservice
295 local service="${1##*/}"
296
297 service_stopped "${service}" && return 0
298
299 [[ -L ${svcdir}/softscripts.new/${service} ]] \
300 && return 0
301
302 if [[ ${SOFTLEVEL} != "reboot" \
303 && ${SOFTLEVEL} != "shutdown" \
304 && ${SOFTLEVEL} != "single" ]] ; then
305 service_coldplugged "${service}" && return 0
306 if net_service "${service}" ; then
307 [[ -z ${OLDSOFTLEVEL} ]] \
308 || ! in_runlevel "${service}" "${OLDSOFTLEVEL}" \
309 && return 0
310 fi
311 fi
312
313 # Should not work for 'use'
314 if [[ -z $(needsme "${service}") ]] ; then
315 # Nothing depends on me
316 stop_service "${service}"
317 else
318 # Something may depend on me
319 needsme=0
320
321 for dep in $(needsme "${service}") ; do
322 if [[ -L "${svcdir}/softscripts.new/${dep}" ]] ; then
323 needsme=1
324 break
325 fi
326 done
327
328 [[ ${needsme} -eq 0 ]] && stop_service "${service}"
329 fi
330 }
331
332 # Stop services
333 if [[ ${SOFTLEVEL} != "single" && \
334 ${SOFTLEVEL} != "reboot" && \
335 ${SOFTLEVEL} != "shutdown" ]] ; then
336 for i in $(get_stop_services) ; do
337 dep_stop "${i}"
338 done
339
340 # Wait for any services that may still be stopping ...
341 [[ ${RC_PARALLEL_STARTUP} = "yes" ]] && wait
342 else
343 get_critical_services
344
345 is_critical_service() {
346 local x
347 local myservice="${1##*/}"
348
349 for x in ${CRITICAL_SERVICES} ${LOGGER_SERVICE} ; do
350 [[ ${myservice} == "${x}" ]] && return 0
351 done
352
353 return 1
354 }
355
356 # First stop non critical services
357 for i in $(get_stop_services) ; do
358 is_critical_service "${i}" || dep_stop "${i}"
359 done
360
361 # Wait for any services that may still be stopping ...
362 [[ ${RC_PARALLEL_STARTUP} == "yes" ]] && wait
363
364 export STOP_CRITICAL="yes"
365 # Now stop the rest
366 for i in $(get_stop_services) ; do
367 dep_stop "${i}"
368 done
369 unset STOP_CRITICAL
370 fi
371
372 # Only change softlevel AFTER all the services have been stopped,
373 # else they will not get the depend's right (wrong SOFTLEVEL)
374
375 echo "${SOFTLEVEL}" > "${svcdir}/softlevel"
376
377 if [[ ${SOFTLEVEL} == "reboot" || ${SOFTLEVEL} == "shutdown" ]] ; then
378 # Clear $svcdir from stale entries, but leave the caches around, as it
379 # should help speed things up a bit
380 rm -rf $(ls -d1 "${svcdir}/"* 2>/dev/null | \
381 grep -ve '\(depcache\|deptree\|envcache\)')
382
383 # Call halt.sh with LC_ALL=C so that bash doesn't load any locales
384 # which could interfere with unmounting /usr
385 if is_vps_sys ; then
386 halt -w
387 LC_ALL=C exec /etc/init.d/"${SOFTLEVEL}".sh
388 else
389 LC_ALL=C exec /etc/init.d/halt.sh "${SOFTLEVEL}"
390 fi
391
392 # Should never get here
393 exit 0
394 fi
395
396 if [[ ${SOFTLEVEL} == "single" ]] ; then
397 rm -rf "${svcdir}/softscripts.new"
398 if is_vps_sys ; then
399 /sbin/halt -f
400 else
401 /sbin/sulogin ${CONSOLE}
402 fi
403 exit 0
404 fi
405
406 # Move the old softscritps directory to a different one
407 # and make the new softscripts directory the current
408
409 mv -f "${svcdir}/softscripts" "${svcdir}/softscripts.old"
410 mv -f "${svcdir}/softscripts.new" "${svcdir}/softscripts"
411
412 get_start_services() {
413 local x list
414
415 get_critical_services
416 list="${CRITICAL_SERVICES}"
417
418 [[ -n ${LOGGER_SERVICE} && \
419 -L "${svcdir}/softscripts/${LOGGER_SERVICE}" ]] && \
420 list="${list} ${LOGGER_SERVICE}"
421
422 for x in $(dolisting "${svcdir}/softscripts/") ; do
423 list="${list} ${x##*/}"
424 done
425
426 trace_dependencies ${list}
427 }
428
429 # Start scripts
430 for i in $(get_start_services) ; do
431 if service_stopped "${i}" ; then
432 do_interactive start_service "${i}"
433 fi
434 done
435
436 # Wait for any services that may still be running ...
437 [[ ${RC_PARALLEL_STARTUP} == "yes" ]] && wait
438
439 # Clean the old runlevel
440 rm -rf "${svcdir}/softscripts.old" &>/dev/null
441
442 # Depends gets nuked, so update them
443 # (this problem should be solved now, but i think it will be a good idea
444 # to recreate the deps after a change in runlevel)
445
446 #/sbin/depscan.sh &>/dev/null
447
448 # We want devfsd running after a change of runlevel (this is mostly if we return
449 # from runlevel 'single')
450 if [[ -z $(ps --no-heading -C 'devfsd') && \
451 -n $(gawk '/\/dev devfs/ { print }' /proc/mounts 2>/dev/null) ]] ; then
452 if [[ ${RC_DEVFSD_STARTUP} != "no" ]] ; then
453 /sbin/devfsd /dev &>/dev/null
454 fi
455 fi
456
457 # Runlevel end, so clear stale fail list
458 rm -rf "${svcdir}/failed" &>/dev/null
459
460 # If we were in the boot runlevel, it is done now ...
461 if [[ -n ${BOOT} ]] ; then
462 unset BOOT
463 # Save our interactive mode into the default runlevel
464 user_want_interactive && svcinteractive="yes"
465 echo "${svcinteractive}" > "${svcdir}/interactive"
466 else
467 # As we're not boot, we remove the interactive file
468 [[ -e ${svcdir}/interactive ]] && rm -f "${svcdir}/interactive"
469 fi
470
471 # Remove the cached CONSOLETYPE
472 unset CONSOLETYPE
473
474 splash "rc_exit"
475
476 # vim:ts=4

Properties

Name Value
svn:eol-style native
svn:executable *
svn:keywords Author Date Id Revision

  ViewVC Help
Powered by ViewVC 1.1.20