/usr/include/gdnsd/dmn.h is in gdnsd-dev 2.2.0-1ubuntu1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
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 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 | /* Copyright © 2012 Brandon L Black <blblack@gmail.com>
*
* This file is part of gdnsd.
*
* gdnsd is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* gdnsd is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with gdnsd. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef DMN_H
#define DMN_H
#include <stdbool.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <stdarg.h>
#include <syslog.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#pragma GCC visibility push(default)
#define PRAG_(x) _Pragma(#x)
// gcc/clang features
#if defined __GNUC__ && (__GNUC__ < 3 || (__GNUC__ == 3 && __GNUC_MINOR__ < 4))
# error Your GCC is way too old (< 3.4)...
#endif
#if defined __clang__ || defined __GNUC__
# define DMN_F_PRINTF(X,Y) __attribute__((__format__(__printf__, X, Y)))
# define DMN_F_NONNULLX(...) __attribute__((__nonnull__(__VA_ARGS__)))
# define DMN_F_NONNULL __attribute__((__nonnull__))
# define DMN_F_NORETURN __attribute__((__noreturn__))
#endif
#if defined __clang__
# if __has_builtin(__builtin_unreachable)
# define DMN_HAVE_UNREACH_BUILTIN 1
# endif
# if __has_attribute(cold)
# define DMN_F_COLD __attribute__((__cold__))
# endif
# define DMN_DIAG_PUSH_IGNORED(x) _Pragma("clang diagnostic push"); \
PRAG_(clang diagnostic ignored x)
# define DMN_DIAG_POP _Pragma("clang diagnostic pop")
#elif defined __GNUC__
# if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)
# define DMN_F_COLD __attribute__((__cold__))
# endif
# if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)
# define DMN_HAVE_UNREACH_BUILTIN 1
# endif
# if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
# define DMN_DIAG_PUSH_IGNORED(x) _Pragma("GCC diagnostic push"); \
PRAG_(GCC diagnostic ignored x)
# define DMN_DIAG_POP _Pragma("GCC diagnostic pop")
# endif
#endif
#ifndef DMN_F_PRINTF
# define DMN_F_PRINTF(X,Y)
#endif
#ifndef DMN_F_NONNULLX
# define DMN_F_NONNULLX(...)
#endif
#ifndef DMN_F_NONNULL
# define DMN_F_NONNULL
#endif
#ifndef DMN_F_NORETURN
# define DMN_F_NORETURN
#endif
#ifndef DMN_F_COLD
# define DMN_F_COLD
#endif
#ifndef DMN_DIAG_PUSH_IGNORED
# define DMN_DIAG_PUSH_IGNORED(_x)
#endif
#ifndef DMN_DIAG_POP
# define DMN_DIAG_POP
#endif
/***
**** Daemonization interfaces
***/
// the pcall stuff isn't very well designed yet :P
typedef void(*dmn_func_vv_t)(void);
DMN_F_NONNULL
unsigned dmn_add_pcall(dmn_func_vv_t func);
void dmn_pcall(unsigned id);
// dmn_init1() *must* be called before *any* other libdmn function!
// debug: if false, all potential messages from dmn_log_debug() and
// dmn_log_devdebug() will be suppressed.
// foreground: if true, we won't actually do fork/setsid-type daemonization,
// but will still go through all the other motions.
// use_syslog: whether to log to syslog at all (false for test/cmdline stuff)
// name: the name of your daemon/program. Will be used for log outputs
// and pidfile naming.
// Immediately after init1(), only the logging APIs (dmn_log_*, dmn_logf_*
// dmn_fmtbuf_*) are available.
DMN_F_NONNULL
void dmn_init1(bool debug, bool foreground, bool use_syslog, const char* name);
// dmn_init2() must be called after dmn_init1() and before dmn_init3().
// pid_dir: This is the application-specific(!)
// directory within which the pidfile exists (or will be created). This
// should not be, for example, "/run" or "/var/run", it should be something
// like "/run/somedaemond" or "/var/run/somedaemond".
// Must be an absolute path (begins with /). If NULL, none of the pidfile
// -related calls (_stop, _status, _signal) will do anything useful, and
// _acquire_pidfile() will be a no-op).
// Immediately after dmn_init2() the basic daemon-control APIs
// (dmn_status(), dmn_stop(), and dmn_signal()) are now
// available for use (in addition to the log APIs allowed
// by init1()).
void dmn_init2(const char* pid_dir);
// dmn_init3 must be called after dmn_init2() and before dmn_fork().
// username: optional - if set, the daemon will drop privileges
// to the uid/gid of this user during dmn_secure() later. If
// the daemon was not started as root, this option is ignored.
// restart: if true, much later in dmn_acquire_pidfile() this
// daemon will try to kill any conflicting instance of itself
// (same pidfile) before acquiring the pidfile.
void dmn_init3(const char* username, const bool restart);
// In !foreground cases, does the whole 9 yards of proper daemonization,
// with execution continuing in the final daemonized child. The original
// process that invoked dmn_fork lingers in a private subroutine inside
// libdmn as a "helper" until dmn_finish(), thus keeping the terminal
// or manager process tied up until it can return a correct exit value,
// and helping with any pcall operations as root post-privdrop.
// In "foreground" cases using privdrop *and* pcalls, this will not do
// any real daemonization, but will fork a helper process to retain root
// for pcall execution later, which terminates at dmn_finish().
// In foreground cases with no privdrop (or no pcalls), does basically nothing.
void dmn_fork(void);
// If we're executing as the root user, this will privdrop
// us as indicated by the earlier username option to init3.
// If pid_dir doesn't exist and/or isn't owned by username (if defined),
// and we're running as root, the pid_dir will be created and/or chowned
// as necessary/possible before the loss of privilege to do so here in
// this function.
// Unless "weak" is set, dmn_secure() may take additional restrictive measures
// regardless of whether we were executing as root or not.
void dmn_secure(const bool weak);
// If the restart parameter was set in init3, this function will first
// check for a running daemon via the pidfile lock mechanism and terminate it.
// Regardless, it will then acquire a proper pidfile lock (or die trying),
// if pid_dir was defined back in init3 (otherwise this call is a no-op).
// When this returns without dying, the current process is now the official
// runtime instance of this daemon for e.g. dmn_status().
void dmn_acquire_pidfile(void);
// Finish the daemon startup procedure by signalling the helper process
// (if any) to exit with status 0. If your daemon doesn't make it
// far enough to call this, the helper will exit non-zero to indicate
// failure to the shell/manager/etc.
void dmn_finish(void);
// retval == 0 means daemon is not running
// retval != 0 means daemon is still running (and the pid is the retval)
pid_t dmn_status(void);
// This can delay up to 15s while waiting for the old daemon to stop.
// retval == 0 means daemon was not running, or was successfully killed.
// retval != 0 means daemon is still running (and the pid is the retval)
pid_t dmn_stop(void);
// Send an arbitrary signal to the running daemon, retval zero indicates
// success, non-zero indicates failure.
int dmn_signal(int sig);
/***
**** Logging interfaces
***/
// This is used "internally" by dmn_log_debug(), but gdnsd also
// uses this for the special case of plugin_extmon's helper process.
bool dmn_get_debug(void);
// again, special for plugin_extmon...
bool dmn_get_syslog_alive(void);
// This is a syslog()-like interface that will log
// to stderr and/or syslog as appropriate
// depending on daemon lifecycle, and is thread-safe.
DMN_F_COLD DMN_F_NONNULLX(2) DMN_F_PRINTF(2,3)
void dmn_logger(int level, const char* fmt, ...);
// As above, but with a va_list interface to make it
// easier to integrate with your own custom wrapper code.
DMN_F_COLD DMN_F_NONNULLX(2) DMN_F_PRINTF(2,0)
void dmn_loggerv(int level, const char* fmt, va_list ap);
// If running under systemd, send it a message over the
// notification socket. If !optional and the message
// cannot be sent, a fatal error will be thrown.
DMN_F_NONNULL
void dmn_sd_notify(const char* notify_msg, const bool optional);
// The intended simple API for logging with 5 separate
// function-call-like interfaces with different levels.
// The _fatal variant exits after emitting the logged statement,
// and the _debug variant becomes a no-op when your application
// is built with -DNDEBUG.
#define dmn_log_info(...) dmn_logger(LOG_INFO,__VA_ARGS__)
#define dmn_log_warn(...) dmn_logger(LOG_WARNING,__VA_ARGS__)
#define dmn_log_err(...) dmn_logger(LOG_ERR,__VA_ARGS__)
// log_debug() messages will only be emitted if the runtime debug flag is set
#define dmn_log_debug(...) do {\
if(dmn_get_debug())\
dmn_logger(LOG_DEBUG,__VA_ARGS__);\
} while(0)
// DMN_NO_FATAL_COVERAGE is to allow coverage testing to skip
// over fatal conditions. If your tests don't cover those
// for pragmatic reasons, this considerably reduces line noise.
// Note that this is only going to work if your tests *never*
// exercise a fatal case; it will probably cause random
// bugs leading to test failures otherwise.
// DMN_COVERTEST_EXIT uses exit(57) rather than _exit(42) on fatals,
// because exit() is needed to gather coverage data.
#ifdef DMN_NO_FATAL_COVERAGE
# define dmn_log_fatal(...) ((void)(0))
#elif defined DMN_COVERTEST_EXIT
# define dmn_log_fatal(...) do {\
dmn_logger(LOG_CRIT,__VA_ARGS__);\
exit(57);\
} while(0)
#else
# define dmn_log_fatal(...) do {\
dmn_logger(LOG_CRIT,__VA_ARGS__);\
_exit(42);\
} while(0)
#endif
// DMN_NO_UNREACH_BUILTIN is to work around gcov coverage testing, which
// flags un-taken branches for all of the __builtin_unreachable()
// dmn_log_devdebug() is suppressed at the preprocessor level if -DNDEBUG
// is set; use this in performance-critical areas (to avoid the runtime
// check of the debug flag) or for spammy messages that only developers need
#ifdef NDEBUG
# if defined(DMN_HAVE_UNREACH_BUILTIN) && !defined(DMN_NO_UNREACH_BUILTIN)
# define dmn_assert(expr) do { if (!(expr)) __builtin_unreachable(); } while (0)
# else
# define dmn_assert(expr) ((void)(0))
# endif
# define dmn_log_devdebug(...) ((void)(0))
#else
# define dmn_assert(expr) do {\
if(!(expr)) {\
dmn_logger(LOG_CRIT,"Assertion '%s' failed in %s() at %s:%u, backtrace:%s",\
#expr, __func__, __FILE__, __LINE__, dmn_logf_bt());\
abort();\
}\
} while(0)
# define dmn_log_devdebug(...) do {\
if(dmn_get_debug())\
dmn_logger(LOG_DEBUG,__VA_ARGS__);\
} while(0)
#endif // NDEBUG
//
// fmtbuf_alloc() allows you to make custom string-formatters
// for use with the above logging functions. You use this
// function to allocate buffer space within your function,
// and then return a pointer to the space. All buffer space
// comes from a shared per-pthread pool, and is reset
// when you call a logging function above.
// Your custom formatter can use only log_fatal() to signal
// bugs, but probably should avoid using custom formatters itself.
// Example:
//
// const char* my_int_formatter(int foo) {
// char* buf = dmn_fmtbuf_alloc(22);
// if(snprintf(buf, 22, "%i", foo) >= 22)
// log_fatal("BUG: Integer formatting did not fit buffer space!");
// return buf;
// }
//
// dmn_log_warn("The integer had value %s!", my_int_formatter(someint));
//
// if size==0, the retval will be NULL
char* dmn_fmtbuf_alloc(const unsigned size);
// Reset (free allocations within) the format buffer. Do not use this
// with the normal log functions. If you use the fmtbuf-based formatters
// *outside* of a dmn log function, use this afterwards to reclaim the
// space.
void dmn_fmtbuf_reset(void);
// Use this as a thread-safe strerror() within the arguments
// of the above logging functions. This is built on dmn_fmtbuf_alloc()
// above and takes care of the difference between the GNU
// and POSIX strerror_r() variants.
const char* dmn_logf_strerror(const int errnum);
#define dmn_logf_errno() dmn_logf_strerror(errno)
// Adds a strack trace to the log message, iff built w/ libunwind
const char* dmn_logf_bt(void);
/******** network utility stuff ***********/
/* Socket union type */
// note anonymous union here, which gcc has supported
// forever, and is now becoming standard in C11
typedef struct {
union {
struct sockaddr_in6 sin6;
struct sockaddr_in sin;
struct sockaddr sa;
};
socklen_t len;
} dmn_anysin_t;
// This is a maximum for the value of dmn_anysin_t.len
#define DMN_ANYSIN_MAXLEN sizeof(struct sockaddr_in6)
// max length of ASCII numeric ipv6 addr, with room for trailing NUL
#ifndef INET6_ADDRSTRLEN
# define INET6_ADDRSTRLEN 46
#endif
// maximum addr:port ASCII representation from dmn_anysin2str below
// maximal form is "[...IPv6...]:12345\0"
#define DMN_ANYSIN_MAXSTR (1 + ((INET6_ADDRSTRLEN) - 1) + 1 + 1 + 5 + 1)
// transforms addr_txt + port_txt -> result using getaddrinfo(), setting result->len
// if "numeric_only" is true:
// input text fields must be numeric, not hostnames or port names.
// if false, hostnames and port names are possible, which may result
// in the libc doing DNS lookups and such on your behalf.
// caller must allocate result to sizeof(dmn_anysin_t)
// port_txt can be NULL, in which case the proto-specific port field will be zero
// retval is retval from getaddrinfo() itself (if non-zero, error occurred and
// string representation is available from gai_strerror()).
// result is unaffected if an error occurs.
DMN_F_NONNULLX(1,3)
int dmn_anysin_getaddrinfo(const char* addr_txt, const char* port_txt, dmn_anysin_t* result, bool numeric_only);
// As above, but for parsing the address and port from a single string of the form addr:port,
// where :port is optional, and addr may be surround by [] (to help with ipv6 [::1]:53 issues).
// Port defaults to unsigned arg "def_port" if not specified in the input string.
DMN_F_NONNULLX(1,3)
int dmn_anysin_fromstr(const char* addr_port_text, const unsigned def_port, dmn_anysin_t* result, bool numeric_only);
// Check if the sockaddr is the V4 or V6 ANY-address (0.0.0.0, or ::)
DMN_F_NONNULL
bool dmn_anysin_is_anyaddr(const dmn_anysin_t* asin);
// convert "asin" to numeric ASCII of the form "ipv4:port" or "[ipv6]:port"
// NULL input results in the string "(null)"
// note that buf *must* be pre-allocated to at least DMN_ANYSIN_MAXSTR bytes!
// return value is from getaddrinfo() (0 for success, otherwise pass to gai_strerror())
DMN_F_NONNULLX(2)
int dmn_anysin2str(const dmn_anysin_t* asin, char* buf);
// convert just the address portion to ASCII in "buf"
// NULL input results in the string "(null)"
// note that buf *must* be pre-allocated to at least INET6_ADDRSTRLEN bytes!
// return value is from getaddrinfo() (0 for success, otherwise pass to gai_strerror())
DMN_F_NONNULLX(2)
int dmn_anysin2str_noport(const dmn_anysin_t* asin, char* buf);
// Log-formatters for dmn_anysin_t + dmn_log_*(), which use the above...
const char* dmn_logf_anysin(const dmn_anysin_t* asin);
const char* dmn_logf_anysin_noport(const dmn_anysin_t* asin);
#pragma GCC visibility pop
#endif // DMN_H
|