]>
Commit | Line | Data |
---|---|---|
db08389d OO |
1 | /* |
2 | * Copyright (C) 2014 Ondrej Oprala <ooprala@redhat.com> | |
ef316a27 | 3 | * Copyright (C) 2014 Karel Zak <kzak@redhat.com> |
db08389d OO |
4 | * |
5 | * This file may be distributed under the terms of the | |
6 | * GNU Lesser General Public License. | |
7 | */ | |
8 | #ifndef UTIL_LINUX_DEBUG_H | |
9 | #define UTIL_LINUX_DEBUG_H | |
10 | ||
ef316a27 KZ |
11 | |
12 | /* | |
13 | * util-linux debug macros | |
14 | * | |
15 | * The debug stuff is based on <name>_debug_mask that controls what outputs is | |
16 | * expected. The mask is usually initialized by <NAME>_DEBUG= env.variable | |
17 | * | |
18 | * After successful initialization the flag <PREFIX>_DEBUG_INIT is always set | |
19 | * to the mask (this flag is required). The <PREFIX> is usually library API | |
20 | * prefix (e.g. MNT_) or program name (e.g. CFDISK_) | |
21 | * | |
22 | * In the code is possible to use | |
23 | * | |
24 | * DBG(FOO, ul_debug("this is output for foo")); | |
25 | * | |
26 | * where for the FOO has to be defined <PREFIX>_DEBUG_FOO. | |
27 | * | |
28 | * It's possible to initialize the mask by comma delimited strings with | |
29 | * subsystem names (e.g. "LIBMOUNT_DEBUG=options,tab"). In this case is | |
30 | * necessary to define mask names array. This functionality is optional. | |
31 | * | |
9e930041 | 32 | * It's strongly recommended to use UL_* macros to define/declare/use |
ef316a27 KZ |
33 | * the debug stuff. |
34 | * | |
35 | * See disk-utils/cfdisk.c: cfdisk_init_debug() for programs debug | |
36 | * or libmount/src/init.c: mnt_init_debug() for library debug | |
37 | * | |
38 | */ | |
39 | ||
db08389d | 40 | #include <stdarg.h> |
14ad2353 | 41 | #include <string.h> |
db08389d | 42 | |
ef316a27 KZ |
43 | struct ul_debug_maskname { |
44 | const char *name; | |
45 | int mask; | |
46 | const char *help; | |
47 | }; | |
48 | #define UL_DEBUG_EMPTY_MASKNAMES {{ NULL, 0, NULL }} | |
49 | #define UL_DEBUG_DEFINE_MASKNAMES(m) static const struct ul_debug_maskname m ## _masknames[] | |
50 | #define UL_DEBUG_MASKNAMES(m) m ## _masknames | |
1e063303 | 51 | |
6d00cfb2 KZ |
52 | #define UL_DEBUG_MASK(m) m ## _debug_mask |
53 | #define UL_DEBUG_DEFINE_MASK(m) int UL_DEBUG_MASK(m) | |
cb3fa847 OO |
54 | #define UL_DEBUG_DECLARE_MASK(m) extern UL_DEBUG_DEFINE_MASK(m) |
55 | ||
6d00cfb2 KZ |
56 | /* |
57 | * Internal mask flags (above 0xffffff) | |
58 | */ | |
59 | #define __UL_DEBUG_FL_NOADDR (1 << 24) /* Don't print object address */ | |
60 | ||
cb3fa847 OO |
61 | |
62 | /* l - library name, p - flag prefix, m - flag postfix, x - function */ | |
e7b49879 | 63 | #define __UL_DBG(l, p, m, x) \ |
d282c88d KZ |
64 | do { \ |
65 | if ((p ## m) & l ## _debug_mask) { \ | |
66 | fprintf(stderr, "%d: %s: %8s: ", getpid(), # l, # m); \ | |
67 | x; \ | |
68 | } \ | |
69 | } while (0) | |
db08389d | 70 | |
e7b49879 KZ |
71 | #define __UL_DBG_CALL(l, p, m, x) \ |
72 | do { \ | |
73 | if ((p ## m) & l ## _debug_mask) { \ | |
74 | x; \ | |
75 | } \ | |
76 | } while (0) | |
77 | ||
78 | #define __UL_DBG_FLUSH(l, p) \ | |
79 | do { \ | |
80 | if (l ## _debug_mask && \ | |
81 | l ## _debug_mask != p ## INIT) { \ | |
82 | fflush(stderr); \ | |
83 | } \ | |
84 | } while (0) | |
85 | ||
a15dca2f | 86 | #define __UL_INIT_DEBUG_FROM_STRING(lib, pref, mask, str) \ |
d282c88d KZ |
87 | do { \ |
88 | if (lib ## _debug_mask & pref ## INIT) \ | |
89 | ; \ | |
a15dca2f KZ |
90 | else if (!mask && str) { \ |
91 | lib ## _debug_mask = ul_debug_parse_mask(lib ## _masknames, str); \ | |
d282c88d KZ |
92 | } else \ |
93 | lib ## _debug_mask = mask; \ | |
6d00cfb2 | 94 | if (lib ## _debug_mask) { \ |
66643f31 | 95 | if (getuid() != geteuid() || getgid() != getegid()) { \ |
6d00cfb2 | 96 | lib ## _debug_mask |= __UL_DEBUG_FL_NOADDR; \ |
7bd0c1ae | 97 | fprintf(stderr, "%d: %s: don't print memory addresses (SUID executable).\n", getpid(), # lib); \ |
66643f31 | 98 | } \ |
6d00cfb2 | 99 | } \ |
d282c88d | 100 | lib ## _debug_mask |= pref ## INIT; \ |
d282c88d | 101 | } while (0) |
db08389d | 102 | |
14ad2353 | 103 | |
a15dca2f KZ |
104 | #define __UL_INIT_DEBUG_FROM_ENV(lib, pref, mask, env) \ |
105 | do { \ | |
106 | const char *envstr = mask ? NULL : getenv(# env); \ | |
107 | __UL_INIT_DEBUG_FROM_STRING(lib, pref, mask, envstr); \ | |
108 | } while (0) | |
109 | ||
110 | ||
111 | ||
db08389d OO |
112 | static inline void __attribute__ ((__format__ (__printf__, 1, 2))) |
113 | ul_debug(const char *mesg, ...) | |
114 | { | |
115 | va_list ap; | |
116 | va_start(ap, mesg); | |
117 | vfprintf(stderr, mesg, ap); | |
118 | va_end(ap); | |
119 | fputc('\n', stderr); | |
120 | } | |
121 | ||
a15dca2f | 122 | static inline int ul_debug_parse_mask( |
ef316a27 KZ |
123 | const struct ul_debug_maskname flagnames[], |
124 | const char *mask) | |
14ad2353 OO |
125 | { |
126 | int res; | |
127 | char *ptr; | |
128 | ||
129 | /* let's check for a numeric mask first */ | |
130 | res = strtoul(mask, &ptr, 0); | |
131 | ||
132 | /* perhaps it's a comma-separated string? */ | |
ef316a27 | 133 | if (ptr && *ptr && flagnames && flagnames[0].name) { |
14ad2353 OO |
134 | char *msbuf, *ms, *name; |
135 | res = 0; | |
136 | ||
137 | ms = msbuf = strdup(mask); | |
138 | if (!ms) | |
139 | return res; | |
140 | ||
141 | while ((name = strtok_r(ms, ",", &ptr))) { | |
ef316a27 | 142 | const struct ul_debug_maskname *d; |
14ad2353 OO |
143 | ms = ptr; |
144 | ||
ef316a27 KZ |
145 | for (d = flagnames; d && d->name; d++) { |
146 | if (strcmp(name, d->name) == 0) { | |
147 | res |= d->mask; | |
14ad2353 OO |
148 | break; |
149 | } | |
14ad2353 OO |
150 | } |
151 | /* nothing else we can do by OR-ing the mask */ | |
152 | if (res == 0xffff) | |
153 | break; | |
154 | } | |
155 | free(msbuf); | |
ef316a27 KZ |
156 | } else if (ptr && strcmp(ptr, "all") == 0) |
157 | res = 0xffff; | |
158 | ||
14ad2353 OO |
159 | return res; |
160 | } | |
ef316a27 KZ |
161 | |
162 | static inline void ul_debug_print_masks( | |
163 | const char *env, | |
164 | const struct ul_debug_maskname flagnames[]) | |
165 | { | |
166 | const struct ul_debug_maskname *d; | |
167 | ||
168 | if (!flagnames) | |
169 | return; | |
170 | ||
171 | fprintf(stderr, "Available \"%s=<name>[,...]|<mask>\" debug masks:\n", | |
172 | env); | |
173 | for (d = flagnames; d && d->name; d++) { | |
174 | if (!d->help) | |
175 | continue; | |
176 | fprintf(stderr, " %-8s [0x%04x] : %s\n", | |
177 | d->name, d->mask, d->help); | |
178 | } | |
179 | } | |
180 | ||
db08389d | 181 | #endif /* UTIL_LINUX_DEBUG_H */ |