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); |