]> git.ipfire.org Git - thirdparty/util-linux.git/blob - include/debug.h
Merge branch 'master' of https://github.com/breavyn/util-linux
[thirdparty/util-linux.git] / include / debug.h
1 /*
2 * SPDX-License-Identifier: LGPL-2.1-or-later
3 *
4 * Copyright (C) 2014 Ondrej Oprala <ooprala@redhat.com>
5 * Copyright (C) 2014 Karel Zak <kzak@redhat.com>
6 *
7 * This file may be distributed under the terms of the
8 * GNU Lesser General Public License.
9 */
10 #ifndef UTIL_LINUX_DEBUG_H
11 #define UTIL_LINUX_DEBUG_H
12
13
14 /*
15 * util-linux debug macros
16 *
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
19 *
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_)
23 *
24 * In the code is possible to use
25 *
26 * DBG(FOO, ul_debug("this is output for foo"));
27 *
28 * where for the FOO has to be defined <PREFIX>_DEBUG_FOO.
29 *
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.
33 *
34 * It's strongly recommended to use UL_* macros to define/declare/use
35 * the debug stuff.
36 *
37 * See disk-utils/cfdisk.c: cfdisk_init_debug() for programs debug
38 * or libmount/src/init.c: mnt_init_debug() for library debug
39 *
40 */
41
42 #include <stdarg.h>
43 #include <string.h>
44
45 struct ul_debug_maskname {
46 const char *name;
47 int mask;
48 const char *help;
49 };
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
53
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)
57
58 /*
59 * Internal mask flags (above 0xffffff)
60 */
61 #define __UL_DEBUG_FL_NOADDR (1 << 24) /* Don't print object address */
62
63
64 /* l - library name, p - flag prefix, m - flag postfix, x - function */
65 #define __UL_DBG(l, p, m, x) \
66 do { \
67 if ((p ## m) & l ## _debug_mask) { \
68 fprintf(stderr, "%d: %s: %8s: ", getpid(), # l, # m); \
69 x; \
70 } \
71 } while (0)
72
73 #define __UL_DBG_CALL(l, p, m, x) \
74 do { \
75 if ((p ## m) & l ## _debug_mask) { \
76 x; \
77 } \
78 } while (0)
79
80 #define __UL_DBG_FLUSH(l, p) \
81 do { \
82 if (l ## _debug_mask && \
83 l ## _debug_mask != p ## INIT) { \
84 fflush(stderr); \
85 } \
86 } while (0)
87
88 #define __UL_INIT_DEBUG_FROM_STRING(lib, pref, mask, str) \
89 do { \
90 if (lib ## _debug_mask & pref ## INIT) \
91 ; \
92 else if (!mask && str) { \
93 lib ## _debug_mask = ul_debug_parse_mask(lib ## _masknames, str); \
94 } else \
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); \
100 } \
101 } \
102 lib ## _debug_mask |= pref ## INIT; \
103 } while (0)
104
105
106 #define __UL_INIT_DEBUG_FROM_ENV(lib, pref, mask, env) \
107 do { \
108 const char *envstr = mask ? NULL : getenv(# env); \
109 __UL_INIT_DEBUG_FROM_STRING(lib, pref, mask, envstr); \
110 } while (0)
111
112
113
114 static inline void __attribute__ ((__format__ (__printf__, 1, 2)))
115 ul_debug(const char *mesg, ...)
116 {
117 va_list ap;
118 va_start(ap, mesg);
119 vfprintf(stderr, mesg, ap);
120 va_end(ap);
121 fputc('\n', stderr);
122 }
123
124 static inline int ul_debug_parse_mask(
125 const struct ul_debug_maskname flagnames[],
126 const char *mask)
127 {
128 int res;
129 char *ptr;
130
131 /* let's check for a numeric mask first */
132 res = strtoul(mask, &ptr, 0);
133
134 /* perhaps it's a comma-separated string? */
135 if (ptr && *ptr && flagnames && flagnames[0].name) {
136 char *msbuf, *ms, *name;
137 res = 0;
138
139 ms = msbuf = strdup(mask);
140 if (!ms)
141 return res;
142
143 while ((name = strtok_r(ms, ",", &ptr))) {
144 const struct ul_debug_maskname *d;
145 ms = ptr;
146
147 for (d = flagnames; d && d->name; d++) {
148 if (strcmp(name, d->name) == 0) {
149 res |= d->mask;
150 break;
151 }
152 }
153 /* nothing else we can do by OR-ing the mask */
154 if (res == 0xffff)
155 break;
156 }
157 free(msbuf);
158 } else if (ptr && strcmp(ptr, "all") == 0)
159 res = 0xffff;
160
161 return res;
162 }
163
164 static inline void ul_debug_print_masks(
165 const char *env,
166 const struct ul_debug_maskname flagnames[])
167 {
168 const struct ul_debug_maskname *d;
169
170 if (!flagnames)
171 return;
172
173 fprintf(stderr, "Available \"%s=<name>[,...]|<mask>\" debug masks:\n",
174 env);
175 for (d = flagnames; d && d->name; d++) {
176 if (!d->help)
177 continue;
178 fprintf(stderr, " %-8s [0x%06x] : %s\n",
179 d->name, d->mask, d->help);
180 }
181 }
182
183 #endif /* UTIL_LINUX_DEBUG_H */