/[baselayout]/trunk/sbin/rc
Gentoo

Contents of /trunk/sbin/rc

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2026 - (show annotations) (download)
Fri May 5 15:25:14 2006 UTC (9 years ago) by uberlord
File size: 12078 byte(s)
If a device initiated service is in the default runlevel then we no longer start it in the boot runlevel.
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 | grep -q " 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"
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 if [[ ${SOFTLEVEL} != "${BOOTLEVEL}" ]] ; then
232 # Normal runlevels *include* boot scripts
233 mylevels="$(dolisting "/etc/runlevels/${SOFTLEVEL}/")"
234 mylevels="${mylevels} $(dolisting "/etc/runlevels/${BOOTLEVEL}/")"
235 else
236 # Non-normal runlevels don't include boot scripts as default
237 mylevels="$(dolisting "/etc/runlevels/${SOFTLEVEL}/")"
238
239 # As we're in the bootlevel, add any services that failed due
240 # to /dev/.rcsysinit existing to the list
241 if [[ -d /dev/.rcboot ]] ; then
242 for x in $(dolisting /dev/.rcboot/) ; do
243 [[ -L ${x} && ! -e /etc/runlevels/"${DEFAULTLEVEL}"/"${x##*/}" ]] \
244 && myscripts="${myscripts} ${x##*/}"
245 done
246 einfo "Device initiated services:${HILITE}${myscripts}${NORMAL}"
247 rm -rf /dev/.rcboot
248 fi
249 fi
250
251 [[ ${OLDSOFTLEVEL} == "${BOOTLEVEL}" || ${OLDSOFTLEVEL} == "single" ]] && \
252 /bin/dmesg -n 1
253
254 for x in ${mylevels} ; do
255 [[ -L ${x} ]] && myscripts="${myscripts} ${x##*/}"
256 done
257 fi
258
259 # The softscripts dir contains all scripts that belong to the
260 # runlevel specified in ${svcdir}/softlevel
261 # It needs to be a new directory, else when stopping the services
262 # and the old directory is not intact, things get broken
263
264 mkdir -p -m 0755 "${svcdir}/softscripts.new"
265
266 for x in ${myscripts} ; do
267 if [[ ! -e "/etc/init.d/${x}" ]] ; then
268 ewarn "WARNING: /etc/init.d/${x} missing; skipping ..."
269 continue
270 fi
271 # The -f eliminates a warning if the symlink already exists,
272 # which can happen if a service is in both the boot level and
273 # the current "normal" runlevel
274 ln -snf "/etc/init.d/${x}" "${svcdir}/softscripts.new/${x}"
275 done
276
277 get_stop_services() {
278 local x list
279
280 for x in $(dolisting "${svcdir}/inactive/") \
281 $(dolisting "${svcdir}/started/") ; do
282 list="${list} ${x##*/}"
283 done
284
285 reverse_list $(trace_dependencies ${list})
286 }
287
288 dep_stop() {
289 local x dep needsme depservice
290 local myservice="${1##*/}"
291
292 service_stopped "${myservice}" && return 0
293
294 # Candidate for zapping ?
295 [[ ! -L "${svcdir}/softscripts.new/${myservice}" ]] || \
296 return 0
297
298 # If this is a 'net' service, we do not want to stop it if it was
299 # not in the previous runlevel, and we are not shutting down,
300 # rebooting or going to single runlevel. This is because the user
301 # (or hotplut) might have started it (net.ppp?) ...
302 if net_service "${myservice}" && \
303 [[ ${SOFTLEVEL} != "reboot" && \
304 ${SOFTLEVEL} != "shutdown" && \
305 ${SOFTLEVEL} != "single" ]] ; then
306 if [[ -z ${OLDSOFTLEVEL} ]] || \
307 ! in_runlevel "${myservice}" "${OLDSOFTLEVEL}" ; then
308 # This service is not in the previous runlevel, so
309 # do not stop it ...
310 return 0
311 fi
312 fi
313
314 # Should not work for 'use'
315 if [[ -z $(needsme "${myservice}") ]] ; then
316 # Nothing depends on me
317 stop_service "${myservice}"
318 else
319 # Something may depend on me
320 needsme=0
321
322 for dep in $(needsme "${myservice}") ; do
323 if [[ -L "${svcdir}/softscripts.new/${dep}" ]] ; then
324 needsme=1
325 break
326 fi
327 done
328
329 [[ ${needsme} -eq 0 ]] && stop_service "${myservice}"
330 fi
331 }
332
333 # Stop services
334 if [[ ${SOFTLEVEL} != "single" && \
335 ${SOFTLEVEL} != "reboot" && \
336 ${SOFTLEVEL} != "shutdown" ]] ; then
337 for i in $(get_stop_services) ; do
338 dep_stop "${i}"
339 done
340
341 # Wait for any services that may still be stopping ...
342 [[ ${RC_PARALLEL_STARTUP} = "yes" ]] && wait
343 else
344 get_critical_services
345
346 is_critical_service() {
347 local x
348 local myservice="${1##*/}"
349
350 for x in ${CRITICAL_SERVICES} ${LOGGER_SERVICE} ; do
351 [[ ${myservice} == "${x}" ]] && return 0
352 done
353
354 return 1
355 }
356
357 # First stop non critical services
358 for i in $(get_stop_services) ; do
359 is_critical_service "${i}" || dep_stop "${i}"
360 done
361
362 # Wait for any services that may still be stopping ...
363 [[ ${RC_PARALLEL_STARTUP} == "yes" ]] && wait
364
365 export STOP_CRITICAL="yes"
366 # Now stop the rest
367 for i in $(get_stop_services) ; do
368 dep_stop "${i}"
369 done
370 unset STOP_CRITICAL
371 fi
372
373 # Only change softlevel AFTER all the services have been stopped,
374 # else they will not get the depend's right (wrong SOFTLEVEL)
375
376 echo "${SOFTLEVEL}" > "${svcdir}/softlevel"
377
378 if [[ ${SOFTLEVEL} == "reboot" || ${SOFTLEVEL} == "shutdown" ]] ; then
379 source /sbin/functions.sh
380
381 # Clear $svcdir from stale entries, but leave the caches around, as it
382 # should help speed things up a bit
383 rm -rf $(ls -d1 "${svcdir}/"* 2>/dev/null | \
384 grep -ve '\(depcache\|deptree\|envcache\)')
385
386 # Need try(), etc
387 source "${svclib}"/sh/init-functions.sh
388
389 source /etc/init.d/halt.sh
390
391 if [[ ${SOFTLEVEL} == "reboot" ]] ; then
392 source /etc/init.d/reboot.sh
393 else
394 source /etc/init.d/shutdown.sh
395 fi
396
397 # Should never get here
398 exit 0
399 fi
400
401 if [[ ${SOFTLEVEL} == "single" ]] ; then
402 /sbin/sulogin ${CONSOLE}
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