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