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