/* Copyright (C) 2019-2020, Dirk Krause SPDX-License-Identifier: BSD-3-Clause */ /* WARNING: This file was generated by the dkct program (see http://dktools.sourceforge.net/ for details). Changes you make here will be lost if dkct is run again! You should modify the original source and run dkct on it. Original source: dk4dmt.ctr */ #ifndef DK4DMT_H_INCLUDED /** Avoid multiple inclusions. */ #define DK4DMT_H_INCLUDED 1 #line 9 "dk4dmt.ctr" /** @file dk4dmt.h Daemon tool functions. The functions in this module can be used to program standing daemons. Three processes are involved in a standing daemon: * master process, originally started, * intermediate process, forked by master, decouples from terminal and * daemon process, forked by intermediate process. When a standing daemon is started by a systemd service unit, the master process must not exit before the daemon process has created the PID file. If you plan to give up root privileges in the child processes (use setgid() and setuid() to change effective user and group), do not use /var/run/program.pid as PID file name, better use /var/run/program/program.pid instead and make sure to set ownership and group on /var/run/program to the unprivileged user and group used by the child process. User and group need write permission to the directory, so the unprivileged child process can remove the PID file when exiting. The general usage structure looks like this: @code #define PROGRAM_NAME "my-new-service" const char program_name[] = { PROGRAM_NAME }; const char pid_file_name[] = { "/run/" PROGRAM_NAME "/" PROGRAM_NAME ".pid" }; dk4dmt_t dmt; ... pid_t cpid; dk4dmt_init(&dmt); if (0 != read_configuration_file()) { dk4dmt_set_program(&dmt, program_name); dk4dmt_set_pidfile(&dmt, pid_file_name); dk4dmt_set_syslog_feature(&dmt, syslog_feature); if (0 != dk4dmt_parent_before_fork(&dmt)) { cpid = fork(); if ((pid_t)0 == cpid) { if (0 != dk4dmt_intermediate_before_fork(&dmt)) { cpid = fork(); if ((pid_t)0 == cpid) { if (0 != dk4dmt_daemon_start(&dmt)) { do_the_service(); } dk4dmt_daemon_end(&dmt); } else { if ((pid_t)(-1) != cpid) { dk4dmt_intermediate_after_fork(&dmt); } else { dk4dmt_intermediate_fork_failed(&dmt); } } } } else { if ((pid_t)(-1) != cpid) { dk4dmt_parent_after_fork(&dmt); } else { dk4dmt_parent_fork_failed(&dmt); } } } } else { dk4dmt_error_config(&dmt); } exval = dk4dmt_get_exit_status(&dmt); exit(exval); @endcode */ #ifndef DK4CONF_H_INCLUDED #if DK4_BUILDING_DKTOOLS4 #include "dk4conf.h" #else #include #endif #endif /** Data collection for daemon. */ typedef struct { char const *prgname; /**< Program name. */ char const *pidfile; /**< PID file name. */ int pfd[2]; /**< Pipe file descriptors. */ int logstderr; /**< Flag: Logging to stderr allowed. */ int slf; /**< Syslog feature. */ int exv; /**< Exit status code to return. */ } dk4dmt_t; #ifdef __cplusplus extern "C" { #endif /** Initialize daemon tool structure. @param pdmt Daemon tool structure to initialize. */ void dk4dmt_init(dk4dmt_t *pdmt); /** Set program name for daemon tool structure. The function does not create a copy of the program name, it keeps the original pointer in the structure. So the progname buffer must exist and contain data as long as the structure is used. @param pdmt Daemon tool structure to set up. @param progname Program name. */ void dk4dmt_set_program(dk4dmt_t *pdmt, const char *progname); /** Set PID file name for daemon tool structure. The function does not create a copy of the file name, it keeps the original pointer in the structure. So the pidfile buffer must exist and contain data as long as the structure is used. @param pdmt Daemon tool structure to set up. @param pidfile PID file name. */ void dk4dmt_set_pidfile(dk4dmt_t *pdmt, const char *pidfile); /** Enable or disable logging to stderr for daemon tool structure. @param pdmt Daemon tool structure to set up. @param flag Allow or deny logging to stderr. */ void dk4dmt_set_log_stderr(dk4dmt_t *pdmt, int flag); /** Set syslog feature for daemon tool structure. @param pdmt Daemon tool structure to set up. @param feat Syslog feature to use. */ void dk4dmt_set_syslog_feature(dk4dmt_t *pdmt, int feat); /** Process initialization before first fork attempt. Open pipe for communication from daemon to parent. @param pdmt Daemon tool structure to use. @return 1 on success, 0 on error. */ int dk4dmt_parent_before_fork(dk4dmt_t *pdmt); /** Wait for startup completion notification in parent process. Close write head, read exit status, close read head. @param pdmt Daemon tool structure to use. */ void dk4dmt_parent_after_fork(dk4dmt_t *pdmt); /** React on failed fork attempt in parent process. Close both pipe heads. @param pdmt Daemon tool structure to use. */ void dk4dmt_parent_fork_failed(dk4dmt_t *pdmt); /** Prepare for second fork attempt in intermediate process. Close read head. On error write exit status code and close write pipe head. @param pdmt Daemon tool structure to use. @return 1 on success, 0 on error. */ int dk4dmt_intermediate_before_fork(dk4dmt_t *pdmt); /** Clean up in intermediate process after forking the daemon. Close write pipe head. @param pdmt Daemon tool structure to use. */ void dk4dmt_intermediate_after_fork(dk4dmt_t *pdmt); /** React on failed fork attempt in intermediate process. Write exit status code and close write pipe head. @param pdmt Daemon tool structure to use. */ void dk4dmt_intermediate_fork_failed(dk4dmt_t *pdmt); /** Create PID file and notify main process to exit. Write exit status and close write pipe head. @param pdmt Daemon tool structure to use. */ int dk4dmt_daemon_start(dk4dmt_t *pdmt); /** Clean up daemon structure before exiting daemon process (remove PID file). @param pdmt Daemon tool structure to use. */ void dk4dmt_daemon_end(dk4dmt_t *pdmt); /** Set exit code in daemon structure for failed system function. @param pdmt Daemon tool structure to use. */ void dk4dmt_error_sysfct(dk4dmt_t *pdmt); /** Set exit code in daemon structure for failed signal process mask. @param pdmt Daemon tool structure to use. */ void dk4dmt_error_sigprocmask(dk4dmt_t *pdmt); /** Set exit code in daemon structure to indicate missing signal functionality. @param pdmt Daemon tool structure to use. */ void dk4dmt_error_no_signal_function(dk4dmt_t *pdmt); /** Set exit code in daemon structure to indicate PID file exists. @param pdmt Daemon tool structure to use. */ void dk4dmt_error_pid_file_exists(dk4dmt_t *pdmt); /** Set exit code in daemon structure to indicate PID file not configured. @param pdmt Daemon tool structure to use. */ void dk4dmt_error_pid_file_name_missing(dk4dmt_t *pdmt); /** Set exit code in daemon structure to indicate write PID file failed. @param pdmt Daemon tool structure to use. */ void dk4dmt_error_write_pid_file(dk4dmt_t *pdmt); /** Set exit code in daemon structure to indicate pipe was not opened (bug). @param pdmt Daemon tool structure to use. */ void dk4dmt_error_pipe_not_open(dk4dmt_t *pdmt); /** Set exit code in daemon structure to indicate reading from pipe failed. @param pdmt Daemon tool structure to use. */ void dk4dmt_error_pipe_read_failed(dk4dmt_t *pdmt); /** Set exit code in daemon structure to indicate fork failed. @param pdmt Daemon tool structure to use. */ void dk4dmt_error_fork_failed(dk4dmt_t *pdmt); /** Set exit code in daemon structure to indicate setsid failed. @param pdmt Daemon tool structure to use. */ void dk4dmt_error_setsid(dk4dmt_t *pdmt); /** Set exit code in daemon structure to indicate dup2 failed. @param pdmt Daemon tool structure to use. */ void dk4dmt_error_dup2_failed(dk4dmt_t *pdmt); /** Set exit code in daemon structure to indicate reading /dev/null failed. @param pdmt Daemon tool structure to use. */ void dk4dmt_error_failed_read_dev_null(dk4dmt_t *pdmt); /** Set exit code in daemon structure to indicate writing /dev/null failed. @param pdmt Daemon tool structure to use. */ void dk4dmt_error_failed_write_dev_null(dk4dmt_t *pdmt); /** Set exit code in daemon structure to indicate chdir to / failed. @param pdmt Daemon tool structure to use. */ void dk4dmt_error_failed_chdir_root(dk4dmt_t *pdmt); /** Set exit code in daemon structure for failed signal set cleanup. @param pdmt Daemon tool structure to use. */ void dk4dmt_error_sigemptyset(dk4dmt_t *pdmt); /** Set exit code in daemon structure for unusable configuration. @param pdmt Daemon tool structure to use. */ void dk4dmt_error_config(dk4dmt_t *pdmt); /** Set exit code in daemon structure to indicate wrong call arguments. @param pdmt Daemon tool structure to use. */ void dk4dmt_error_usage(dk4dmt_t *pdmt); /** Indicate success. @param pdmt Daemon tool structure to use. */ void dk4dmt_success(dk4dmt_t *pdmt); /** Retrieve exit status code. @param pdmt Daemon tool structure to use. @return Exit status code to return. */ int dk4dmt_get_exit_status(dk4dmt_t *pdmt); #ifdef __cplusplus } #endif #endif