(root)/
util-linux-2.39/
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 */