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 /** @file dk4dmt.c The dk4dmt module.
15 */
16
17
18 #include "dk4conf.h"
19
20 #include <stdio.h>
21
22 #if DK4_HAVE_SYS_TYPES_H
23 #ifndef SYS_TYPES_H_INCLUDED
24 #include <sys/types.h>
25 #define SYS_TYPES_H_INCLUDED 1
26 #endif
27 #endif
28
29 #if DK4_HAVE_SYS_STAT_H
30 #ifndef SYS_STAT_H_INCLUDED
31 #include <sys/stat.h>
32 #define SYS_STAT_H_INCLUDED 1
33 #endif
34 #endif
35
36 #if DK4_HAVE_STDLIB_H
37 #ifndef STDLIB_H_INCLUDED
38 #include <stdlib.h>
39 #define STDLIB_H_INCLUDED 1
40 #endif
41 #endif
42
43 #if DK4_HAVE_UNISTD_H
44 #ifndef UNISTD_H_INCLUDED
45 #include <unistd.h>
46 #define UNISTD_H_INCLUDED 1
47 #endif
48 #endif
49
50 #if DK4_HAVE_FCNTL_H
51 #ifndef FCNTL_H_INCLUDED
52 #include <fcntl.h>
53 #define FCNTL_H_INCLUDED 1
54 #endif
55 #endif
56
57 #if DK4_HAVE_SIGNAL_H
58 #ifndef SIGNAL_H_INCLUDED
59 #include <signal.h>
60 #define SIGNAL_H_INCLUDED 1
61 #endif
62 #endif
63
64 #if DK4_HAVE_IO_H
65 #ifndef IO_H_INCLUDED
66 #include <io.h>
67 #define IO_H_INCLUDED 1
68 #endif
69 #endif
70
71 #if DK4_HAVE_SYSLOG_H
72 #ifndef SYSLOG_H_INCLUDED
73 #include <syslog.h>
74 #define SYSLOG_H_INCLUDED 1
75 #endif
76 #endif
77
78 #if DK4_HAVE_SYSEXITS_H
79 #ifndef SYSEXITS_H_INCLUDED
80 #include <sysexits.h>
81 #define SYSEXITS_H_INCLUDED
82 #endif
83 #endif
84
85 #ifndef DK4TYPES_H_INCLUDED
86 #include <libdk4base/dk4types.h>
87 #endif
88
89 #ifndef DK4DMT_H_INCLUDED
90 #include <libdk4c/dk4dmt.h>
91 #endif
92
93 #ifndef DK4MEM_H_INCLUDED
94 #include <libdk4base/dk4mem.h>
95 #endif
96
97 #ifndef DK4MAO8D_H_INCLUDED
98 #include <libdk4maio8d/dk4mao8d.h>
99 #endif
100
101 #ifndef DK4STAT8_H_INCLUDED
102 #include <libdk4c/dk4stat8.h>
103 #endif
104
105 #ifndef DK4STR8_H_INCLUDED
106 #include <libdk4base/dk4str8.h>
107 #endif
108
109 #ifndef DK4FOPC8_H_INCLUDED
110 #include <libdk4c/dk4fopc8.h>
111 #endif
112
113 #ifndef DK4MKDH8_H_INCLUDED
114 #include <libdk4c/dk4mkdh8.h>
115 #endif
116
117
118
119
120
121 /** Constant texts used by module.
122 */
123 static char const * const dk4dmt_kw[] = {
124 /* 0 */
125 "\n",
126
127 /* 1 */
128 "w",
129
130 /* 2 */
131 "/dev/null",
132
133 /* 3 */
134 "/",
135
136 /* 4 */
137 "No signal handling functions available!",
138
139 /* 5 */
140 "Failed to create empty set for signal ",
141
142 /* 6 */
143 "!",
144
145 /* 7 */
146 "Failed to reset handler for signal ",
147
148 /* 8 */
149 "!",
150
151 /* 9 */
152 "Failed to unblock all signals!",
153
154 /* 10 */
155 "PID file already exists!",
156
157 /* 11 */
158 "Pipe not open (bug)!",
159
160 /* 12 */
161 "Failed to read from pipe!",
162
163 /* 13 */
164 "Failed to fork new process!",
165
166 /* 14 */
167 "Failed to decouple from terminal using setsid()!",
168
169 /* 15 */
170 "Missing function to decouple from terminal (setsid/setpgrp)!",
171
172 /* 16 */
173 "Failed to write PID file!",
174
175 /* 17 */
176 "No PID file name specified (bug)!",
177
178 /* 18 */
179 "Failed to duplicate standard file handle using dup2()!",
180
181 /* 19 */
182 "Failed to open /dev/null for read access!",
183
184 /* 20 */
185 "Failed to open /dev/null for write access!",
186
187 /* 21 */
188 "Failed to change to / directory!",
189
190 /* 22 */
191 "Failed to remove PID file \"",
192
193 /* 23 */
194 "\"!",
195
196 /* 24 */
197 "dk4dmt.o",
198
199 NULL
200
201 };
202
203
204
205 static
206 void
dk4dmt_log_1(dk4dmt_t * pdmt,size_t i)207 dk4dmt_log_1(dk4dmt_t *pdmt, size_t i)
208 {
209 #if DK4_HAVE_SYSLOG
210 const char *progname;
211 #endif
212 if (0 != pdmt->logstderr) {
213 fputs(dk4dmt_kw[i], stderr);
214 fputc('\n', stderr);
215 }
216 #if DK4_HAVE_SYSLOG
217 progname = pdmt->prgname;
218 if (NULL == progname) { progname = dk4dmt_kw[24]; }
219 openlog(progname, LOG_PID, pdmt->slf);
220 syslog(LOG_ERR, "%s", dk4dmt_kw[i]);
221 closelog();
222 #endif
223 }
224
225
226
227 static
228 void
dk4dmt_log_3(dk4dmt_t * pdmt,size_t i1,size_t i2,const char * s)229 dk4dmt_log_3(dk4dmt_t *pdmt, size_t i1, size_t i2, const char *s)
230 {
231 #if DK4_HAVE_SYSLOG
232 const char *progname;
233 #endif
234 if (0 != pdmt->logstderr) {
235 fputs(dk4dmt_kw[i1], stderr);
236 fputs(s, stderr);
237 fputs(dk4dmt_kw[i2], stderr);
238 fputc('\n', stderr);
239 }
240 #if DK4_HAVE_SYSLOG
241 progname = pdmt->prgname;
242 if (NULL == progname) { progname = dk4dmt_kw[24]; }
243 openlog(progname, LOG_PID, pdmt->slf);
244 syslog(LOG_ERR, "%s%s%s", dk4dmt_kw[i1], s, dk4dmt_kw[i2]);
245 closelog();
246 #endif
247 }
248
249
250
251 /** Set exit status in structure.
252 @param pdmt Structure to modify.
253 @param syse One of the codes defined in the sysexits header.
254 @param sdes Systemd error code.
255 */
256 static
257 void
dk4dmt_set_error_exit_status(dk4dmt_t * pdmt,int syse,int sdes)258 dk4dmt_set_error_exit_status(dk4dmt_t *pdmt, int syse, int sdes)
259 {
260 if (NULL != pdmt) {
261 if (EXIT_SUCCESS == pdmt->exv) {
262 #if DK4_HAVE_SYSTEMD
263 if (0 != sdes) {
264 pdmt->exv = sdes;
265 }
266 else {
267 pdmt->exv = syse;
268 }
269 #else
270 if (0 != syse) {
271 pdmt->exv = syse;
272 }
273 else {
274 switch (sdes) {
275 default : {
276 #if (DK4_HAVE_SYSEXITS_H) && defined(EX_OSERR)
277 pdmt->exv = EX_OSERR;
278 #else
279 pdmt->exv = EXIT_FAILURE;
280 #endif
281 } break;
282 }
283 }
284 #endif
285 }
286 }
287 }
288
289
290
291 void
dk4dmt_init(dk4dmt_t * pdmt)292 dk4dmt_init(dk4dmt_t *pdmt)
293 {
294 if (NULL != pdmt) {
295 DK4_MEMRES(pdmt,sizeof(dk4dmt_t));
296 pdmt->prgname = NULL;
297 pdmt->pidfile = NULL;
298 pdmt->pfd[0] = -1;
299 pdmt->pfd[1] = -1;
300 pdmt->logstderr = 0;
301 #if (DK4_HAVE_SYSLOG_H) && defined(LOG_DAEMON)
302 pdmt->slf = LOG_DAEMON;
303 #else
304 pdmt->slf = (3<<3);
305 #endif
306 pdmt->exv = EXIT_SUCCESS;
307 }
308 }
309
310
311
312 void
dk4dmt_set_program(dk4dmt_t * pdmt,const char * progname)313 dk4dmt_set_program(dk4dmt_t *pdmt, const char *progname)
314 {
315 if ((NULL != pdmt) && (NULL != progname)) {
316 pdmt->prgname = progname;
317 }
318 }
319
320
321
322 void
dk4dmt_set_pidfile(dk4dmt_t * pdmt,const char * pidfile)323 dk4dmt_set_pidfile(dk4dmt_t *pdmt, const char *pidfile)
324 {
325 if ((NULL != pdmt) && (NULL != pidfile)) {
326 pdmt->pidfile = pidfile;
327 }
328 }
329
330
331
332 void
dk4dmt_set_log_stderr(dk4dmt_t * pdmt,int flag)333 dk4dmt_set_log_stderr(dk4dmt_t *pdmt, int flag)
334 {
335 if (NULL != pdmt) {
336 pdmt->logstderr = flag;
337 }
338 }
339
340
341
342 void
dk4dmt_set_syslog_feature(dk4dmt_t * pdmt,int feat)343 dk4dmt_set_syslog_feature(dk4dmt_t *pdmt, int feat)
344 {
345 if (NULL != pdmt) {
346 pdmt->slf = feat;
347 }
348 }
349
350
351
352 void
dk4dmt_error_sigprocmask(dk4dmt_t * pdmt)353 dk4dmt_error_sigprocmask(dk4dmt_t *pdmt)
354 {
355 #if (DK4_HAVE_SYSEXITS_H) && defined(EX_OSERR)
356 dk4dmt_set_error_exit_status(pdmt, EX_OSERR, 207);
357 #else
358 dk4dmt_set_error_exit_status(pdmt, EXIT_FAILURE, 207);
359 #endif
360 }
361
362
363
364 void
dk4dmt_error_sigemptyset(dk4dmt_t * pdmt)365 dk4dmt_error_sigemptyset(dk4dmt_t *pdmt)
366 {
367 #if (DK4_HAVE_SYSEXITS_H) && defined(EX_OSERR)
368 dk4dmt_set_error_exit_status(pdmt, EX_OSERR, 207);
369 #else
370 dk4dmt_set_error_exit_status(pdmt, EXIT_FAILURE, 207);
371 #endif
372 }
373
374
375
376 void
dk4dmt_error_no_signal_function(dk4dmt_t * pdmt)377 dk4dmt_error_no_signal_function(dk4dmt_t *pdmt)
378 {
379 #if (DK4_HAVE_SYSEXITS_H) && defined(EX_OSERR)
380 dk4dmt_set_error_exit_status(pdmt, EX_OSERR, 2);
381 #else
382 dk4dmt_set_error_exit_status(pdmt, EXIT_FAILURE, 2);
383 #endif
384 }
385
386
387
388 void
dk4dmt_error_pid_file_exists(dk4dmt_t * pdmt)389 dk4dmt_error_pid_file_exists(dk4dmt_t *pdmt)
390 {
391 #if (DK4_HAVE_SYSEXITS_H) && defined(EX_SOFTWARE)
392 dk4dmt_set_error_exit_status(pdmt, EX_SOFTWARE, 0);
393 #else
394 dk4dmt_set_error_exit_status(pdmt, EXIT_FAILURE, 0);
395 #endif
396 }
397
398
399
400 void
dk4dmt_error_pid_file_name_missing(dk4dmt_t * pdmt)401 dk4dmt_error_pid_file_name_missing(dk4dmt_t *pdmt)
402 {
403 #if (DK4_HAVE_SYSEXITS_H) && defined(EX_SOFTWARE)
404 dk4dmt_set_error_exit_status(pdmt, EX_SOFTWARE, 0);
405 #else
406 dk4dmt_set_error_exit_status(pdmt, EXIT_FAILURE, 0);
407 #endif
408 }
409
410
411
412 void
dk4dmt_error_pipe_not_open(dk4dmt_t * pdmt)413 dk4dmt_error_pipe_not_open(dk4dmt_t *pdmt)
414 {
415 #if (DK4_HAVE_SYSEXITS_H) && defined(EX_SOFTWARE)
416 dk4dmt_set_error_exit_status(pdmt, EX_SOFTWARE, 0);
417 #else
418 dk4dmt_set_error_exit_status(pdmt, EXIT_FAILURE, 0);
419 #endif
420 }
421
422
423
424 void
dk4dmt_error_pipe_read_failed(dk4dmt_t * pdmt)425 dk4dmt_error_pipe_read_failed(dk4dmt_t *pdmt)
426 {
427 #if (DK4_HAVE_SYSEXITS_H) && defined(EX_IOERR)
428 dk4dmt_set_error_exit_status(pdmt, EX_IOERR, 0);
429 #else
430 dk4dmt_set_error_exit_status(pdmt, EXIT_FAILURE, 0);
431 #endif
432 }
433
434
435
436 void
dk4dmt_error_fork_failed(dk4dmt_t * pdmt)437 dk4dmt_error_fork_failed(dk4dmt_t *pdmt)
438 {
439 #if (DK4_HAVE_SYSEXITS_H) && defined(EX_OSERR)
440 dk4dmt_set_error_exit_status(pdmt, EX_OSERR, 0);
441 #else
442 dk4dmt_set_error_exit_status(pdmt, EXIT_FAILURE, 0);
443 #endif
444 }
445
446
447
448 void
dk4dmt_error_dup2_failed(dk4dmt_t * pdmt)449 dk4dmt_error_dup2_failed(dk4dmt_t *pdmt)
450 {
451 #if (DK4_HAVE_SYSEXITS_H) && defined(EX_IOERR)
452 dk4dmt_set_error_exit_status(pdmt, EX_IOERR, 0);
453 #else
454 dk4dmt_set_error_exit_status(pdmt, EXIT_FAILURE, 0);
455 #endif
456 }
457
458
459
460 void
dk4dmt_error_failed_read_dev_null(dk4dmt_t * pdmt)461 dk4dmt_error_failed_read_dev_null(dk4dmt_t *pdmt)
462 {
463 #if (DK4_HAVE_SYSEXITS_H) && defined(EX_IOERR)
464 dk4dmt_set_error_exit_status(pdmt, EX_IOERR, 0);
465 #else
466 dk4dmt_set_error_exit_status(pdmt, EXIT_FAILURE, 0);
467 #endif
468 }
469
470
471
472 void
dk4dmt_error_failed_write_dev_null(dk4dmt_t * pdmt)473 dk4dmt_error_failed_write_dev_null(dk4dmt_t *pdmt)
474 {
475 #if (DK4_HAVE_SYSEXITS_H) && defined(EX_IOERR)
476 dk4dmt_set_error_exit_status(pdmt, EX_IOERR, 0);
477 #else
478 dk4dmt_set_error_exit_status(pdmt, EXIT_FAILURE, 0);
479 #endif
480 }
481
482
483
484 void
dk4dmt_error_failed_chdir_root(dk4dmt_t * pdmt)485 dk4dmt_error_failed_chdir_root(dk4dmt_t *pdmt)
486 {
487 #if (DK4_HAVE_SYSEXITS_H) && defined(EX_OSERR)
488 dk4dmt_set_error_exit_status(pdmt, EX_OSERR, 200);
489 #else
490 dk4dmt_set_error_exit_status(pdmt, EXIT_FAILURE, 200);
491 #endif
492 }
493
494
495
496 void
dk4dmt_error_setsid(dk4dmt_t * pdmt)497 dk4dmt_error_setsid(dk4dmt_t *pdmt)
498 {
499 #if (DK4_HAVE_SYSEXITS_H) && defined(EX_OSERR)
500 dk4dmt_set_error_exit_status(pdmt, EX_OSERR, 220);
501 #else
502 dk4dmt_set_error_exit_status(pdmt, EXIT_FAILURE, 220);
503 #endif
504 }
505
506
507 void
dk4dmt_error_write_pid_file(dk4dmt_t * pdmt)508 dk4dmt_error_write_pid_file(dk4dmt_t *pdmt)
509 {
510 #if (DK4_HAVE_SYSEXITS_H) && defined(EX_IOERR)
511 dk4dmt_set_error_exit_status(pdmt, EX_IOERR, 0);
512 #else
513 dk4dmt_set_error_exit_status(pdmt, EXIT_FAILURE, 0);
514 #endif
515 }
516
517
518
519 void
dk4dmt_error_sysfct(dk4dmt_t * pdmt)520 dk4dmt_error_sysfct(dk4dmt_t *pdmt)
521 {
522 if (NULL != pdmt) {
523 #if (DK4_HAVE_SYSEXITS_H) && defined(EX_OSERR)
524 dk4dmt_set_error_exit_status(pdmt, EX_OSERR, 0);
525 #else
526 dk4dmt_set_error_exit_status(pdmt, EXIT_FAILURE, 0);
527 #endif
528 }
529 }
530
531
532
533 void
dk4dmt_error_usage(dk4dmt_t * pdmt)534 dk4dmt_error_usage(dk4dmt_t *pdmt)
535 {
536 if (NULL != pdmt) {
537 #if (DK4_HAVE_SYSEXITS_H) && defined(EX_USAGE)
538 dk4dmt_set_error_exit_status(pdmt, EX_USAGE, 0);
539 #else
540 dk4dmt_set_error_exit_status(pdmt, EXIT_FAILURE, 0);
541 #endif
542 }
543 }
544
545
546
547 void
dk4dmt_error_config(dk4dmt_t * pdmt)548 dk4dmt_error_config(dk4dmt_t *pdmt)
549 {
550 if (NULL != pdmt) {
551 #if (DK4_HAVE_SYSEXITS_H) && defined(EX_CONFIG)
552 dk4dmt_set_error_exit_status(pdmt, EX_CONFIG, 0);
553 #else
554 dk4dmt_set_error_exit_status(pdmt, EXIT_FAILURE, 0);
555 #endif
556 }
557 }
558
559
560
561 static
562 void
dk4dmt_reset_all_signals(int * pback,dk4dmt_t * pdmt)563 dk4dmt_reset_all_signals(int *pback, dk4dmt_t *pdmt)
564 {
565 #if DK4_HAVE_SIGACTION
566 struct sigaction sigact; /* Information for sigaction() */
567 #endif
568 char buf[16*sizeof(int)];
569 int maxsig; /* Maximum signal number */
570 int signo; /* Current signal number to process */
571 int go; /* Flag: Reconfigure signal */
572 int ec; /* Error code */
573
574 ec = 0;
575 #ifdef _NSIG
576 maxsig = _NSIG;
577 #else
578 maxsig = 16;
579 #endif
580 for (signo = 1; ((maxsig >= signo) && (1 == *pback)); signo++) {
581 go = 1;
582 #ifdef SIGKILL
583 if (SIGKILL == signo) { go = 0; }
584 #else
585 if (9 == signo) { go = 0; }
586 #endif
587 #ifdef SIGSTOP
588 if (SIGSTOP == signo) { go = 0; }
589 #else
590 if (19 == signo) { go = 0; }
591 #endif
592 if (0 != go) {
593 #if DK4_HAVE_SIGACTION
594 DK4_MEMRES(&sigact, sizeof(sigact));
595 sigact.sa_handler = SIG_DFL;
596 sigact.sa_flags = 0;
597 if (0 != sigemptyset(&(sigact.sa_mask))) {
598 if (16 > signo) {
599 *pback = 0;
600 dk4dmt_error_sigemptyset(pdmt);
601 /* ERROR: Failed to empty set */
602 #if DK4_HAVE_SNPRINTF
603 snprintf(buf, sizeof(buf), "%d", signo);
604 #else
605 sprintf(buf, "%d", signo);
606 #endif
607 dk4dmt_log_3(pdmt, 5, 6, buf);
608 }
609 }
610 else {
611 if (0 != sigaction(signo, &sigact, NULL)) {
612 if (16 > signo) {
613 *pback = 0;
614 dk4dmt_error_sigemptyset(pdmt);
615 /* ERROR: sigaction failed */
616 #if DK4_HAVE_SNPRINTF
617 snprintf(buf, sizeof(buf), "%d", signo);
618 #else
619 sprintf(buf, "%d", signo);
620 #endif
621 dk4dmt_log_3(pdmt, 7, 8, buf);
622 }
623 }
624 }
625 #else
626 #if DK4_HAVE_SIGSET
627 sigset(signo, SIG_DFL);
628 #else
629 #if DK4_HAVE_SIGNAL
630 signal(signo, SIG_DFL);
631 #else
632 *pback = 0;
633 dk4dmt_error_no_signal_function(pdmt);
634 /* ERROR: No function available to modify signals */
635 if (0 == ec) { ec = 3; }
636 #endif
637 #endif
638 #endif
639 }
640 }
641 switch (ec) {
642 case 3: {
643 dk4dmt_log_1(pdmt, 4);
644 } break;
645 }
646 }
647
648
649
650 static
651 void
dk4dmt_unblock_all_signals(int * pback,dk4dmt_t * pdmt)652 dk4dmt_unblock_all_signals(int *pback, dk4dmt_t *pdmt)
653 {
654 sigset_t set;
655 if (0 == sigemptyset(&set)) {
656 if (0 != sigprocmask(SIG_SETMASK, &set, NULL)) {
657 *pback = 0;
658 dk4dmt_error_sigprocmask(pdmt);
659 /* ERROR: sigprocmask failed */
660 dk4dmt_log_1(pdmt, 9);
661 }
662 }
663 else {
664 *pback = 0;
665 dk4dmt_error_sigemptyset(pdmt);
666 /* ERROR: Failed to sigemptyset */
667 dk4dmt_log_1(pdmt, 9);
668 }
669 }
670
671
672
673 static
674 void
dk4dmt_close_non_std_file_descriptors(void)675 dk4dmt_close_non_std_file_descriptors(void)
676 {
677 #if DK4_HAVE_SYS_RESOURCE_H && DK4_HAVE_GETRLIMIT && defined(RLIMIT_NOFILE)
678 struct rlimit rl;
679 #endif
680 int maxfd = 1024;
681 int fd;
682
683 /* Find maximum file descriptor
684 */
685 #if DK4_HAVE_SYS_RESOURCE_H && DK4_HAVE_GETRLIMIT && defined(RLIMIT_NOFILE)
686 if (0 == getrlimit(RLIMIT_NOFILE, &rl)) {
687 #if defined(RLIM_INFINITY)
688 if (RLIM_INFINITY != rl.rlim_max) {
689 back = rl.rlim_max;
690 }
691 #else
692 back = rl.rlim_max;
693 #endif
694 }
695 #else
696 #endif
697 /*
698 Close file descriptors
699 */
700 for (fd = 3; fd <= maxfd; fd++) {
701 (void)close(fd);
702 }
703 }
704
705
706
707 int
dk4dmt_parent_before_fork(dk4dmt_t * pdmt)708 dk4dmt_parent_before_fork(dk4dmt_t *pdmt)
709 {
710 dk4_stat_t stb;
711 int back = 0;
712
713 if (NULL != pdmt) {
714 back = 1;
715 /*
716 Close non-standard file descriptors
717 */
718 dk4dmt_close_non_std_file_descriptors();
719 /*
720 Reset all signals
721 */
722 dk4dmt_reset_all_signals(&back, pdmt);
723 if (1 == back) {
724 /*
725 Unblock all signals
726 */
727 dk4dmt_unblock_all_signals(&back, pdmt);
728 if (1 == back) {
729 if (NULL != pdmt->pidfile) {
730 if (0 != dk4stat_c8(&stb, pdmt->pidfile, NULL)) {
731 back = 0;
732 dk4dmt_error_pid_file_exists(pdmt);
733 /* ERROR: PID file exists */
734 dk4dmt_log_1(pdmt, 10);
735 }
736 }
737 if (1 == back) {
738 if (0 != pipe(&(pdmt->pfd[0]))) {
739 back = 0;
740 pdmt->pfd[0] = -1;
741 pdmt->pfd[1] = -1;
742 }
743 }
744 }
745 }
746 }
747 return back;
748 }
749
750
751
752 void
dk4dmt_parent_after_fork(dk4dmt_t * pdmt)753 dk4dmt_parent_after_fork(dk4dmt_t *pdmt)
754 {
755 int v;
756
757 if (NULL != pdmt) {
758 /*
759 Close write head
760 */
761 if (-1 != pdmt->pfd[1]) {
762 close(pdmt->pfd[1]);
763 pdmt->pfd[1] = -1;
764 }
765 else {
766 dk4dmt_error_pipe_not_open(pdmt);
767 /* ERROR: Pipe was not open (bug) */
768 dk4dmt_log_1(pdmt, 11);
769 }
770 /*
771 Read exit status code and close read head
772 */
773 if (-1 != pdmt->pfd[0]) {
774 if ((int)sizeof(int) == (int)read(pdmt->pfd[0], &v, sizeof(int))) {
775 pdmt->exv = v;
776 }
777 else {
778 dk4dmt_error_pipe_read_failed(pdmt);
779 /* ERROR: Failed to read from pipe */
780 dk4dmt_log_1(pdmt, 12);
781 }
782 close(pdmt->pfd[0]);
783 pdmt->pfd[0] = -1;
784 }
785 else {
786 dk4dmt_error_pipe_not_open(pdmt);
787 /* ERROR: Pipe was not open (bug) */
788 dk4dmt_log_1(pdmt, 11);
789 }
790 }
791 }
792
793
794
795 void
dk4dmt_parent_fork_failed(dk4dmt_t * pdmt)796 dk4dmt_parent_fork_failed(dk4dmt_t *pdmt)
797 {
798 if (NULL != pdmt) {
799 /*
800 Write error exit status code
801 */
802 dk4dmt_error_fork_failed(pdmt);
803 /* ERROR: Fork failed */
804 dk4dmt_log_1(pdmt, 13);
805 /*
806 Close write head
807 */
808 if (-1 != pdmt->pfd[1]) {
809 close(pdmt->pfd[1]);
810 pdmt->pfd[1] = -1;
811 }
812 /*
813 Close read head
814 */
815 if (-1 != pdmt->pfd[0]) {
816 close(pdmt->pfd[0]);
817 pdmt->pfd[0] = -1;
818 }
819 }
820 }
821
822
823
824 int
dk4dmt_intermediate_before_fork(dk4dmt_t * pdmt)825 dk4dmt_intermediate_before_fork(dk4dmt_t *pdmt)
826 {
827 int back = 0;
828 if (NULL != pdmt) {
829 back = 1;
830 /*
831 Close read head
832 */
833 if (-1 != pdmt->pfd[0]) {
834 close(pdmt->pfd[0]);
835 pdmt->pfd[0] = -1;
836 }
837 #if DK4_HAVE_SETSID
838 if ((pid_t)(-1) == setsid()) {
839 back = 0;
840 dk4dmt_error_setsid(pdmt);
841 /* ERROR: setsid() failed */
842 dk4dmt_log_1(pdmt, 14);
843 }
844 #else
845 #if DK4_HAVE_SETPGRP
846 setpgrp();
847 #else
848 back = 0;
849 dk4dmt_error_setsid(pdmt);
850 /* ERROR: No function to decouple from terminal */
851 dk4dmt_log_1(pdmt, 15);
852 #endif
853 #endif
854 }
855 return back;
856 }
857
858
859
860 void
dk4dmt_intermediate_after_fork(dk4dmt_t * pdmt)861 dk4dmt_intermediate_after_fork(dk4dmt_t *pdmt)
862 {
863 if (NULL != pdmt) {
864 /*
865 Close write head
866 */
867 if (-1 != pdmt->pfd[1]) {
868 close(pdmt->pfd[1]);
869 pdmt->pfd[1] = -1;
870 }
871 }
872 }
873
874
875
876 void
dk4dmt_intermediate_fork_failed(dk4dmt_t * pdmt)877 dk4dmt_intermediate_fork_failed(dk4dmt_t *pdmt)
878 {
879 int v;
880
881 if (NULL != pdmt) {
882 /*
883 Set exit status code
884 */
885 dk4dmt_parent_fork_failed(pdmt);
886 /* ERROR: Fork failed */
887 dk4dmt_log_1(pdmt, 13);
888 /*
889 Close write head
890 */
891 if (-1 != pdmt->pfd[1]) {
892 v = pdmt->exv;
893 if ((int)sizeof(v) != (int)write(pdmt->pfd[1], &v, sizeof(v))) {
894 #if (DK4_HAVE_SYSEXITS_H) && defined(EX_IOERR)
895 dk4dmt_set_error_exit_status(pdmt, EX_IOERR, 0);
896 #else
897 dk4dmt_set_error_exit_status(pdmt, EXIT_FAILURE, 0);
898 #endif
899 }
900 close(pdmt->pfd[1]);
901 pdmt->pfd[1] = -1;
902 }
903 }
904 }
905
906
907
908 int
dk4dmt_daemon_start(dk4dmt_t * pdmt)909 dk4dmt_daemon_start(dk4dmt_t *pdmt)
910 {
911 char pidbuf[16*sizeof(dk4_um_t)];
912 FILE *fipo;
913 int res;
914 int v;
915 int fdout;
916 int fdin;
917 int back = 0;
918
919 if (NULL != pdmt) {
920 if (NULL != pdmt->pidfile) {
921 res = dk4ma_write_c8_decimal_unsigned(
922 pidbuf, sizeof(pidbuf), (dk4_um_t)getpid(), 0, NULL
923 );
924 if (0 != res) {
925 if (0 != dk4str8_cat_s(pidbuf,sizeof(pidbuf),dk4dmt_kw[0],NULL))
926 {
927 (void)dk4mkdir_hierarchy_c8(pdmt->pidfile, 0, NULL);
928 fipo = dk4fopen_c8(
929 pdmt->pidfile,dk4dmt_kw[1],DK4_FOPEN_SC_PRIVILEGED,NULL
930 );
931 if (NULL != fipo) {
932 back = 1;
933 if (EOF == fputs(pidbuf, fipo)) {
934 back = 0;
935 dk4dmt_error_write_pid_file(pdmt);
936 /* ERROR: Failed to write PID file */
937 dk4dmt_log_1(pdmt, 16);
938 }
939 if (0 != fclose(fipo)) {
940 back = 0;
941 dk4dmt_error_write_pid_file(pdmt);
942 /* ERROR: Failed to write PID file */
943 dk4dmt_log_1(pdmt, 16);
944 }
945 }
946 else {
947 dk4dmt_error_write_pid_file(pdmt);
948 /* ERROR: Failed to write PID file */
949 dk4dmt_log_1(pdmt, 16);
950 }
951 }
952 }
953 if (0 == back) {
954 unlink(pdmt->pidfile);
955 }
956 }
957 else {
958 dk4dmt_error_pid_file_name_missing(pdmt);
959 /* ERROR: Missing PID file name */
960 dk4dmt_log_1(pdmt, 17);
961 }
962 /*
963 Connect /dev/null to stdin, stdout and stderr
964 */
965 if (0 != back) {
966 fdin = open(dk4dmt_kw[2], O_RDONLY);
967 if (-1 < fdin) {
968 if (-1 == dup2(fdin, 0)) {
969 back = 0;
970 dk4dmt_error_dup2_failed(pdmt);
971 /* ERROR: Failed to duplicate file handle */
972 dk4dmt_log_1(pdmt, 18);
973 }
974 close(fdin);
975 }
976 else {
977 back = 0;
978 dk4dmt_error_failed_read_dev_null(pdmt);
979 /* ERROR: Failed to read /dev/null */
980 dk4dmt_log_1(pdmt, 19);
981 }
982 fdout = open(dk4dmt_kw[2], O_WRONLY);
983 if (-1 < fdout) {
984 if (-1 == dup2(fdout, 1)) {
985 back = 0;
986 dk4dmt_error_dup2_failed(pdmt);
987 /* ERROR: Failed to duplicate file handle */
988 dk4dmt_log_1(pdmt, 18);
989 }
990 if (-1 == dup2(fdout, 2)) {
991 back = 0;
992 dk4dmt_error_dup2_failed(pdmt);
993 /* ERROR: Failed to duplicate file handle */
994 dk4dmt_log_1(pdmt, 18);
995 }
996 close(fdout);
997 }
998 else {
999 back = 0;
1000 dk4dmt_error_failed_write_dev_null(pdmt);
1001 /* ERROR: Failed to write /dev/null */
1002 dk4dmt_log_1(pdmt, 20);
1003 }
1004 }
1005 /*
1006 Use exact permissions when creating new files or directories
1007 */
1008 if (0 != back) {
1009 umask(0);
1010 }
1011 /*
1012 Change to root directory
1013 */
1014 if (0 != back) {
1015 if (0 != chdir(dk4dmt_kw[3])) {
1016 back = 0;
1017 dk4dmt_error_failed_chdir_root(pdmt);
1018 /* ERROR: Failed to change into root directory */
1019 dk4dmt_log_1(pdmt, 21);
1020 }
1021 }
1022 /* Send exit status code to main process
1023 */
1024 if (-1 != pdmt->pfd[1]) {
1025 v = pdmt->exv;
1026 if ((int)sizeof(v) != (int)write(pdmt->pfd[1], &v, sizeof(v))) {
1027 #if (DK4_HAVE_SYSEXITS_H) && defined(EX_IOERR)
1028 dk4dmt_set_error_exit_status(pdmt, EX_IOERR, 0);
1029 #else
1030 dk4dmt_set_error_exit_status(pdmt, EXIT_FAILURE, 0);
1031 #endif
1032 }
1033 close(pdmt->pfd[1]);
1034 pdmt->pfd[1] = -1;
1035 }
1036 }
1037 return back;
1038 }
1039
1040
1041
1042 void
dk4dmt_daemon_end(dk4dmt_t * pdmt)1043 dk4dmt_daemon_end(dk4dmt_t *pdmt)
1044 {
1045 if (NULL != pdmt) {
1046 if (NULL != pdmt->pidfile) {
1047 if (0 != unlink(pdmt->pidfile)) {
1048 /* ERROR: Failed to remove PID file */
1049 dk4dmt_log_3(pdmt, 22, 23, pdmt->pidfile);
1050 }
1051 }
1052 }
1053 }
1054
1055
1056
1057 void
dk4dmt_success(dk4dmt_t * pdmt)1058 dk4dmt_success(dk4dmt_t *pdmt)
1059 {
1060 if (NULL != pdmt) {
1061 pdmt->exv = EXIT_SUCCESS;
1062 }
1063 }
1064
1065
1066 int
dk4dmt_get_exit_status(dk4dmt_t * pdmt)1067 dk4dmt_get_exit_status(dk4dmt_t *pdmt)
1068 {
1069 int back = EXIT_FAILURE;
1070 if (NULL != pdmt) {
1071 back = pdmt->exv;
1072 }
1073 return back;
1074 }
1075
1076
1077 /* vim: set ai sw=4 ts=4 : */
1078
1079