2 * SPDX-License-Identifier: LGPL-2.1-or-later
4 * Copyright (C) 2014 Ondrej Oprala <ooprala@redhat.com>
5 * Copyright (C) 2014 Karel Zak <kzak@redhat.com>
7 * This file may be distributed under the terms of the
8 * GNU Lesser General Public License.
10 #ifndef UTIL_LINUX_DEBUG_H
11 #define UTIL_LINUX_DEBUG_H
15 * util-linux debug macros
17 * The debug stuff is based on <name>_debug_mask that controls what outputs is
18 * expected. The mask is usually initialized by <NAME>_DEBUG= env.variable
20 * After successful initialization the flag <PREFIX>_DEBUG_INIT is always set
21 * to the mask (this flag is required). The <PREFIX> is usually library API
22 * prefix (e.g. MNT_) or program name (e.g. CFDISK_)
24 * In the code is possible to use
26 * DBG(FOO, ul_debug("this is output for foo"));
28 * where for the FOO has to be defined <PREFIX>_DEBUG_FOO.
30 * It's possible to initialize the mask by comma delimited strings with
31 * subsystem names (e.g. "LIBMOUNT_DEBUG=options,tab"). In this case is
32 * necessary to define mask names array. This functionality is optional.
34 * It's strongly recommended to use UL_* macros to define/declare/use
37 * See disk-utils/cfdisk.c: cfdisk_init_debug() for programs debug
38 * or libmount/src/init.c: mnt_init_debug() for library debug
45 struct ul_debug_maskname
{
50 #define UL_DEBUG_EMPTY_MASKNAMES {{ NULL, 0, NULL }}
51 #define UL_DEBUG_DEFINE_MASKNAMES(m) static const struct ul_debug_maskname m ## _masknames[]
52 #define UL_DEBUG_MASKNAMES(m) m ## _masknames
54 #define UL_DEBUG_MASK(m) m ## _debug_mask
55 #define UL_DEBUG_DEFINE_MASK(m) int UL_DEBUG_MASK(m)
56 #define UL_DEBUG_DECLARE_MASK(m) extern UL_DEBUG_DEFINE_MASK(m)
59 * Internal mask flags (above 0xffffff)
61 #define __UL_DEBUG_FL_NOADDR (1 << 24) /* Don't print object address */
64 /* l - library name, p - flag prefix, m - flag postfix, x - function */
65 #define __UL_DBG(l, p, m, x) \
67 if ((p ## m) & l ## _debug_mask) { \
68 fprintf(stderr, "%d: %s: %8s: ", getpid(), # l, # m); \
73 #define __UL_DBG_CALL(l, p, m, x) \
75 if ((p ## m) & l ## _debug_mask) { \
80 #define __UL_DBG_FLUSH(l, p) \
82 if (l ## _debug_mask && \
83 l ## _debug_mask != p ## INIT) { \
88 #define __UL_INIT_DEBUG_FROM_STRING(lib, pref, mask, str) \
90 if (lib ## _debug_mask & pref ## INIT) \
92 else if (!mask && str) { \
93 lib ## _debug_mask = ul_debug_parse_mask(lib ## _masknames, str); \
95 lib ## _debug_mask = mask; \
96 if (lib ## _debug_mask) { \
97 if (getuid() != geteuid() || getgid() != getegid()) { \
98 lib ## _debug_mask |= __UL_DEBUG_FL_NOADDR; \
99 fprintf(stderr, "%d: %s: don't print memory addresses (SUID executable).\n", getpid(), # lib); \
102 lib ## _debug_mask |= pref ## INIT; \
106 #define __UL_INIT_DEBUG_FROM_ENV(lib, pref, mask, env) \
108 const char *envstr = mask ? NULL : getenv(# env); \
109 __UL_INIT_DEBUG_FROM_STRING(lib, pref, mask, envstr); \
114 static inline void __attribute__ ((__format__ (__printf__
, 1, 2)))
115 ul_debug(const char *mesg
, ...)
119 vfprintf(stderr
, mesg
, ap
);
124 static inline int ul_debug_parse_mask(
125 const struct ul_debug_maskname flagnames
[],
131 /* let's check for a numeric mask first */
132 res
= strtoul(mask
, &ptr
, 0);
134 /* perhaps it's a comma-separated string? */
135 if (ptr
&& *ptr
&& flagnames
&& flagnames
[0].name
) {
136 char *msbuf
, *ms
, *name
;
139 ms
= msbuf
= strdup(mask
);
143 while ((name
= strtok_r(ms
, ",", &ptr
))) {
144 const struct ul_debug_maskname
*d
;
147 for (d
= flagnames
; d
&& d
->name
; d
++) {
148 if (strcmp(name
, d
->name
) == 0) {
153 /* nothing else we can do by OR-ing the mask */
158 } else if (ptr
&& strcmp(ptr
, "all") == 0)
164 static inline void ul_debug_print_masks(
166 const struct ul_debug_maskname flagnames
[])
168 const struct ul_debug_maskname
*d
;
173 fprintf(stderr
, "Available \"%s=<name>[,...]|<mask>\" debug masks:\n",
175 for (d
= flagnames
; d
&& d
->name
; d
++) {
178 fprintf(stderr
, " %-8s [0x%06x] : %s\n",
179 d
->name
, d
->mask
, d
->help
);
183 #endif /* UTIL_LINUX_DEBUG_H */