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