blob: 0229ab32923639dcfe7ff7901fb7d9dd01feb58d [file] [log] [blame]
bigbiff7b4c7a62015-01-01 19:44:14 -05001/*
2 * Copyright (C) 2014 Ondrej Oprala <ooprala@redhat.com>
3 * Copyright (C) 2014 Karel Zak <kzak@redhat.com>
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
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 *
32 * It's stringly recommended to use UL_* macros to define/declare/use
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
40#include <stdarg.h>
41#include <string.h>
42
43struct 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
51
52#define UL_DEBUG_DEFINE_MASK(m) int m ## _debug_mask
53#define UL_DEBUG_DECLARE_MASK(m) extern UL_DEBUG_DEFINE_MASK(m)
54
55/* p - flag prefix, m - flag postfix */
56#define UL_DEBUG_DEFINE_FLAG(p, m) p ## m
57
58/* l - library name, p - flag prefix, m - flag postfix, x - function */
59#define __UL_DBG(l, p, m, x) \
60 do { \
61 if ((p ## m) & l ## _debug_mask) { \
62 fprintf(stderr, "%d: %s: %8s: ", getpid(), # l, # m); \
63 x; \
64 } \
65 } while (0)
66
67#define __UL_DBG_CALL(l, p, m, x) \
68 do { \
69 if ((p ## m) & l ## _debug_mask) { \
70 x; \
71 } \
72 } while (0)
73
74#define __UL_DBG_FLUSH(l, p) \
75 do { \
76 if (l ## _debug_mask && \
77 l ## _debug_mask != p ## INIT) { \
78 fflush(stderr); \
79 } \
80 } while (0)
81
82
83#define __UL_INIT_DEBUG(lib, pref, mask, env) \
84 do { \
85 if (lib ## _debug_mask & pref ## INIT) \
86 ; \
87 else if (!mask) { \
88 char *str = getenv(# env); \
89 if (str) \
90 lib ## _debug_mask = ul_debug_parse_envmask(lib ## _masknames, str); \
91 } else \
92 lib ## _debug_mask = mask; \
93 lib ## _debug_mask |= pref ## INIT; \
94 } while (0)
95
96
97static inline void __attribute__ ((__format__ (__printf__, 1, 2)))
98ul_debug(const char *mesg, ...)
99{
100 va_list ap;
101 va_start(ap, mesg);
102 vfprintf(stderr, mesg, ap);
103 va_end(ap);
104 fputc('\n', stderr);
105}
106
107static inline void __attribute__ ((__format__ (__printf__, 2, 3)))
108ul_debugobj(void *handler, const char *mesg, ...)
109{
110 va_list ap;
111
112 if (handler)
113 fprintf(stderr, "[%p]: ", handler);
114 va_start(ap, mesg);
115 vfprintf(stderr, mesg, ap);
116 va_end(ap);
117 fputc('\n', stderr);
118}
119
120static inline int ul_debug_parse_envmask(
121 const struct ul_debug_maskname flagnames[],
122 const char *mask)
123{
124 int res;
125 char *ptr;
126
127 /* let's check for a numeric mask first */
128 res = strtoul(mask, &ptr, 0);
129
130 /* perhaps it's a comma-separated string? */
131 if (ptr && *ptr && flagnames && flagnames[0].name) {
132 char *msbuf, *ms, *name;
133 res = 0;
134
135 ms = msbuf = strdup(mask);
136 if (!ms)
137 return res;
138
139 while ((name = strtok_r(ms, ",", &ptr))) {
140 const struct ul_debug_maskname *d;
141 ms = ptr;
142
143 for (d = flagnames; d && d->name; d++) {
144 if (strcmp(name, d->name) == 0) {
145 res |= d->mask;
146 break;
147 }
148 }
149 /* nothing else we can do by OR-ing the mask */
150 if (res == 0xffff)
151 break;
152 }
153 free(msbuf);
154 } else if (ptr && strcmp(ptr, "all") == 0)
155 res = 0xffff;
156
157 return res;
158}
159
160static inline void ul_debug_print_masks(
161 const char *env,
162 const struct ul_debug_maskname flagnames[])
163{
164 const struct ul_debug_maskname *d;
165
166 if (!flagnames)
167 return;
168
169 fprintf(stderr, "Available \"%s=<name>[,...]|<mask>\" debug masks:\n",
170 env);
171 for (d = flagnames; d && d->name; d++) {
172 if (!d->help)
173 continue;
174 fprintf(stderr, " %-8s [0x%04x] : %s\n",
175 d->name, d->mask, d->help);
176 }
177}
178
179#endif /* UTIL_LINUX_DEBUG_H */