/[baselayout]/trunk/sbin/rc
Gentoo

Contents of /trunk/sbin/rc

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1959 - (show annotations) (download)
Wed Apr 5 17:44:34 2006 UTC (8 years, 6 months ago) by uberlord
File size: 12043 byte(s)
    runscript.sh now stores the fact that it failed to to /dev/.rcsysinit
    existing in the directory /dev/.rcafterinit. rc adds services in
    /dev/.rcafterinit to the boot list and then rm -f's that directory. This
    solves the issue of udev-089 forcing coldplug removal.
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 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 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/.rcafterinit ]] ; then
242 for x in $(dolisting /dev/.rcafterinit/) ; do
243 [[ -L ${x} ]] && myscripts="${myscripts} ${x##*/}"
244 done
245 einfo "Device initiated services:${HILITE}${myscripts}${NORMAL}"
246 rm -rf /dev/.rcafterinit
247 fi
248 fi
249
250 [[ ${OLDSOFTLEVEL} == "${BOOTLEVEL}" || ${OLDSOFTLEVEL} == "single" ]] && \
251 /bin/dmesg -n 1
252
253 for x in ${mylevels} ; do
254 [[ -L ${x} ]] && myscripts="${myscripts} ${x##*/}"
255 done
256 fi
257
258 # The softscripts dir contains all scripts that belong to the
259 # runlevel specified in ${svcdir}/softlevel
260 # It needs to be a new directory, else when stopping the services
261 # and the old directory is not intact, things get broken
262
263 mkdir -p -m 0755 "${svcdir}/softscripts.new"
264
265 for x in ${myscripts} ; do
266 if [[ ! -e "/etc/init.d/${x}" ]] ; then
267 ewarn "WARNING: /etc/init.d/${x} missing; skipping ..."
268 continue
269 fi
270 # The -f eliminates a warning if the symlink already exists,
271 # which can happen if a service is in both the boot level and
272 # the current "normal" runlevel
273 ln -snf "/etc/init.d/${x}" "${svcdir}/softscripts.new/${x}"
274 done
275
276 get_stop_services() {
277 local x list
278
279 for x in $(dolisting "${svcdir}/inactive/") \
280 $(dolisting "${svcdir}/started/") ; do
281 list="${list} ${x##*/}"
282 done
283
284 reverse_list $(trace_dependencies ${list})
285 }
286
287 dep_stop() {
288 local x dep needsme depservice
289 local myservice="${1##*/}"
290
291 service_stopped "${myservice}" && return 0
292
293 # Candidate for zapping ?
294 [[ ! -L "${svcdir}/softscripts.new/${myservice}" ]] || \
295 return 0
296
297 # If this is a 'net' service, we do not want to stop it if it was
298 # not in the previous runlevel, and we are not shutting down,
299 # rebooting or going to single runlevel. This is because the user
300 # (or hotplut) might have started it (net.ppp?) ...
301 if net_service "${myservice}" && \
302 [[ ${SOFTLEVEL} != "reboot" && \
303 ${SOFTLEVEL} != "shutdown" && \
304 ${SOFTLEVEL} != "single" ]] ; then
305 if [[ -z ${OLDSOFTLEVEL} ]] || \
306 ! in_runlevel "${myservice}" "${OLDSOFTLEVEL}" ; then
307 # This service is not in the previous runlevel, so
308 # do not stop it ...
309 return 0
310 fi
311 fi
312
313 # Should not work for 'use'
314 if [[ -z $(needsme "${myservice}") ]] ; then
315 # Nothing depends on me
316 stop_service "${myservice}"
317 else
318 # Something may depend on me
319 needsme=0
320
321 for dep in $(needsme "${myservice}") ; 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 "${myservice}"
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 source /sbin/functions.sh
379
380 # Clear $svcdir from stale entries, but leave the caches around, as it
381 # should help speed things up a bit
382 rm -rf $(ls -d1 "${svcdir}/"* 2>/dev/null | \
383 grep -ve '\(depcache\|deptree\|envcache\)')
384
385 # Need try(), etc
386 source "${svclib}"/sh/init-functions.sh
387
388 source /etc/init.d/halt.sh
389
390 if [[ ${SOFTLEVEL} == "reboot" ]] ; then
391 source /etc/init.d/reboot.sh
392 else
393 source /etc/init.d/shutdown.sh
394 fi
395
396 # Should never get here
397 exit 0
398 fi
399
400 if [[ ${SOFTLEVEL} == "single" ]] ; then
401 /sbin/sulogin ${CONSOLE}
402 exit 0
403 fi
404
405 # Move the old softscritps directory to a different one
406 # and make the new softscripts directory the current
407
408 mv -f "${svcdir}/softscripts" "${svcdir}/softscripts.old"
409 mv -f "${svcdir}/softscripts.new" "${svcdir}/softscripts"
410
411 get_start_services() {
412 local x list
413
414 get_critical_services
415 list="${CRITICAL_SERVICES}"
416
417 [[ -n ${LOGGER_SERVICE} && \
418 -L "${svcdir}/softscripts/${LOGGER_SERVICE}" ]] && \
419 list="${list} ${LOGGER_SERVICE}"
420
421 for x in $(dolisting "${svcdir}/softscripts/") ; do
422 list="${list} ${x##*/}"
423 done
424
425 trace_dependencies ${list}
426 }
427
428 # Start scripts
429 for i in $(get_start_services) ; do
430 if service_stopped "${i}" ; then
431 do_interactive start_service "${i}"
432 fi
433 done
434
435 # Wait for any services that may still be running ...
436 [[ ${RC_PARALLEL_STARTUP} == "yes" ]] && wait
437
438 # Clean the old runlevel
439 rm -rf "${svcdir}/softscripts.old" &>/dev/null
440
441 # Depends gets nuked, so update them
442 # (this problem should be solved now, but i think it will be a good idea
443 # to recreate the deps after a change in runlevel)
444
445 #/sbin/depscan.sh &>/dev/null
446
447 # We want devfsd running after a change of runlevel (this is mostly if we return
448 # from runlevel 'single')
449 if [[ -z $(ps --no-heading -C 'devfsd') && \
450 -n $(gawk '/\/dev devfs/ { print }' /proc/mounts 2>/dev/null) ]] ; then
451 if [[ ${RC_DEVFSD_STARTUP} != "no" ]] ; then
452 /sbin/devfsd /dev &>/dev/null
453 fi
454 fi
455
456 # Runlevel end, so clear stale fail list
457 rm -rf "${svcdir}/failed" &>/dev/null
458
459 # If we were in the boot runlevel, it is done now ...
460 if [[ -n ${BOOT} ]] ; then
461 unset BOOT
462 # Save our interactive mode into the default runlevel
463 user_want_interactive && svcinteractive="yes"
464 echo "${svcinteractive}" > "${svcdir}/interactive"
465 else
466 # As we're not boot, we remove the interactive file
467 [[ -e ${svcdir}/interactive ]] && rm -f "${svcdir}/interactive"
468 fi
469
470 # Remove the cached CONSOLETYPE
471 unset CONSOLETYPE
472
473 splash "rc_exit"
474
475 # 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