1 /* 2 Copyright (C) 2019-2021, Dirk Krause 3 SPDX-License-Identifier: BSD-3-Clause 4 */ 5 6 /* 7 WARNING: This file was generated by the dkct program (see 8 http://dktools.sourceforge.net/ for details). 9 Changes you make here will be lost if dkct is run again! 10 You should modify the original source and run dkct on it. 11 Original source: dk4dmt.ctr 12 */ 13 14 #ifndef DK4DMT_H_INCLUDED 15 /** Avoid multiple inclusions. */ 16 #define DK4DMT_H_INCLUDED 1 17 18 19 /** @file dk4dmt.h Daemon tool functions. 20 21 The functions in this module can be used to program standing daemons. 22 Three processes are involved in a standing daemon: 23 24 * master process, originally started, 25 * intermediate process, forked by master, decouples from terminal and 26 * daemon process, forked by intermediate process. 27 28 When a standing daemon is started by a systemd service unit, the master 29 process must not exit before the daemon process has created the PID file. 30 31 If you plan to give up root privileges in the child processes 32 (use setgid() and setuid() to change effective user and group), 33 do not use /var/run/<i>program</i>.pid as PID file name, better 34 use /var/run/<i>program</i>/<i>program</i>.pid instead and make 35 sure to set ownership and group on /var/run/<i>program</i> 36 to the unprivileged user and group used by the child process. 37 User and group need write permission to the directory, so the unprivileged 38 child process can remove the PID file when exiting. 39 40 The general usage structure looks like this: 41 42 @code 43 #define PROGRAM_NAME "my-new-service" 44 const char program_name[] = { 45 PROGRAM_NAME 46 }; 47 const char pid_file_name[] = { 48 "/run/" PROGRAM_NAME "/" PROGRAM_NAME ".pid" 49 }; 50 dk4dmt_t dmt; 51 52 ... 53 54 pid_t cpid; 55 dk4dmt_init(&dmt); 56 if (0 != read_configuration_file()) { 57 dk4dmt_set_program(&dmt, program_name); 58 dk4dmt_set_pidfile(&dmt, pid_file_name); 59 dk4dmt_set_syslog_feature(&dmt, syslog_feature); 60 if (0 != dk4dmt_parent_before_fork(&dmt)) { 61 cpid = fork(); 62 if ((pid_t)0 == cpid) { 63 if (0 != dk4dmt_intermediate_before_fork(&dmt)) { 64 cpid = fork(); 65 if ((pid_t)0 == cpid) { 66 if (0 != dk4dmt_daemon_start(&dmt)) { 67 do_the_service(); 68 } 69 dk4dmt_daemon_end(&dmt); 70 } 71 else { 72 if ((pid_t)(-1) != cpid) { 73 dk4dmt_intermediate_after_fork(&dmt); 74 } 75 else { 76 dk4dmt_intermediate_fork_failed(&dmt); 77 } 78 } 79 } 80 } 81 else { 82 if ((pid_t)(-1) != cpid) { 83 dk4dmt_parent_after_fork(&dmt); 84 } 85 else { 86 dk4dmt_parent_fork_failed(&dmt); 87 } 88 } 89 } 90 } 91 else { 92 dk4dmt_error_config(&dmt); 93 } 94 exval = dk4dmt_get_exit_status(&dmt); 95 exit(exval); 96 @endcode 97 98 */ 99 100 #ifndef DK4CONF_H_INCLUDED 101 #if DK4_BUILDING_DKTOOLS4 102 #include "dk4conf.h" 103 #else 104 #include <dktools-4/dk4conf.h> 105 #endif 106 #endif 107 108 109 /** Data collection for daemon. 110 */ 111 typedef struct { 112 char const *prgname; /**< Program name. */ 113 char const *pidfile; /**< PID file name. */ 114 int pfd[2]; /**< Pipe file descriptors. */ 115 int logstderr; /**< Flag: Logging to stderr allowed. */ 116 int slf; /**< Syslog feature. */ 117 int exv; /**< Exit status code to return. */ 118 } dk4dmt_t; 119 120 121 122 #ifdef __cplusplus 123 extern "C" { 124 #endif 125 126 /** Initialize daemon tool structure. 127 @param pdmt Daemon tool structure to initialize. 128 */ 129 130 void 131 dk4dmt_init(dk4dmt_t *pdmt); 132 133 134 /** Set program name for daemon tool structure. 135 The function does not create a copy of the program name, 136 it keeps the original pointer in the structure. 137 So the progname buffer must exist and contain data as long as 138 the structure is used. 139 @param pdmt Daemon tool structure to set up. 140 @param progname Program name. 141 */ 142 143 void 144 dk4dmt_set_program(dk4dmt_t *pdmt, const char *progname); 145 146 147 /** Set PID file name for daemon tool structure. 148 The function does not create a copy of the file name, it keeps the original 149 pointer in the structure. 150 So the pidfile buffer must exist and contain data as long as 151 the structure is used. 152 @param pdmt Daemon tool structure to set up. 153 @param pidfile PID file name. 154 */ 155 156 void 157 dk4dmt_set_pidfile(dk4dmt_t *pdmt, const char *pidfile); 158 159 160 /** Enable or disable logging to stderr for daemon tool structure. 161 @param pdmt Daemon tool structure to set up. 162 @param flag Allow or deny logging to stderr. 163 */ 164 165 void 166 dk4dmt_set_log_stderr(dk4dmt_t *pdmt, int flag); 167 168 169 /** Set syslog feature for daemon tool structure. 170 @param pdmt Daemon tool structure to set up. 171 @param feat Syslog feature to use. 172 */ 173 174 void 175 dk4dmt_set_syslog_feature(dk4dmt_t *pdmt, int feat); 176 177 178 /** Process initialization before first fork attempt. 179 Open pipe for communication from daemon to parent. 180 @param pdmt Daemon tool structure to use. 181 @return 1 on success, 0 on error. 182 */ 183 184 int 185 dk4dmt_parent_before_fork(dk4dmt_t *pdmt); 186 187 188 /** Wait for startup completion notification in parent process. 189 Close write head, read exit status, close read head. 190 @param pdmt Daemon tool structure to use. 191 */ 192 193 void 194 dk4dmt_parent_after_fork(dk4dmt_t *pdmt); 195 196 197 /** React on failed fork attempt in parent process. 198 Close both pipe heads. 199 @param pdmt Daemon tool structure to use. 200 */ 201 202 void 203 dk4dmt_parent_fork_failed(dk4dmt_t *pdmt); 204 205 206 /** Prepare for second fork attempt in intermediate process. 207 Close read head. 208 On error write exit status code and close write pipe head. 209 @param pdmt Daemon tool structure to use. 210 @return 1 on success, 0 on error. 211 */ 212 213 int 214 dk4dmt_intermediate_before_fork(dk4dmt_t *pdmt); 215 216 217 /** Clean up in intermediate process after forking the daemon. 218 Close write pipe head. 219 @param pdmt Daemon tool structure to use. 220 */ 221 222 void 223 dk4dmt_intermediate_after_fork(dk4dmt_t *pdmt); 224 225 226 /** React on failed fork attempt in intermediate process. 227 Write exit status code and close write pipe head. 228 @param pdmt Daemon tool structure to use. 229 */ 230 231 void 232 dk4dmt_intermediate_fork_failed(dk4dmt_t *pdmt); 233 234 235 /** Create PID file and notify main process to exit. 236 Write exit status and close write pipe head. 237 @param pdmt Daemon tool structure to use. 238 */ 239 240 int 241 dk4dmt_daemon_start(dk4dmt_t *pdmt); 242 243 244 /** Clean up daemon structure before exiting daemon process (remove PID file). 245 @param pdmt Daemon tool structure to use. 246 */ 247 248 void 249 dk4dmt_daemon_end(dk4dmt_t *pdmt); 250 251 252 /** Set exit code in daemon structure for failed system function. 253 @param pdmt Daemon tool structure to use. 254 */ 255 256 void 257 dk4dmt_error_sysfct(dk4dmt_t *pdmt); 258 259 260 /** Set exit code in daemon structure for failed signal process mask. 261 @param pdmt Daemon tool structure to use. 262 */ 263 264 void 265 dk4dmt_error_sigprocmask(dk4dmt_t *pdmt); 266 267 268 /** Set exit code in daemon structure to indicate missing signal functionality. 269 @param pdmt Daemon tool structure to use. 270 */ 271 272 void 273 dk4dmt_error_no_signal_function(dk4dmt_t *pdmt); 274 275 276 /** Set exit code in daemon structure to indicate PID file exists. 277 @param pdmt Daemon tool structure to use. 278 */ 279 280 void 281 dk4dmt_error_pid_file_exists(dk4dmt_t *pdmt); 282 283 284 /** Set exit code in daemon structure to indicate PID file not configured. 285 @param pdmt Daemon tool structure to use. 286 */ 287 288 void 289 dk4dmt_error_pid_file_name_missing(dk4dmt_t *pdmt); 290 291 292 /** Set exit code in daemon structure to indicate write PID file failed. 293 @param pdmt Daemon tool structure to use. 294 */ 295 296 void 297 dk4dmt_error_write_pid_file(dk4dmt_t *pdmt); 298 299 /** Set exit code in daemon structure to indicate pipe was not opened (bug). 300 @param pdmt Daemon tool structure to use. 301 */ 302 303 void 304 dk4dmt_error_pipe_not_open(dk4dmt_t *pdmt); 305 306 307 /** Set exit code in daemon structure to indicate reading from pipe failed. 308 @param pdmt Daemon tool structure to use. 309 */ 310 311 void 312 dk4dmt_error_pipe_read_failed(dk4dmt_t *pdmt); 313 314 315 /** Set exit code in daemon structure to indicate fork failed. 316 @param pdmt Daemon tool structure to use. 317 */ 318 319 void 320 dk4dmt_error_fork_failed(dk4dmt_t *pdmt); 321 322 323 /** Set exit code in daemon structure to indicate setsid failed. 324 @param pdmt Daemon tool structure to use. 325 */ 326 327 void 328 dk4dmt_error_setsid(dk4dmt_t *pdmt); 329 330 331 /** Set exit code in daemon structure to indicate dup2 failed. 332 @param pdmt Daemon tool structure to use. 333 */ 334 335 void 336 dk4dmt_error_dup2_failed(dk4dmt_t *pdmt); 337 338 339 /** Set exit code in daemon structure to indicate reading /dev/null failed. 340 @param pdmt Daemon tool structure to use. 341 */ 342 343 void 344 dk4dmt_error_failed_read_dev_null(dk4dmt_t *pdmt); 345 346 347 /** Set exit code in daemon structure to indicate writing /dev/null failed. 348 @param pdmt Daemon tool structure to use. 349 */ 350 351 void 352 dk4dmt_error_failed_write_dev_null(dk4dmt_t *pdmt); 353 354 355 /** Set exit code in daemon structure to indicate chdir to / failed. 356 @param pdmt Daemon tool structure to use. 357 */ 358 359 void 360 dk4dmt_error_failed_chdir_root(dk4dmt_t *pdmt); 361 362 363 /** Set exit code in daemon structure for failed signal set cleanup. 364 @param pdmt Daemon tool structure to use. 365 */ 366 367 void 368 dk4dmt_error_sigemptyset(dk4dmt_t *pdmt); 369 370 371 /** Set exit code in daemon structure for unusable configuration. 372 @param pdmt Daemon tool structure to use. 373 */ 374 375 void 376 dk4dmt_error_config(dk4dmt_t *pdmt); 377 378 379 /** Set exit code in daemon structure to indicate wrong call arguments. 380 @param pdmt Daemon tool structure to use. 381 */ 382 383 void 384 dk4dmt_error_usage(dk4dmt_t *pdmt); 385 386 387 /** Indicate success. 388 @param pdmt Daemon tool structure to use. 389 */ 390 void 391 dk4dmt_success(dk4dmt_t *pdmt); 392 393 394 /** Retrieve exit status code. 395 @param pdmt Daemon tool structure to use. 396 @return Exit status code to return. 397 */ 398 399 int 400 dk4dmt_get_exit_status(dk4dmt_t *pdmt); 401 402 #ifdef __cplusplus 403 } 404 #endif 405 406 407 #endif 408