bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek/* Copyright (c) 2001-2018 Dovecot authors, see the included COPYING file */
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek#include "lib.h"
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek#include "dovecot-version.h"
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek#include "array.h"
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek#include "event-filter.h"
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek#include "env-util.h"
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek#include "hostpid.h"
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek#include "ipwd.h"
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek#include "process-title.h"
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek#include "var-expand-private.h"
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek#include "randgen.h"
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek#include <fcntl.h>
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek#include <unistd.h>
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek#include <sys/time.h>
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek/* Mainly for including the full version information in core dumps.
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek NOTE: Don't set this const - otherwise it won't end up in core dumps. */
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozekchar dovecot_build_info[] = DOVECOT_BUILD_INFO;
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozekstatic bool lib_initialized = FALSE;
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozekint dev_null_fd = -1;
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozekstruct atexit_callback {
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek int priority;
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek lib_atexit_callback_t *callback;
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek};
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozekstatic ARRAY(struct atexit_callback) atexit_callbacks = ARRAY_INIT;
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek#undef i_unlink
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozekint i_unlink(const char *path, const char *source_fname,
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek unsigned int source_linenum)
00f3fbb66e882213a78a7ad0a4f9190d0838c830Justin Stephenson{
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek if (unlink(path) < 0) {
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek i_error("unlink(%s) failed: %m (in %s:%u)",
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek path, source_fname, source_linenum);
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek return -1;
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek }
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek return 0;
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek}
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek#undef i_unlink_if_exists
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozekint i_unlink_if_exists(const char *path, const char *source_fname,
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek unsigned int source_linenum)
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek{
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek if (unlink(path) == 0)
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek return 1;
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek else if (errno == ENOENT)
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek return 0;
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek else {
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek i_error("unlink(%s) failed: %m (in %s:%u)",
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek path, source_fname, source_linenum);
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek return -1;
2b84054e2f9fa7301af4dbef4dcbf1cba066ecb3Lukas Slebodnik }
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek}
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozekvoid i_getopt_reset(void)
2b84054e2f9fa7301af4dbef4dcbf1cba066ecb3Lukas Slebodnik{
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek#ifdef __GLIBC__
2b84054e2f9fa7301af4dbef4dcbf1cba066ecb3Lukas Slebodnik /* a) for subcommands allow -options anywhere in command line
2b84054e2f9fa7301af4dbef4dcbf1cba066ecb3Lukas Slebodnik b) this is actually required for the reset to work (glibc bug?) */
2b84054e2f9fa7301af4dbef4dcbf1cba066ecb3Lukas Slebodnik optind = 0;
57c5ea8825c7179fd93382dbcbb07e828e5aec19René Genz#else
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek optind = 1;
2b84054e2f9fa7301af4dbef4dcbf1cba066ecb3Lukas Slebodnik#endif
2b84054e2f9fa7301af4dbef4dcbf1cba066ecb3Lukas Slebodnik}
2b84054e2f9fa7301af4dbef4dcbf1cba066ecb3Lukas Slebodnik
2b84054e2f9fa7301af4dbef4dcbf1cba066ecb3Lukas Slebodnikvoid lib_atexit(lib_atexit_callback_t *callback)
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek{
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek lib_atexit_priority(callback, 0);
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek}
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozekvoid lib_atexit_priority(lib_atexit_callback_t *callback, int priority)
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek{
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek struct atexit_callback *cb;
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek const struct atexit_callback *callbacks;
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek unsigned int i, count;
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek if (!array_is_created(&atexit_callbacks))
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek i_array_init(&atexit_callbacks, 8);
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek else {
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek /* skip if it's already added */
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek callbacks = array_get(&atexit_callbacks, &count);
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek for (i = count; i > 0; i--) {
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek if (callbacks[i-1].callback == callback) {
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek i_assert(callbacks[i-1].priority == priority);
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek return;
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek }
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek }
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek }
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek cb = array_append_space(&atexit_callbacks);
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek cb->priority = priority;
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek cb->callback = callback;
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek}
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozekstatic int atexit_callback_priority_cmp(const struct atexit_callback *cb1,
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek const struct atexit_callback *cb2)
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek{
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek return cb1->priority - cb2->priority;
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek}
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozekvoid lib_atexit_run(void)
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek{
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek const struct atexit_callback *cb;
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek if (array_is_created(&atexit_callbacks)) {
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek array_sort(&atexit_callbacks, atexit_callback_priority_cmp);
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek array_foreach(&atexit_callbacks, cb)
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek (*cb->callback)();
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek array_free(&atexit_callbacks);
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek }
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek}
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozekstatic void lib_open_non_stdio_dev_null(void)
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek{
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek dev_null_fd = open("/dev/null", O_WRONLY);
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek if (dev_null_fd == -1)
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek i_fatal("open(/dev/null) failed: %m");
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek /* Make sure stdin, stdout and stderr fds exist. We especially rely on
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek stderr being available and a lot of code doesn't like fd being 0.
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek We'll open /dev/null as write-only also for stdin, since if any
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek reads are attempted from it we'll want them to fail. */
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek while (dev_null_fd < STDERR_FILENO) {
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek dev_null_fd = dup(dev_null_fd);
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek if (dev_null_fd == -1)
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek i_fatal("dup(/dev/null) failed: %m");
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek }
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek /* close the actual /dev/null fd on exec*(), but keep it in stdio fds */
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek fd_close_on_exec(dev_null_fd, TRUE);
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek}
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozekvoid lib_init(void)
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek{
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek i_assert(!lib_initialized);
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek random_init();
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek data_stack_init();
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek hostpid_init();
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek lib_open_non_stdio_dev_null();
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek lib_event_init();
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek event_filter_init();
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek var_expand_extensions_init();
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek lib_initialized = TRUE;
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek}
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozekbool lib_is_initialized(void)
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek{
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek return lib_initialized;
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek}
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozekvoid lib_deinit(void)
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek{
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek i_assert(lib_initialized);
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek lib_initialized = FALSE;
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek lib_atexit_run();
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek ipwd_deinit();
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek hostpid_deinit();
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek var_expand_extensions_deinit();
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek event_filter_deinit();
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek lib_event_deinit();
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek i_close_fd(&dev_null_fd);
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek data_stack_deinit();
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek env_deinit();
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek failures_deinit();
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek process_title_deinit();
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek random_deinit();
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek}
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek