PageRenderTime 48ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 1ms

/dracut-logger.sh

https://gitlab.com/harald-hoyer/dracut
Shell | 442 lines | 197 code | 39 blank | 206 comment | 78 complexity | 44a901f440a89c215eb1261eb17620c9 MD5 | raw file
Possible License(s): GPL-2.0
  1. #!/bin/bash
  2. #
  3. # logging faciality module for dracut both at build- and boot-time
  4. #
  5. # Copyright 2010 Amadeusz Żołnowski <aidecoe@aidecoe.name>
  6. #
  7. # This program is free software; you can redistribute it and/or modify
  8. # it under the terms of the GNU General Public License as published by
  9. # the Free Software Foundation; either version 2 of the License, or
  10. # (at your option) any later version.
  11. #
  12. # This program is distributed in the hope that it will be useful,
  13. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. # GNU General Public License for more details.
  16. #
  17. # You should have received a copy of the GNU General Public License
  18. # along with this program. If not, see <http://www.gnu.org/licenses/>.
  19. __DRACUT_LOGGER__=1
  20. ## @brief Logging facility module for dracut both at build- and boot-time.
  21. #
  22. # @section intro Introduction
  23. #
  24. # The logger takes a bit from Log4j philosophy. There are defined 6 logging
  25. # levels:
  26. # - TRACE (6)
  27. # The TRACE Level designates finer-grained informational events than the
  28. # DEBUG.
  29. # - DEBUG (5)
  30. # The DEBUG Level designates fine-grained informational events that are most
  31. # useful to debug an application.
  32. # - INFO (4)
  33. # The INFO level designates informational messages that highlight the
  34. # progress of the application at coarse-grained level.
  35. # - WARN (3)
  36. # The WARN level designates potentially harmful situations.
  37. # - ERROR (2)
  38. # The ERROR level designates error events that might still allow the
  39. # application to continue running.
  40. # - FATAL (1)
  41. # The FATAL level designates very severe error events that will presumably
  42. # lead the application to abort.
  43. # Descriptions are borrowed from Log4j documentation:
  44. # http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/Level.html
  45. #
  46. # @section usage Usage
  47. #
  48. # First of all you have to start with dlog_init() function which initializes
  49. # required variables. Don't call any other logging function before that one!
  50. # If you're ready with this, you can use following functions which corresponds
  51. # clearly to levels listed in @ref intro Introduction. Here they are:
  52. # - dtrace()
  53. # - ddebug()
  54. # - dinfo()
  55. # - dwarn()
  56. # - derror()
  57. # - dfatal()
  58. # They take all arguments given as a single message to be logged. See dlog()
  59. # function for details how it works. Note that you shouldn't use dlog() by
  60. # yourself. It's wrapped with above functions.
  61. #
  62. # @see dlog_init() dlog()
  63. #
  64. # @section conf Configuration
  65. #
  66. # Logging is controlled by following global variables:
  67. # - @var stdloglvl - logging level to standard error (console output)
  68. # - @var sysloglvl - logging level to syslog (by logger command)
  69. # - @var fileloglvl - logging level to file
  70. # - @var kmsgloglvl - logging level to /dev/kmsg (only for boot-time)
  71. # - @var logfile - log file which is used when @var fileloglvl is higher
  72. # than 0
  73. # and two global variables: @var maxloglvl and @var syslogfacility which <b>must
  74. # not</b> be overwritten. Both are set by dlog_init(). @var maxloglvl holds
  75. # maximum logging level of those three and indicates that dlog_init() was run.
  76. # @var syslogfacility is set either to 'user' (when building initramfs) or
  77. # 'daemon' (when booting).
  78. #
  79. # Logging level set by the variable means that messages from this logging level
  80. # and above (FATAL is the highest) will be shown. Logging levels may be set
  81. # independently for each destination (stderr, syslog, file, kmsg).
  82. #
  83. # @see dlog_init()
  84. ## @brief Initializes dracut Logger.
  85. #
  86. # @retval 1 if something has gone wrong
  87. # @retval 0 on success.
  88. #
  89. # @note This function need to be called before any other from this file.
  90. #
  91. # If any of the variables is not set, this function set it to default:
  92. # - @var stdloglvl = 4 (info)
  93. # - @var sysloglvl = 0 (no logging)
  94. # - @var fileloglvl is set to 4 when @var logfile is set too, otherwise it's
  95. # - @var kmsgloglvl = 0 (no logging)
  96. # set to 0
  97. #
  98. # @warning Function sets global variables @var maxloglvl and @syslogfacility.
  99. # See file doc comment for details.
  100. dlog_init() {
  101. local __oldumask
  102. local ret=0; local errmsg
  103. [ -z "$stdloglvl" ] && stdloglvl=4
  104. [ -z "$sysloglvl" ] && sysloglvl=0
  105. [ -z "$kmsgloglvl" ] && kmsgloglvl=0
  106. # Skip initialization if it's already done.
  107. [ -n "$maxloglvl" ] && return 0
  108. if [ -z "$fileloglvl" ]; then
  109. [ -w "$logfile" ] && fileloglvl=4 || fileloglvl=0
  110. elif (( $fileloglvl > 0 )); then
  111. if [[ $logfile ]]; then
  112. __oldumask=$(umask)
  113. umask 0377
  114. ! [ -e "$logfile" ] && >"$logfile"
  115. umask $__oldumask
  116. if [ -w "$logfile" -a -f "$logfile" ]; then
  117. # Mark new run in the log file
  118. echo >>"$logfile"
  119. if command -v date >/dev/null; then
  120. echo "=== $(date) ===" >>"$logfile"
  121. else
  122. echo "===============================================" >>"$logfile"
  123. fi
  124. echo >>"$logfile"
  125. else
  126. # We cannot log to file, so turn this facility off.
  127. fileloglvl=0
  128. ret=1
  129. errmsg="'$logfile' is not a writable file"
  130. fi
  131. fi
  132. fi
  133. if (( $UID != 0 )); then
  134. kmsgloglvl=0
  135. sysloglvl=0
  136. fi
  137. if (( $sysloglvl > 0 )); then
  138. if [[ -d /run/systemd/journal ]] \
  139. && type -P systemd-cat &>/dev/null \
  140. && systemctl --quiet is-active systemd-journald.socket &>/dev/null \
  141. && { echo "dracut-$DRACUT_VERSION" | systemd-cat -t 'dracut' &>/dev/null; } ; then
  142. readonly _dlogdir="$(mktemp --tmpdir="$TMPDIR/" -d -t dracut-log.XXXXXX)"
  143. readonly _systemdcatfile="$_dlogdir/systemd-cat"
  144. mkfifo "$_systemdcatfile"
  145. readonly _dlogfd=15
  146. systemd-cat -t 'dracut' --level-prefix=true <"$_systemdcatfile" &
  147. exec 15>"$_systemdcatfile"
  148. elif ! [ -S /dev/log -a -w /dev/log ] || ! command -v logger >/dev/null; then
  149. # We cannot log to syslog, so turn this facility off.
  150. kmsgloglvl=$sysloglvl
  151. sysloglvl=0
  152. ret=1
  153. errmsg="No '/dev/log' or 'logger' included for syslog logging"
  154. fi
  155. fi
  156. if (($sysloglvl > 0)) || (($kmsgloglvl > 0 )); then
  157. if [ -n "$dracutbasedir" ]; then
  158. readonly syslogfacility=user
  159. else
  160. readonly syslogfacility=daemon
  161. fi
  162. export syslogfacility
  163. fi
  164. local lvl; local maxloglvl_l=0
  165. for lvl in $stdloglvl $sysloglvl $fileloglvl $kmsgloglvl; do
  166. (( $lvl > $maxloglvl_l )) && maxloglvl_l=$lvl
  167. done
  168. readonly maxloglvl=$maxloglvl_l
  169. export maxloglvl
  170. if (($stdloglvl < 6)) && (($kmsgloglvl < 6)) && (($fileloglvl < 6)) && (($sysloglvl < 6)); then
  171. unset dtrace
  172. dtrace() { :; };
  173. fi
  174. if (($stdloglvl < 5)) && (($kmsgloglvl < 5)) && (($fileloglvl < 5)) && (($sysloglvl < 5)); then
  175. unset ddebug
  176. ddebug() { :; };
  177. fi
  178. if (($stdloglvl < 4)) && (($kmsgloglvl < 4)) && (($fileloglvl < 4)) && (($sysloglvl < 4)); then
  179. unset dinfo
  180. dinfo() { :; };
  181. fi
  182. if (($stdloglvl < 3)) && (($kmsgloglvl < 3)) && (($fileloglvl < 3)) && (($sysloglvl < 3)); then
  183. unset dwarn
  184. dwarn() { :; };
  185. unset dwarning
  186. dwarning() { :; };
  187. fi
  188. if (($stdloglvl < 2)) && (($kmsgloglvl < 2)) && (($fileloglvl < 2)) && (($sysloglvl < 2)); then
  189. unset derror
  190. derror() { :; };
  191. fi
  192. if (($stdloglvl < 1)) && (($kmsgloglvl < 1)) && (($fileloglvl < 1)) && (($sysloglvl < 1)); then
  193. unset dfatal
  194. dfatal() { :; };
  195. fi
  196. [ -n "$errmsg" ] && derror "$errmsg"
  197. return $ret
  198. }
  199. ## @brief Converts numeric logging level to the first letter of level name.
  200. #
  201. # @param lvl Numeric logging level in range from 1 to 6.
  202. # @retval 1 if @a lvl is out of range.
  203. # @retval 0 if @a lvl is correct.
  204. # @result Echoes first letter of level name.
  205. _lvl2char() {
  206. case "$1" in
  207. 1) echo F;;
  208. 2) echo E;;
  209. 3) echo W;;
  210. 4) echo I;;
  211. 5) echo D;;
  212. 6) echo T;;
  213. *) return 1;;
  214. esac
  215. }
  216. ## @brief Converts numeric level to logger priority defined by POSIX.2.
  217. #
  218. # @param lvl Numeric logging level in range from 1 to 6.
  219. # @retval 1 if @a lvl is out of range.
  220. # @retval 0 if @a lvl is correct.
  221. # @result Echoes logger priority.
  222. _lvl2syspri() {
  223. printf $syslogfacility.
  224. case "$1" in
  225. 1) echo crit;;
  226. 2) echo error;;
  227. 3) echo warning;;
  228. 4) echo info;;
  229. 5) echo debug;;
  230. 6) echo debug;;
  231. *) return 1;;
  232. esac
  233. }
  234. ## @brief Converts dracut-logger numeric level to syslog log level
  235. #
  236. # @param lvl Numeric logging level in range from 1 to 6.
  237. # @retval 1 if @a lvl is out of range.
  238. # @retval 0 if @a lvl is correct.
  239. # @result Echoes kernel console numeric log level
  240. #
  241. # Conversion is done as follows:
  242. #
  243. # <tt>
  244. # FATAL(1) -> LOG_EMERG (0)
  245. # none -> LOG_ALERT (1)
  246. # none -> LOG_CRIT (2)
  247. # ERROR(2) -> LOG_ERR (3)
  248. # WARN(3) -> LOG_WARNING (4)
  249. # none -> LOG_NOTICE (5)
  250. # INFO(4) -> LOG_INFO (6)
  251. # DEBUG(5) -> LOG_DEBUG (7)
  252. # TRACE(6) /
  253. # </tt>
  254. #
  255. # @see /usr/include/sys/syslog.h
  256. _dlvl2syslvl() {
  257. local lvl
  258. case "$1" in
  259. 1) lvl=0;;
  260. 2) lvl=3;;
  261. 3) lvl=4;;
  262. 4) lvl=6;;
  263. 5) lvl=7;;
  264. 6) lvl=7;;
  265. *) return 1;;
  266. esac
  267. [ "$syslogfacility" = user ] && echo $((8+$lvl)) || echo $((24+$lvl))
  268. }
  269. ## @brief Prints to stderr and/or writes to file, to syslog and/or /dev/kmsg
  270. # given message with given level (priority).
  271. #
  272. # @param lvl Numeric logging level.
  273. # @param msg Message.
  274. # @retval 0 It's always returned, even if logging failed.
  275. #
  276. # @note This function is not supposed to be called manually. Please use
  277. # dtrace(), ddebug(), or others instead which wrap this one.
  278. #
  279. # This is core logging function which logs given message to standard error, file
  280. # and/or syslog (with POSIX shell command <tt>logger</tt>) and/or to /dev/kmsg.
  281. # The format is following:
  282. #
  283. # <tt>X: some message</tt>
  284. #
  285. # where @c X is the first letter of logging level. See module description for
  286. # details on that.
  287. #
  288. # Message to syslog is sent with tag @c dracut. Priorities are mapped as
  289. # following:
  290. # - @c FATAL to @c crit
  291. # - @c ERROR to @c error
  292. # - @c WARN to @c warning
  293. # - @c INFO to @c info
  294. # - @c DEBUG and @c TRACE both to @c debug
  295. _do_dlog() {
  296. local lvl="$1"; shift
  297. local lvlc=$(_lvl2char "$lvl") || return 0
  298. local msg="$*"
  299. local lmsg="$lvlc: $*"
  300. (( $lvl <= $stdloglvl )) && echo "$msg" >&2
  301. if (( $lvl <= $sysloglvl )); then
  302. if [[ "$_dlogfd" ]]; then
  303. printf -- "<%s>%s\n" "$(($(_dlvl2syslvl $lvl) & 7))" "$msg" >&$_dlogfd
  304. else
  305. logger -t "dracut[$$]" -p $(_lvl2syspri $lvl) -- "$msg"
  306. fi
  307. fi
  308. if (( $lvl <= $fileloglvl )) && [[ -w "$logfile" ]] && [[ -f "$logfile" ]]; then
  309. echo "$lmsg" >>"$logfile"
  310. fi
  311. (( $lvl <= $kmsgloglvl )) && \
  312. echo "<$(_dlvl2syslvl $lvl)>dracut[$$] $msg" >/dev/kmsg
  313. }
  314. ## @brief Internal helper function for _do_dlog()
  315. #
  316. # @param lvl Numeric logging level.
  317. # @param msg Message.
  318. # @retval 0 It's always returned, even if logging failed.
  319. #
  320. # @note This function is not supposed to be called manually. Please use
  321. # dtrace(), ddebug(), or others instead which wrap this one.
  322. #
  323. # This function calls _do_dlog() either with parameter msg, or if
  324. # none is given, it will read standard input and will use every line as
  325. # a message.
  326. #
  327. # This enables:
  328. # dwarn "This is a warning"
  329. # echo "This is a warning" | dwarn
  330. dlog() {
  331. [ -z "$maxloglvl" ] && return 0
  332. (( $1 <= $maxloglvl )) || return 0
  333. if (( $# > 1 )); then
  334. _do_dlog "$@"
  335. else
  336. while read line; do
  337. _do_dlog "$1" "$line"
  338. done
  339. fi
  340. }
  341. ## @brief Logs message at TRACE level (6)
  342. #
  343. # @param msg Message.
  344. # @retval 0 It's always returned, even if logging failed.
  345. dtrace() {
  346. set +x
  347. dlog 6 "$@"
  348. [ -n "$debug" ] && set -x || :
  349. }
  350. ## @brief Logs message at DEBUG level (5)
  351. #
  352. # @param msg Message.
  353. # @retval 0 It's always returned, even if logging failed.
  354. ddebug() {
  355. set +x
  356. dlog 5 "$@"
  357. [ -n "$debug" ] && set -x || :
  358. }
  359. ## @brief Logs message at INFO level (4)
  360. #
  361. # @param msg Message.
  362. # @retval 0 It's always returned, even if logging failed.
  363. dinfo() {
  364. set +x
  365. dlog 4 "$@"
  366. [ -n "$debug" ] && set -x || :
  367. }
  368. ## @brief Logs message at WARN level (3)
  369. #
  370. # @param msg Message.
  371. # @retval 0 It's always returned, even if logging failed.
  372. dwarn() {
  373. set +x
  374. dlog 3 "$@"
  375. [ -n "$debug" ] && set -x || :
  376. }
  377. ## @brief It's an alias to dwarn() function.
  378. #
  379. # @param msg Message.
  380. # @retval 0 It's always returned, even if logging failed.
  381. dwarning() {
  382. set +x
  383. dwarn "$@"
  384. [ -n "$debug" ] && set -x || :
  385. }
  386. ## @brief Logs message at ERROR level (2)
  387. #
  388. # @param msg Message.
  389. # @retval 0 It's always returned, even if logging failed.
  390. derror() {
  391. set +x
  392. dlog 2 "$@"
  393. [ -n "$debug" ] && set -x || :
  394. }
  395. ## @brief Logs message at FATAL level (1)
  396. #
  397. # @param msg Message.
  398. # @retval 0 It's always returned, even if logging failed.
  399. dfatal() {
  400. set +x
  401. dlog 1 "$@"
  402. [ -n "$debug" ] && set -x || :
  403. }