/
daemon.c
136 lines (118 loc) · 2.96 KB
/
daemon.c
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
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "args.h"
#include "log.h"
#include "utility.h"
const int SLEEP_DELAY = 0;
const char SAFE_DIR[] = "/";
const char DEV_NULL_DIR[] = "/dev/null";
bool mainLoop(int argc, char **argv);
void forkChildAndExit()
{
pid_t pid = fork();
if (pid < 0) {
fprintf(stderr,"Error: Fork failed.\n");
exit(EXIT_FAILURE);
} else if (0 < pid) {
exit(EXIT_SUCCESS);
}
}
void becomeSessionLeader()
{
if (setsid() < 0) {
fprintf(stderr,"Error: Failed to become session leader.\n");
exit(EXIT_FAILURE);
}
}
// TODO: Implement a working signal handler
void initSignals()
{
signal(SIGCHLD, SIG_IGN);
signal(SIGHUP, SIG_IGN);
}
void setFilePermissions()
{
umask(0);
}
void moveToSafeDirectory(const char *pSafeDir)
{
if (chdir(pSafeDir) < 0) {
errorf("Could not change working directory to: %s\n", pSafeDir);
exit(EXIT_FAILURE);
}
else {
infof("Changed working directory to: %s\n", pSafeDir);
}
}
void closeAllOpenFileDescrtiptors()
{
for (int x = sysconf(_SC_OPEN_MAX); 0 < x; x--)
{
close(x);
}
stdin = fopen(DEV_NULL_DIR, "r");
stdout = fopen(DEV_NULL_DIR, "w+");
stderr = fopen(DEV_NULL_DIR, "w+");
}
static void init(bool pDaemon, const char *pLogName, const char *pSafeDir)
{
if (pDaemon) {
forkChildAndExit();
becomeSessionLeader();
initSignals();
forkChildAndExit(); // guarantee daemon is detached from a terminal permanently
setFilePermissions();
closeAllOpenFileDescrtiptors();
}
// always do the following
initLog(pLogName);
moveToSafeDirectory(pSafeDir);
if (pDaemon) {
notice("Started as daemon.");
}
else {
notice("Started as interactive program.");
}
}
static void cleanup()
{
notice("Program terminated.");
stopLog();
}
int main(int argc, char **argv)
{
bool daemon = true;
const char *logName = argv[0];
const char *safeDir = SAFE_DIR;
int sleepDelay = SLEEP_DELAY;
args_param_t args_param_list[] =
{
{"-i", &daemon, argsBoolFalse },
{"--interactive", &daemon, argsBoolFalse },
{"-d", &daemon, argsBoolTrue },
{"--daemon", &daemon, argsBoolTrue },
{"-s", &sleepDelay, argsInteger },
{"--sleep", &sleepDelay, argsInteger },
{"-l", &logName, argsString },
{"--log", &logName, argsString },
{"--dir", &safeDir, argsString },
ARGS_DONE
};
argsProcess(argc, argv, args_param_list);
init(daemon, logName, safeDir);
infof("Sleep delay set to %d second(s).", sleepDelay);
// run mainLoop() before calling sleep so that local control responds right away
// if done is true after the first execution, the program will exit right away
bool done = mainLoop(argc, argv);
while (!done) {
sleep(sleepDelay);
done = mainLoop(argc, argv);
}
cleanup();
return EXIT_SUCCESS;
}