src/server/daemon/main.c

changeset 443
ef3c8a0e1fee
parent 434
ff576305ae6e
child 444
96d2ba2f28db
equal deleted inserted replaced
442:05c2b62448b1 443:ef3c8a0e1fee
33 #include <signal.h> 33 #include <signal.h>
34 #include <errno.h> 34 #include <errno.h>
35 #include <pthread.h> 35 #include <pthread.h>
36 #include <fcntl.h> 36 #include <fcntl.h>
37 #include <poll.h> 37 #include <poll.h>
38 #include <semaphore.h>
38 39
39 #include "../util/pool.h" 40 #include "../util/pool.h"
40 #include "../public/nsapi.h" 41 #include "../public/nsapi.h"
41 #include "../util/plist.h" 42 #include "../util/plist.h"
42 #include "../util/date.h" 43 #include "../util/date.h"
110 static char log_pipe_stdout_buf[LOG_THREAD_READ_BUF]; 111 static char log_pipe_stdout_buf[LOG_THREAD_READ_BUF];
111 static char log_pipe_stderr_buf[LOG_THREAD_READ_BUF]; 112 static char log_pipe_stderr_buf[LOG_THREAD_READ_BUF];
112 static size_t log_pipe_stdout_tmp_pos = 0; 113 static size_t log_pipe_stdout_tmp_pos = 0;
113 static size_t log_pipe_stderr_tmp_pos = 0; 114 static size_t log_pipe_stderr_tmp_pos = 0;
114 115
116 // pipe used for startup
117 // after fork, the parent process waits, until the daemon is fully started
118 // to get potential error and log messages
119 static int daemon_start_pipe[2];
120
121 // used for sending log messages from the daemon process to the parent process
122 // in the startup phase
123 static int parent_log_pipe[2];
124
125 static LogDup startup_log;
126
127 static void finish_daemon_startup(int status) {
128 if(status != 0) {
129 log_ereport(LOG_FAILURE, "daemon startup failed");
130 if(status > 127) {
131 status = 127;
132 }
133 }
134 char s = (char)status;
135
136 // notify parent process about startup status
137 write(daemon_start_pipe[1], &s, 1);
138 close(daemon_start_pipe[1]);
139
140 // remove logdup
141 log_remove_logdup(&startup_log);
142 close(parent_log_pipe[0]);
143 close(parent_log_pipe[1]);
144 }
145
115 static int log_pipe(const char *name, int fd, char *buf, size_t *pos) { 146 static int log_pipe(const char *name, int fd, char *buf, size_t *pos) {
116 ssize_t r = read(fd, log_pipe_readbuf, 2); 147 ssize_t r = read(fd, log_pipe_readbuf, 2);
117 if(r <= 0) { 148 if(r <= 0) {
118 return 1; 149 return r == 0 ? 0 : 1;
119 } 150 }
120 151
121 char *tmp = buf; 152 char *tmp = buf;
122 int tmplen = *pos; 153 int tmplen = *pos;
123 154
168 } 199 }
169 200
170 // check stdout 201 // check stdout
171 if(fds[0].revents & POLLIN) { 202 if(fds[0].revents & POLLIN) {
172 if(log_pipe("stdout", fds[0].fd, log_pipe_stdout_buf, &log_pipe_stdout_tmp_pos)) { 203 if(log_pipe("stdout", fds[0].fd, log_pipe_stdout_buf, &log_pipe_stdout_tmp_pos)) {
204 log_ereport(LOG_WARN, "log_pipe stdout failed");
173 break; 205 break;
174 } 206 }
175 } 207 }
176 208
177 // check stderr 209 // check stderr
178 if(fds[1].revents & POLLIN) { 210 if(fds[1].revents & POLLIN) {
179 if(log_pipe("stderr", fds[0].fd, log_pipe_stderr_buf, &log_pipe_stderr_tmp_pos)) { 211 if(log_pipe("stderr", fds[0].fd, log_pipe_stderr_buf, &log_pipe_stderr_tmp_pos)) {
212 log_ereport(LOG_WARN, "log_pipe stderr failed");
180 break; 213 break;
181 } 214 }
182 } 215 }
183 } 216 }
184 217
185 log_ereport(LOG_INFORM, "log thread end"); 218 log_ereport(LOG_INFORM, "log thread end");
186 219
187 return NULL; 220 return NULL;
221 }
222
223
224 // read (blocking) 1 byte from daemon_start_pipe and return the value
225 // this is used to wait in the parent process, until the daemon process
226 // is started
227 // the returning byte is used as the process return value
228 static int main_daemon_startup_wait(void) {
229 // receive log messages from daemon
230 char buf[2048];
231 ssize_t r;
232 while((r = read(parent_log_pipe[0], buf, 2048)) > 0) {
233 ssize_t pos = 0;
234 while(r > 0) {
235 ssize_t w = write(STDOUT_FILENO, buf+pos, r-pos);
236 pos += w;
237 r -= w;
238 break;
239 }
240 }
241 // log pipe closed, daemon_start_pipe should contain the status code now
242
243 char ret;
244 if(read(daemon_start_pipe[0], &ret, 1) != 1) {
245 return 255;
246 }
247 return ret;
248 }
249
250 static void startup_log_write(void *cookie, char *msg, size_t length) {
251 write(parent_log_pipe[1], msg, length);
188 } 252 }
189 253
190 int main(int argc, char **argv) { 254 int main(int argc, char **argv) {
191 //test(); 255 //test();
192 256
197 if(p[0] == '-' && p[1] == 'c') { 261 if(p[0] == '-' && p[1] == 'c') {
198 is_daemon = 0; 262 is_daemon = 0;
199 break; 263 break;
200 } 264 }
201 } 265 }
266
267 if(init_logging()) {
268 fprintf(stderr, "OOM\n");
269 return 1;
270 }
271
272 is_daemon = 1;
202 if(is_daemon) { 273 if(is_daemon) {
274 // initialize startup pipes
275 if(pipe(daemon_start_pipe)) {
276 perror("pipe");
277 return EXIT_FAILURE;
278 }
279 if(pipe(parent_log_pipe)) {
280 perror("pipe");
281 return EXIT_FAILURE;
282 }
283
284 log_ereport(LOG_INFORM, "start daemon");
285
286 // register parent process as LogDup to receive startup log messages
287 // in the parent process, because stdout/stderr will be closed
288 // after fork
289 startup_log.write = startup_log_write;
290 log_add_logdup(&startup_log);
291
203 // create daemon 292 // create daemon
204 pid_t pid = fork(); 293 pid_t pid = fork();
205 if(pid < 0) { 294 if(pid < 0) {
295 perror("fork");
206 return EXIT_FAILURE; 296 return EXIT_FAILURE;
207 } else if(pid > 0) { 297 } else if(pid > 0) {
208 return EXIT_SUCCESS; 298 close(daemon_start_pipe[1]);
299 close(parent_log_pipe[1]);
300 return main_daemon_startup_wait();
209 } 301 }
210 302
211 if(setsid() < 0) { 303 if(setsid() < 0) {
212 fprintf(stderr, "setsid failed\n"); 304 fprintf(stderr, "setsid failed\n");
213 return EXIT_FAILURE; 305 return EXIT_FAILURE;
214 } 306 }
215 printf("start daemon\n"); 307
216 308 // close read-end of pipe in the daemon process
217 for(int i=0;i<3;i++) { 309 close(daemon_start_pipe[0]);
218 close(i);
219 }
220 310
221 // stdio redirection 311 // stdio redirection
222 // create pipes 312 // create pipes
223 if(pipe(std_out) != 0) { 313 if(pipe(std_out) != 0) {
224 perror("pipe"); 314 perror("pipe");
227 if(pipe(std_err) != 0) { 317 if(pipe(std_err) != 0) {
228 perror("pipe"); 318 perror("pipe");
229 return EXIT_FAILURE; 319 return EXIT_FAILURE;
230 } 320 }
231 321
322 for(int i=0;i<3;i++) {
323 close(i);
324 }
325
232 dup2(std_out[1], 1); 326 dup2(std_out[1], 1);
233 dup2(std_err[1], 2); 327 //dup2(std_err[1], 2);
234 close(std_err[1]); 328 close(std_out[1]);
329 //close(std_err[1]);
235 330
236 // set log thread stack size 331 // set log thread stack size
237 pthread_attr_t tattr; 332 pthread_attr_t tattr;
238 pthread_attr_init(&tattr); 333 pthread_attr_init(&tattr);
239 pthread_attr_setstacksize(&tattr, LOG_THREAD_STACK_SIZE); 334 pthread_attr_setstacksize(&tattr, LOG_THREAD_STACK_SIZE);
263 log_ereport(LOG_FAILURE, "cannot initialize server."); 358 log_ereport(LOG_FAILURE, "cannot initialize server.");
264 return EXIT_FAILURE; 359 return EXIT_FAILURE;
265 } 360 }
266 361
267 status = webserver_run(); 362 status = webserver_run();
363 if(is_daemon) {
364 finish_daemon_startup(status);
365 }
268 if(status != 0) { 366 if(status != 0) {
269 log_ereport(LOG_FAILURE, "cannot run server."); 367 log_ereport(LOG_FAILURE, "cannot run server.");
270 return EXIT_FAILURE; 368 return EXIT_FAILURE;
271 } 369 }
272 370

mercurial