request for added feature be commited: duende pid file
Yarin
yarin at warpmail.net
Mon Dec 27 16:22:42 EST 2010
Mr. Trenholme,
I noticed that your duende daemon doesn't save itself a pid file, which makes handling it harder.
Specifically, the service scripts included in your latest release, have to do some really hackish things to shut down the daemon. :-(
To fix this, I've added a PID file feature to the duende. I figured, all good daemons have it, why doesn't yours? :-)
I've successfully compiled and tested the code, and am using it myself, so it's ready to go.
Basically, I just added a some chunks near the start of the main() routine, but modified it a hair to accommodate the changes.
Besides that, I replaced all of the "argv[1]" occurrences with "argv[exec_argv_offset]" beyond the first for() loop in main().
(Note: I also preserved your formatting style is the new code)
Below is the proposed new code for the main() function of the file ./tools/duende.c:
int main(int argc, char **argv) {
int exit_status;
pid_t pid, log_pid;
int stream1[2]; /* Used for piping */
int exec_argv_offset = 1; /* Also used to determine PID writing */
if(argv[0] == NULL || argv[1] == NULL) {
printf("Usage: duende (--pid=/path/to/file) [program] [arguments]\n");
exit(1);
}
if(!strncasecmp(argv[1],"--pid=",6)) {
if(argv[2] == NULL) {
printf("Usage: duende (--pid=/path/to/file) [program] [arguments]\n");
exit(1);
}
exec_argv_offset = 2;
}
/* Let children know that duende is running */
if(setenv("DUENDE_IS_RUNNING","1",0) != 0) {
printf("FATAL: Unable to set environment variable\n");
exit(1);
}
/* The parent immediately exits */
if(fork() != 0)
exit(0);
/* The child becomes a full-fledged daemon */
setpgid(0,0); /* No longer visible in 'ps' without the 'auxw' argument */
/* Write our PID to a file if the user so desires us to */
if(exec_argv_offset == 2) {
FILE *fp_pid = fopen(argv[1] + 6,"w");
if(!fp_pid) {
syslog(LOG_ALERT,"Fatal writing, to PID file, error\n");
exit(1);
}
unsigned int local_pid = getpid();
fprintf(fp_pid,"%u",local_pid);
fclose(fp_pid);
}
/* Sysadmins expect HUP to reload, so we set that up */
signal(SIGHUP,handle_hup);
signal(SIGTERM,handle_term);
signal(SIGINT,handle_term);
pid = 0; log_pid = 0;
for(;;) {
if(pipe(stream1) != 0) {
syslog(LOG_ALERT,"Fatal pipe error");
exit(3);
}
pid = fork();
if(pid == -1) {
syslog(LOG_ALERT,"Fatal pid error");
exit(1);
}
if(pid == 0) { /* Child; this one execs maradns */
close(stream1[0]);
/* Dup the standard output */
if(dup2(stream1[1],1) != 1) {
syslog(LOG_ALERT,"Fatal dup2 error 1");
exit(4);
}
/* And the standard error */
if(dup2(stream1[1],2) != 2) {
syslog(LOG_ALERT,"Fatal dup2 error 2");
exit(5);
}
argv[0] = argv[exec_argv_offset];
execvp(argv[exec_argv_offset],argv + exec_argv_offset);
/* OK, not found */
printf("duende: %s: Command can't run, terminating\n",argv[exec_argv_offset]);
syslog(LOG_ALERT,"Command can't run, terminating\n");
exit(1);
}
/* Parent */
close(stream1[1]);
log_pid = fork();
if(log_pid == 0) { /* Child to syslog all of MaraDNS' output */
argv[0] = "duende-log-helper";
log_helper(argv[exec_argv_offset],stream1[0]);
syslog(LOG_ALERT,"log_helper finished, terminating\n");
exit(1);
}
for(;;) {
/* If we got a HUP signal, send it to the child */
if(got_hup_signal == 1) {
kill(pid,SIGHUP);
got_hup_signal = 0;
}
/* If we got a TERM or INT signal, send it to the children
then exit ourselves */
else if(got_term_signal == 1) {
/* XXX: make sure term really stops the children */
kill(pid,SIGTERM);
kill(log_pid,SIGTERM);
syslog(LOG_ALERT,"got term signal, terminating\n");
exit(0);
}
sleep(1);
if(waitpid(pid,&exit_status,WNOHANG) == pid) { /* If child ended */
handle_child_exited(exit_status,log_pid,pid);
close(stream1[0]);
break; /* Out of the inner loop; re-start Mara */
}
/* If logger terminated */
if(waitpid(log_pid,&exit_status,WNOHANG) == log_pid) {
handle_child_exited(exit_status,pid,log_pid);
close(stream1[0]);
break; /* Out of the inner loop; re-start Mara */
}
}
}
}
Thank you,
Yarin Licht
More information about the list
mailing list