Code sync
[external/libdaemon.git] / examples / testd.c
1 /***
2   This file is part of libdaemon.
3
4   Copyright 2003-2008 Lennart Poettering
5
6   libdaemon is free software; you can redistribute it and/or modify
7   it under the terms of the GNU Lesser General Public License as
8   published by the Free Software Foundation, either version 2.1 of the
9   License, or (at your option) any later version.
10
11   libdaemon is distributed in the hope that it will be useful, but
12   WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14   Lesser General Public License for more details.
15
16   You should have received a copy of the GNU Lesser General Public
17   License along with libdaemon. If not, see
18   <http://www.gnu.org/licenses/>.
19 ***/
20
21 #include <signal.h>
22 #include <errno.h>
23 #include <string.h>
24 #include <sys/types.h>
25 #include <sys/time.h>
26 #include <sys/unistd.h>
27 #include <sys/select.h>
28
29 #include <libdaemon/dfork.h>
30 #include <libdaemon/dsignal.h>
31 #include <libdaemon/dlog.h>
32 #include <libdaemon/dpid.h>
33 #include <libdaemon/dexec.h>
34
35 int main(int argc, char *argv[]) {
36     pid_t pid;
37
38     /* Reset signal handlers */
39     if (daemon_reset_sigs(-1) < 0) {
40         daemon_log(LOG_ERR, "Failed to reset all signal handlers: %s", strerror(errno));
41         return 1;
42     }
43
44     /* Unblock signals */
45     if (daemon_unblock_sigs(-1) < 0) {
46         daemon_log(LOG_ERR, "Failed to unblock all signals: %s", strerror(errno));
47         return 1;
48     }
49
50     /* Set indetification string for the daemon for both syslog and PID file */
51     daemon_pid_file_ident = daemon_log_ident = daemon_ident_from_argv0(argv[0]);
52
53     /* Check if we are called with -k parameter */
54     if (argc >= 2 && !strcmp(argv[1], "-k")) {
55         int ret;
56
57         /* Kill daemon with SIGTERM */
58
59         /* Check if the new function daemon_pid_file_kill_wait() is available, if it is, use it. */
60         if ((ret = daemon_pid_file_kill_wait(SIGTERM, 5)) < 0)
61             daemon_log(LOG_WARNING, "Failed to kill daemon: %s", strerror(errno));
62
63         return ret < 0 ? 1 : 0;
64     }
65
66     /* Check that the daemon is not rung twice a the same time */
67     if ((pid = daemon_pid_file_is_running()) >= 0) {
68         daemon_log(LOG_ERR, "Daemon already running on PID file %u", pid);
69         return 1;
70     }
71
72     /* Prepare for return value passing from the initialization procedure of the daemon process */
73     if (daemon_retval_init() < 0) {
74         daemon_log(LOG_ERR, "Failed to create pipe.");
75         return 1;
76     }
77
78     /* Do the fork */
79     if ((pid = daemon_fork()) < 0) {
80
81         /* Exit on error */
82         daemon_retval_done();
83         return 1;
84
85     } else if (pid) { /* The parent */
86         int ret;
87
88         /* Wait for 20 seconds for the return value passed from the daemon process */
89         if ((ret = daemon_retval_wait(20)) < 0) {
90             daemon_log(LOG_ERR, "Could not recieve return value from daemon process: %s", strerror(errno));
91             return 255;
92         }
93
94         daemon_log(ret != 0 ? LOG_ERR : LOG_INFO, "Daemon returned %i as return value.", ret);
95         return ret;
96
97     } else { /* The daemon */
98         int fd, quit = 0;
99         fd_set fds;
100
101         /* Close FDs */
102         if (daemon_close_all(-1) < 0) {
103             daemon_log(LOG_ERR, "Failed to close all file descriptors: %s", strerror(errno));
104
105             /* Send the error condition to the parent process */
106             daemon_retval_send(1);
107             goto finish;
108         }
109
110         /* Create the PID file */
111         if (daemon_pid_file_create() < 0) {
112             daemon_log(LOG_ERR, "Could not create PID file (%s).", strerror(errno));
113             daemon_retval_send(2);
114             goto finish;
115         }
116
117         /* Initialize signal handling */
118         if (daemon_signal_init(SIGINT, SIGTERM, SIGQUIT, SIGHUP, 0) < 0) {
119             daemon_log(LOG_ERR, "Could not register signal handlers (%s).", strerror(errno));
120             daemon_retval_send(3);
121             goto finish;
122         }
123
124         /*... do some further init work here */
125
126
127         /* Send OK to parent process */
128         daemon_retval_send(0);
129
130         daemon_log(LOG_INFO, "Sucessfully started");
131
132         /* Prepare for select() on the signal fd */
133         FD_ZERO(&fds);
134         fd = daemon_signal_fd();
135         FD_SET(fd, &fds);
136
137         while (!quit) {
138             fd_set fds2 = fds;
139
140             /* Wait for an incoming signal */
141             if (select(FD_SETSIZE, &fds2, 0, 0, 0) < 0) {
142
143                 /* If we've been interrupted by an incoming signal, continue */
144                 if (errno == EINTR)
145                     continue;
146
147                 daemon_log(LOG_ERR, "select(): %s", strerror(errno));
148                 break;
149             }
150
151             /* Check if a signal has been recieved */
152             if (FD_ISSET(fd, &fds2)) {
153                 int sig;
154
155                 /* Get signal */
156                 if ((sig = daemon_signal_next()) <= 0) {
157                     daemon_log(LOG_ERR, "daemon_signal_next() failed: %s", strerror(errno));
158                     break;
159                 }
160
161                 /* Dispatch signal */
162                 switch (sig) {
163
164                     case SIGINT:
165                     case SIGQUIT:
166                     case SIGTERM:
167                         daemon_log(LOG_WARNING, "Got SIGINT, SIGQUIT or SIGTERM.");
168                         quit = 1;
169                         break;
170
171                     case SIGHUP:
172                         daemon_log(LOG_INFO, "Got a HUP");
173                         daemon_exec("/", NULL, "/bin/ls", "ls", (char*) NULL);
174                         break;
175
176                 }
177             }
178         }
179
180         /* Do a cleanup */
181 finish:
182         daemon_log(LOG_INFO, "Exiting...");
183         daemon_retval_send(255);
184         daemon_signal_done();
185         daemon_pid_file_remove();
186
187         return 0;
188     }
189 }