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