1
0

init-functions 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745
  1. #!/bin/sh
  2. ########################################################################
  3. #
  4. # Begin /lib/lsb/init-funtions
  5. #
  6. # Description : Run Level Control Functions
  7. #
  8. # Authors : Gerard Beekmans - gerard@linuxfromscratch.org
  9. # : DJ Lucas - dj@linuxfromscratch.org
  10. # Update : Bruce Dubbs - bdubbs@linuxfromscratch.org
  11. #
  12. # Version : LFS 7.0
  13. #
  14. # Notes : With code based on Matthias Benkmann's simpleinit-msb
  15. # http://winterdrache.de/linux/newboot/index.html
  16. #
  17. # The file should be located in /lib/lsb
  18. #
  19. ########################################################################
  20. ## Environmental setup
  21. # Setup default values for environment
  22. umask 022
  23. export PATH="/bin:/usr/bin:/sbin:/usr/sbin"
  24. ## Screen Dimensions
  25. # Find current screen size
  26. if [ -z "${COLUMNS}" ]; then
  27. COLUMNS=$(stty size)
  28. COLUMNS=${COLUMNS##* }
  29. fi
  30. # When using remote connections, such as a serial port, stty size returns 0
  31. if [ "${COLUMNS}" = "0" ]; then
  32. COLUMNS=80
  33. fi
  34. ## Measurements for positioning result messages
  35. COL=$((${COLUMNS} - 8))
  36. WCOL=$((${COL} - 2))
  37. ## Set Cursor Position Commands, used via echo
  38. SET_COL="\\033[${COL}G" # at the $COL char
  39. SET_WCOL="\\033[${WCOL}G" # at the $WCOL char
  40. CURS_UP="\\033[1A\\033[0G" # Up one line, at the 0'th char
  41. ## Set color commands, used via echo
  42. # Please consult `man console_codes for more information
  43. # under the "ECMA-48 Set Graphics Rendition" section
  44. #
  45. # Warning: when switching from a 8bit to a 9bit font,
  46. # the linux console will reinterpret the bold (1;) to
  47. # the top 256 glyphs of the 9bit font. This does
  48. # not affect framebuffer consoles
  49. NORMAL="\\033[0;39m" # Standard console grey
  50. SUCCESS="\\033[1;32m" # Success is green
  51. WARNING="\\033[1;33m" # Warnings are yellow
  52. FAILURE="\\033[1;31m" # Failures are red
  53. INFO="\\033[1;36m" # Information is light cyan
  54. BRACKET="\\033[1;34m" # Brackets are blue
  55. BOOTLOG=/run/var/bootlog
  56. KILLDELAY=3
  57. # Set any user specified environment variables e.g. HEADLESS
  58. [ -r /etc/sysconfig/rc.site ] && . /etc/sysconfig/rc.site
  59. ################################################################################
  60. # start_daemon() #
  61. # Usage: start_daemon [-f] [-n nicelevel] [-p pidfile] pathname [args...] #
  62. # #
  63. # Purpose: This runs the specified program as a daemon #
  64. # #
  65. # Inputs: -f: (force) run the program even if it is already running. #
  66. # -n nicelevel: specify a nice level. See 'man nice(1)'. #
  67. # -p pidfile: use the specified file to determine PIDs. #
  68. # pathname: the complete path to the specified program #
  69. # args: additional arguments passed to the program (pathname) #
  70. # #
  71. # Return values (as defined by LSB exit codes): #
  72. # 0 - program is running or service is OK #
  73. # 1 - generic or unspecified error #
  74. # 2 - invalid or excessive argument(s) #
  75. # 5 - program is not installed #
  76. ################################################################################
  77. start_daemon()
  78. {
  79. local force=""
  80. local nice="0"
  81. local pidfile=""
  82. local pidlist=""
  83. local retval=""
  84. # Process arguments
  85. while true
  86. do
  87. case "${1}" in
  88. -f)
  89. force="1"
  90. shift 1
  91. ;;
  92. -n)
  93. nice="${2}"
  94. shift 2
  95. ;;
  96. -p)
  97. pidfile="${2}"
  98. shift 2
  99. ;;
  100. -*)
  101. return 2
  102. ;;
  103. *)
  104. program="${1}"
  105. break
  106. ;;
  107. esac
  108. done
  109. # Check for a valid program
  110. if [ ! -e "${program}" ]; then return 5; fi
  111. # Execute
  112. if [ -z "${force}" ]; then
  113. if [ -z "${pidfile}" ]; then
  114. # Determine the pid by discovery
  115. pidlist=`pidofproc "${1}"`
  116. retval="${?}"
  117. else
  118. # The PID file contains the needed PIDs
  119. # Note that by LSB requirement, the path must be given to pidofproc,
  120. # however, it is not used by the current implementation or standard.
  121. pidlist=`pidofproc -p "${pidfile}" "${1}"`
  122. retval="${?}"
  123. fi
  124. # Return a value ONLY
  125. # It is the init script's (or distribution's functions) responsibilty
  126. # to log messages!
  127. case "${retval}" in
  128. 0)
  129. # Program is already running correctly, this is a
  130. # succesful start.
  131. return 0
  132. ;;
  133. 1)
  134. # Program is not running, but an invalid pid file exists
  135. # remove the pid file and continue
  136. rm -f "${pidfile}"
  137. ;;
  138. 3)
  139. # Program is not running and no pidfile exists
  140. # do nothing here, let start_deamon continue.
  141. ;;
  142. *)
  143. # Others as returned by status values shall not be interpreted
  144. # and returned as an unspecified error.
  145. return 1
  146. ;;
  147. esac
  148. fi
  149. # Do the start!
  150. nice -n "${nice}" "${@}"
  151. }
  152. ################################################################################
  153. # killproc() #
  154. # Usage: killproc [-p pidfile] pathname [signal] #
  155. # #
  156. # Purpose: Send control signals to running processes #
  157. # #
  158. # Inputs: -p pidfile, uses the specified pidfile #
  159. # pathname, pathname to the specified program #
  160. # signal, send this signal to pathname #
  161. # #
  162. # Return values (as defined by LSB exit codes): #
  163. # 0 - program (pathname) has stopped/is already stopped or a #
  164. # running program has been sent specified signal and stopped #
  165. # successfully #
  166. # 1 - generic or unspecified error #
  167. # 2 - invalid or excessive argument(s) #
  168. # 5 - program is not installed #
  169. # 7 - program is not running and a signal was supplied #
  170. ################################################################################
  171. killproc()
  172. {
  173. local pidfile
  174. local program
  175. local prefix
  176. local progname
  177. local signal="-TERM"
  178. local fallback="-KILL"
  179. local nosig
  180. local pidlist
  181. local retval
  182. local pid
  183. local delay="30"
  184. local piddead
  185. local dtime
  186. # Process arguments
  187. while true; do
  188. case "${1}" in
  189. -p)
  190. pidfile="${2}"
  191. shift 2
  192. ;;
  193. *)
  194. program="${1}"
  195. if [ -n "${2}" ]; then
  196. signal="${2}"
  197. fallback=""
  198. else
  199. nosig=1
  200. fi
  201. # Error on additional arguments
  202. if [ -n "${3}" ]; then
  203. return 2
  204. else
  205. break
  206. fi
  207. ;;
  208. esac
  209. done
  210. # Check for a valid program
  211. if [ ! -e "${program}" ]; then return 5; fi
  212. # Check for a valid signal
  213. check_signal "${signal}"
  214. if [ "${?}" -ne "0" ]; then return 2; fi
  215. # Get a list of pids
  216. if [ -z "${pidfile}" ]; then
  217. # determine the pid by discovery
  218. pidlist=`pidofproc "${1}"`
  219. retval="${?}"
  220. else
  221. # The PID file contains the needed PIDs
  222. # Note that by LSB requirement, the path must be given to pidofproc,
  223. # however, it is not used by the current implementation or standard.
  224. pidlist=`pidofproc -p "${pidfile}" "${1}"`
  225. retval="${?}"
  226. fi
  227. # Return a value ONLY
  228. # It is the init script's (or distribution's functions) responsibilty
  229. # to log messages!
  230. case "${retval}" in
  231. 0)
  232. # Program is running correctly
  233. # Do nothing here, let killproc continue.
  234. ;;
  235. 1)
  236. # Program is not running, but an invalid pid file exists
  237. # Remove the pid file.
  238. rm -f "${pidfile}"
  239. # This is only a success if no signal was passed.
  240. if [ -n "${nosig}" ]; then
  241. return 0
  242. else
  243. return 7
  244. fi
  245. ;;
  246. 3)
  247. # Program is not running and no pidfile exists
  248. # This is only a success if no signal was passed.
  249. if [ -n "${nosig}" ]; then
  250. return 0
  251. else
  252. return 7
  253. fi
  254. ;;
  255. *)
  256. # Others as returned by status values shall not be interpreted
  257. # and returned as an unspecified error.
  258. return 1
  259. ;;
  260. esac
  261. # Perform different actions for exit signals and control signals
  262. check_sig_type "${signal}"
  263. if [ "${?}" -eq "0" ]; then # Signal is used to terminate the program
  264. # Account for empty pidlist (pid file still exists and no
  265. # signal was given)
  266. if [ "${pidlist}" != "" ]; then
  267. # Kill the list of pids
  268. for pid in ${pidlist}; do
  269. kill -0 "${pid}" 2> /dev/null
  270. if [ "${?}" -ne "0" ]; then
  271. # Process is dead, continue to next and assume all is well
  272. continue
  273. else
  274. kill "${signal}" "${pid}" 2> /dev/null
  275. # Wait up to ${delay}/10 seconds to for "${pid}" to
  276. # terminate in 10ths of a second
  277. while [ "${delay}" -ne "0" ]; do
  278. kill -0 "${pid}" 2> /dev/null || piddead="1"
  279. if [ "${piddead}" = "1" ]; then break; fi
  280. sleep 0.1
  281. delay="$(( ${delay} - 1 ))"
  282. done
  283. # If a fallback is set, and program is still running, then
  284. # use the fallback
  285. if [ -n "${fallback}" -a "${piddead}" != "1" ]; then
  286. kill "${fallback}" "${pid}" 2> /dev/null
  287. sleep 1
  288. # Check again, and fail if still running
  289. kill -0 "${pid}" 2> /dev/null && return 1
  290. else
  291. # just check one last time and if still alive, fail
  292. sleep 1
  293. kill -0 "${pid}" 2> /dev/null && return 1
  294. fi
  295. fi
  296. done
  297. fi
  298. # Check for and remove stale PID files.
  299. if [ -z "${pidfile}" ]; then
  300. # Find the basename of $program
  301. prefix=`echo "${program}" | sed 's/[^/]*$//'`
  302. progname=`echo "${program}" | sed "s@${prefix}@@"`
  303. if [ -e "/var/run/${progname}.pid" ]; then
  304. rm -f "/var/run/${progname}.pid" 2> /dev/null
  305. fi
  306. else
  307. if [ -e "${pidfile}" ]; then rm -f "${pidfile}" 2> /dev/null; fi
  308. fi
  309. # For signals that do not expect a program to exit, simply
  310. # let kill do it's job, and evaluate kills return for value
  311. else # check_sig_type - signal is not used to terminate program
  312. for pid in ${pidlist}; do
  313. kill "${signal}" "${pid}"
  314. if [ "${?}" -ne "0" ]; then return 1; fi
  315. done
  316. fi
  317. }
  318. ################################################################################
  319. # pidofproc() #
  320. # Usage: pidofproc [-p pidfile] pathname #
  321. # #
  322. # Purpose: This function returns one or more pid(s) for a particular daemon #
  323. # #
  324. # Inputs: -p pidfile, use the specified pidfile instead of pidof #
  325. # pathname, path to the specified program #
  326. # #
  327. # Return values (as defined by LSB status codes): #
  328. # 0 - Success (PIDs to stdout) #
  329. # 1 - Program is dead, PID file still exists (remaining PIDs output) #
  330. # 3 - Program is not running (no output) #
  331. ################################################################################
  332. pidofproc()
  333. {
  334. local pidfile
  335. local program
  336. local prefix
  337. local progname
  338. local pidlist
  339. local lpids
  340. local exitstatus="0"
  341. # Process arguments
  342. while true; do
  343. case "${1}" in
  344. -p)
  345. pidfile="${2}"
  346. shift 2
  347. ;;
  348. *)
  349. program="${1}"
  350. if [ -n "${2}" ]; then
  351. # Too many arguments
  352. # Since this is status, return unknown
  353. return 4
  354. else
  355. break
  356. fi
  357. ;;
  358. esac
  359. done
  360. # If a PID file is not specified, try and find one.
  361. if [ -z "${pidfile}" ]; then
  362. # Get the program's basename
  363. prefix=`echo "${program}" | sed 's/[^/]*$//'`
  364. if [ -z "${prefix}" ]; then
  365. progname="${program}"
  366. else
  367. progname=`echo "${program}" | sed "s@${prefix}@@"`
  368. fi
  369. # If a PID file exists with that name, assume that is it.
  370. if [ -e "/var/run/${progname}.pid" ]; then
  371. pidfile="/var/run/${progname}.pid"
  372. fi
  373. fi
  374. # If a PID file is set and exists, use it.
  375. if [ -n "${pidfile}" -a -e "${pidfile}" ]; then
  376. # Use the value in the first line of the pidfile
  377. pidlist=`/bin/head -n1 "${pidfile}"`
  378. # This can optionally be written as 'sed 1q' to repalce 'head -n1'
  379. # should LFS move /bin/head to /usr/bin/head
  380. else
  381. # Use pidof
  382. pidlist=`pidof "${program}"`
  383. fi
  384. # Figure out if all listed PIDs are running.
  385. for pid in ${pidlist}; do
  386. kill -0 ${pid} 2> /dev/null
  387. if [ "${?}" -eq "0" ]; then
  388. lpids="${pids}${pid} "
  389. else
  390. exitstatus="1"
  391. fi
  392. done
  393. if [ -z "${lpids}" -a ! -f "${pidfile}" ]; then
  394. return 3
  395. else
  396. echo "${lpids}"
  397. return "${exitstatus}"
  398. fi
  399. }
  400. ################################################################################
  401. # statusproc() #
  402. # Usage: statusproc [-p pidfile] pathname #
  403. # #
  404. # Purpose: This function prints the status of a particular daemon to stdout #
  405. # #
  406. # Inputs: -p pidfile, use the specified pidfile instead of pidof #
  407. # pathname, path to the specified program #
  408. # #
  409. # Note: Output to stdout. Not logged. #
  410. # #
  411. # Return values: #
  412. # 0 - Status printed #
  413. # 1 - Input error. The daemon to check was not specified. #
  414. ################################################################################
  415. statusproc()
  416. {
  417. if [ "${#}" = "0" ]; then
  418. echo "Usage: statusproc {program}"
  419. exit 1
  420. fi
  421. local pidfile
  422. local pidlist
  423. # Process arguments
  424. while true; do
  425. case "${1}" in
  426. -p)
  427. pidfile="${2}"
  428. shift 2
  429. ;;
  430. esac
  431. done
  432. if [ -z "${pidfile}" ]; then
  433. pidlist=`pidofproc -p "${pidfile}" $@`
  434. else
  435. pidlist=`pidofproc $@`
  436. fi
  437. # Trim trailing blanks
  438. pidlist=`echo "${pidlist}" | sed -r 's/ +$//'`
  439. base="${1##*/}"
  440. if [ -n "${pidlist}" ]; then
  441. echo -e "${INFO}${base} is running with Process" \
  442. "ID(s) ${pidlist}.${NORMAL}"
  443. else
  444. if [ -n "${base}" -a -e "/var/run/${base}.pid" ]; then
  445. echo -e "${WARNING}${1} is not running but" \
  446. "/var/run/${base}.pid exists.${NORMAL}"
  447. else
  448. if [ -z "${pidlist}" -a -n "${pidfile}" ]; then
  449. echo -e "${WARNING}${1} is not running" \
  450. "but ${pidfile} exists.${NORMAL}"
  451. else
  452. echo -e "${INFO}${1} is not running.${NORMAL}"
  453. fi
  454. fi
  455. fi
  456. }
  457. ################################################################################
  458. # timespec() #
  459. # #
  460. # Purpose: An internal utility function to format a timestamp #
  461. # a boot log file. Sets the STAMP variable. #
  462. # #
  463. # Return value: Not used #
  464. ################################################################################
  465. timespec()
  466. {
  467. STAMP="$(echo `date +"%b %d %T %:z"` `hostname`) "
  468. return 0
  469. }
  470. ################################################################################
  471. # log_success_msg() #
  472. # Usage: log_success_msg ["message"] #
  473. # #
  474. # Purpose: Print a successful status message to the screen and #
  475. # a boot log file. #
  476. # #
  477. # Inputs: $@ - Message #
  478. # #
  479. # Return values: Not used #
  480. ################################################################################
  481. log_success_msg()
  482. {
  483. echo -n -e "${@}"
  484. echo -e "${SET_COL}${BRACKET}[${SUCCESS} OK ${BRACKET}]${NORMAL}"
  485. timespec
  486. echo -e "${STAMP} ${@} OK" >> ${BOOTLOG}
  487. return 0
  488. }
  489. log_success_msg2()
  490. {
  491. echo -n -e "${@}"
  492. echo -e "${SET_COL}${BRACKET}[${SUCCESS} OK ${BRACKET}]${NORMAL}"
  493. echo " OK" >> ${BOOTLOG}
  494. return 0
  495. }
  496. ################################################################################
  497. # log_failure_msg() #
  498. # Usage: log_failure_msg ["message"] #
  499. # #
  500. # Purpose: Print a failure status message to the screen and #
  501. # a boot log file. #
  502. # #
  503. # Inputs: $@ - Message #
  504. # #
  505. # Return values: Not used #
  506. ################################################################################
  507. log_failure_msg()
  508. {
  509. echo -n -e "${@}"
  510. echo -e "${SET_COL}${BRACKET}[${FAILURE} FAIL ${BRACKET}]${NORMAL}"
  511. timespec
  512. echo -e "${STAMP} ${@} FAIL" >> ${BOOTLOG}
  513. return 0
  514. }
  515. log_failure_msg2()
  516. {
  517. echo -n -e "${@}"
  518. echo -e "${SET_COL}${BRACKET}[${FAILURE} FAIL ${BRACKET}]${NORMAL}"
  519. echo "FAIL" >> ${BOOTLOG}
  520. return 0
  521. }
  522. ################################################################################
  523. # log_warning_msg() #
  524. # Usage: log_warning_msg ["message"] #
  525. # #
  526. # Purpose: Print a warning status message to the screen and #
  527. # a boot log file. #
  528. # #
  529. # Return values: Not used #
  530. ################################################################################
  531. log_warning_msg()
  532. {
  533. echo -n -e "${@}"
  534. echo -e "${SET_COL}${BRACKET}[${WARNING} WARN ${BRACKET}]${NORMAL}"
  535. timespec
  536. echo -e "${STAMP} ${@} WARN" >> ${BOOTLOG}
  537. return 0
  538. }
  539. ################################################################################
  540. # log_info_msg() #
  541. # Usage: log_info_msg message #
  542. # #
  543. # Purpose: Print an information message to the screen and #
  544. # a boot log file. Does not print a trailing newline character. #
  545. # #
  546. # Return values: Not used #
  547. ################################################################################
  548. log_info_msg()
  549. {
  550. echo -n -e "${@}"
  551. timespec
  552. echo -n -e "${STAMP} ${@}" >> ${BOOTLOG}
  553. return 0
  554. }
  555. log_info_msg2()
  556. {
  557. echo -n -e "${@}"
  558. echo -n -e "${@}" >> ${BOOTLOG}
  559. return 0
  560. }
  561. ################################################################################
  562. # evaluate_retval() #
  563. # Usage: Evaluate a return value and print success or failyure as appropriate #
  564. # #
  565. # Purpose: Convenience function to terminate an info message #
  566. # #
  567. # Return values: Not used #
  568. ################################################################################
  569. evaluate_retval()
  570. {
  571. local error_value="${?}"
  572. if [ ${error_value} = 0 ]; then
  573. log_success_msg2
  574. else
  575. log_failure_msg2
  576. fi
  577. }
  578. ################################################################################
  579. # check_signal() #
  580. # Usage: check_signal [ -{signal} | {signal} ] #
  581. # #
  582. # Purpose: Check for a valid signal. This is not defined by any LSB draft, #
  583. # however, it is required to check the signals to determine if the #
  584. # signals chosen are invalid arguments to the other functions. #
  585. # #
  586. # Inputs: Accepts a single string value in the form or -{signal} or {signal} #
  587. # #
  588. # Return values: #
  589. # 0 - Success (signal is valid #
  590. # 1 - Signal is not valid #
  591. ################################################################################
  592. check_signal()
  593. {
  594. local valsig
  595. # Add error handling for invalid signals
  596. valsig="-ALRM -HUP -INT -KILL -PIPE -POLL -PROF -TERM -USR1 -USR2"
  597. valsig="${valsig} -VTALRM -STKFLT -PWR -WINCH -CHLD -URG -TSTP -TTIN"
  598. valsig="${valsig} -TTOU -STOP -CONT -ABRT -FPE -ILL -QUIT -SEGV -TRAP"
  599. valsig="${valsig} -SYS -EMT -BUS -XCPU -XFSZ -0 -1 -2 -3 -4 -5 -6 -8 -9"
  600. valsig="${valsig} -11 -13 -14 -15"
  601. echo "${valsig}" | grep -- " ${1} " > /dev/null
  602. if [ "${?}" -eq "0" ]; then
  603. return 0
  604. else
  605. return 1
  606. fi
  607. }
  608. ################################################################################
  609. # check_sig_type() #
  610. # Usage: check_signal [ -{signal} | {signal} ] #
  611. # #
  612. # Purpose: Check if signal is a program termination signal or a control signal #
  613. # This is not defined by any LSB draft, however, it is required to #
  614. # check the signals to determine if they are intended to end a #
  615. # program or simply to control it. #
  616. # #
  617. # Inputs: Accepts a single string value in the form or -{signal} or {signal} #
  618. # #
  619. # Return values: #
  620. # 0 - Signal is used for program termination #
  621. # 1 - Signal is used for program control #
  622. ################################################################################
  623. check_sig_type()
  624. {
  625. local valsig
  626. # The list of termination signals (limited to generally used items)
  627. valsig="-ALRM -INT -KILL -TERM -PWR -STOP -ABRT -QUIT -2 -3 -6 -9 -14 -15"
  628. echo "${valsig}" | grep -- " ${1} " > /dev/null
  629. if [ "${?}" -eq "0" ]; then
  630. return 0
  631. else
  632. return 1
  633. fi
  634. }
  635. ################################################################################
  636. # wait_for_user() #
  637. # #
  638. # Purpose: Wait for the user to respond if not a headless system #
  639. # #
  640. ################################################################################
  641. wait_for_user()
  642. {
  643. # Wait for the user by default
  644. [ "${HEADLESS=0}" = "0" ] && read ENTER
  645. return 0
  646. }
  647. # End /lib/lsb/init-functions