]>
Commit | Line | Data |
---|---|---|
db08389d | 1 | /* |
faeb1b64 KZ |
2 | * SPDX-License-Identifier: LGPL-2.1-or-later |
3 | * | |
db08389d | 4 | * Copyright (C) 2014 Ondrej Oprala <ooprala@redhat.com> |
ef316a27 | 5 | * Copyright (C) 2014 Karel Zak <kzak@redhat.com> |
db08389d OO |
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 | ||
ef316a27 KZ |
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 | * | |
9e930041 | 34 | * It's strongly recommended to use UL_* macros to define/declare/use |
ef316a27 KZ |
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 | ||
db08389d | 42 | #include <stdarg.h> |
14ad2353 | 43 | #include <string.h> |
db08389d | 44 | |
ef316a27 KZ |
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 | |
1e063303 | 53 | |
6d00cfb2 KZ |
54 | #define UL_DEBUG_MASK(m) m ## _debug_mask |
55 | #define UL_DEBUG_DEFINE_MASK(m) int UL_DEBUG_MASK(m) | |
cb3fa847 OO |
56 | #define UL_DEBUG_DECLARE_MASK(m) extern UL_DEBUG_DEFINE_MASK(m) |
57 | ||
6d00cfb2 KZ |
58 | /* |
59 | * Internal mask flags (above 0xffffff) | |
60 | */ | |
61 | #define __UL_DEBUG_FL_NOADDR (1 << 24) /* Don't print object address */ | |
62 | ||
cb3fa847 OO |
63 | |
64 | /* l - library name, p - flag prefix, m - flag postfix, x - function */ | |
e7b49879 | 65 | #define __UL_DBG(l, p, m, x) \ |
d282c88d KZ |
66 | do { \ |
67 | if ((p ## m) & l ## _debug_mask) { \ | |
68 | fprintf(stderr, "%d: %s: %8s: ", getpid(), # l, # m); \ | |
69 | x; \ | |
70 | } \ | |
71 | } while (0) | |
db08389d | 72 | |
e7b49879 KZ |
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 | ||
a15dca2f | 88 | #define __UL_INIT_DEBUG_FROM_STRING(lib, pref, mask, str) \ |
d282c88d KZ |
89 | do { \ |
90 | if (lib ## _debug_mask & pref ## INIT) \ | |
91 | ; \ | |
a15dca2f KZ |
92 | else if (!mask && str) { \ |
93 | lib ## _debug_mask = ul_debug_parse_mask(lib ## _masknames, str); \ | |
d282c88d KZ |
94 | } else \ |
95 | lib ## _debug_mask = mask; \ | |
6d00cfb2 | 96 | if (lib ## _debug_mask) { \ |
66643f31 | 97 | if (getuid() != geteuid() || getgid() != getegid()) { \ |
6d00cfb2 | 98 | lib ## _debug_mask |= __UL_DEBUG_FL_NOADDR; \ |
7bd0c1ae | 99 | fprintf(stderr, "%d: %s: don't print memory addresses (SUID executable).\n", getpid(), # lib); \ |
66643f31 | 100 | } \ |
6d00cfb2 | 101 | } \ |
d282c88d | 102 | lib ## _debug_mask |= pref ## INIT; \ |
d282c88d | 103 | } while (0) |
db08389d | 104 | |
14ad2353 | 105 | |
a15dca2f KZ |
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 | ||
db08389d OO |
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 | ||
a15dca2f | 124 | static inline int ul_debug_parse_mask( |
ef316a27 KZ |
125 | const struct ul_debug_maskname flagnames[], |
126 | const char *mask) | |
14ad2353 OO |
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? */ | |
ef316a27 | 135 | if (ptr && *ptr && flagnames && flagnames[0].name) { |
14ad2353 OO |
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))) { | |
ef316a27 | 144 | const struct ul_debug_maskname *d; |
14ad2353 OO |
145 | ms = ptr; |
146 | ||
ef316a27 KZ |
147 | for (d = flagnames; d && d->name; d++) { |
148 | if (strcmp(name, d->name) == 0) { | |
149 | res |= d->mask; | |
14ad2353 OO |
150 | break; |
151 | } | |
14ad2353 OO |
152 | } |
153 | /* nothing else we can do by OR-ing the mask */ | |
154 | if (res == 0xffff) | |
155 | break; | |
156 | } | |
157 | free(msbuf); | |
ef316a27 KZ |
158 | } else if (ptr && strcmp(ptr, "all") == 0) |
159 | res = 0xffff; | |
160 | ||
14ad2353 OO |
161 | return res; |
162 | } | |
ef316a27 KZ |
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; | |
45c1fe0c | 178 | fprintf(stderr, " %-8s [0x%06x] : %s\n", |
ef316a27 KZ |
179 | d->name, d->mask, d->help); |
180 | } | |
181 | } | |
182 | ||
db08389d | 183 | #endif /* UTIL_LINUX_DEBUG_H */ |