Hello, currently espeakup uses daemon() to do the daemonizing stuff. Unfortunately, daemon() does things not very appropriately, and there is notably a delay between the parent exit()ing and the child writing the pid file. The attached patch reimplements it properly, espeakup then notably plays much more nicely with systemd. Samuel
--- a/espeakup.c +++ b/espeakup.c @@ -24,6 +24,8 @@ #include <string.h> #include <unistd.h> #include <pthread.h> +#include <fcntl.h> +#include <sys/file.h> #include "espeakup.h" @@ -42,21 +44,94 @@ const int defaultVolume = 5; char *defaultVoice = NULL; int debug = 0; +int espeakup_start_daemon(void) +{ + int fds[2]; + pid_t pid; + char c; + + if (pipe(fds) < 0) { + perror("pipe"); + exit(1); + } + pid = fork(); + + if (pid < 0) { + perror("fork"); + exit(1); + } + if (pid) { + /* Parent, just wait for daemon */ + if (read(fds[0], &c, 1) < 0) { + printf("Espeakup is already running!\n"); + exit(1); + } + exit(c); + } + + + /* Child, create new session */ + setsid(); + pid = fork(); + if (pid) + /* Intermediate child, just exit */ + exit(0); + + /* Child */ + if (chdir("/") < 0) { + c = 1; + (void) write(fds[1], &c, 1); + exit(1); + } + return fds[1]; +} + int espeakup_is_running(void) { - int rc; - FILE *pidFile; + int pidFile; + int n; + char s[16]; pid_t pid; - rc = 0; - pidFile = fopen(pidPath, "r"); - if (pidFile) { - fscanf(pidFile, "%d", &pid); - fclose(pidFile); - if (!kill(pid, 0) || errno != ESRCH) - rc = 1; + pidFile = open(pidPath, O_RDWR|O_CREAT, 0666); + if (pidFile < 0) { + printf("Can not work with the pid file %s: %s\n", pidPath, strerror(errno)); + return -1; + } + + if (flock(pidFile, LOCK_EX) < 0) { + printf("Can not lock the pid file %s: %s\n", pidPath, strerror(errno)); + goto error; + } + n = read(pidFile, s, sizeof(s)-1); + if (n < 0) { + printf("Can not read the pid file %s: %s\n", pidPath, strerror(errno)); + goto error; + } + s[n] = 0; + n = sscanf(s, "%d", &pid); + if (n == 1 && (!kill(pid, 0) || errno != ESRCH)) + { + /* Already running */ + close(pidFile); + return 1; } - return rc; + if (ftruncate(pidFile, 0) < 0) { + printf("Could not truncate the pid file %s: %s\n", pidPath, strerror(errno)); + goto error; + } + lseek(pidFile, 0, SEEK_SET); + n = snprintf(s, sizeof(s), "%d", getpid()); + if (write(pidFile, s, n) < 0) { + printf("Could not write to the pid file %s: %s\n", pidPath, strerror(errno)); + goto error; + } + close(pidFile); + return 0; + +error: + close(pidFile); + return -1; } int create_pid_file(void) @@ -91,6 +166,8 @@ void espeakup_sighandler(int sig) int main(int argc, char **argv) { + int fd, null; + char ret; pthread_t queue_thread_id; struct synth_t s = { .voice = "", @@ -99,27 +176,37 @@ int main(int argc, char **argv) /* process command line options */ process_cli(argc, argv); + if (!debug) + fd = espeakup_start_daemon(); + /* Is the espeakup daemon running? */ if (espeakup_is_running()) { printf("Espeakup is already running!\n"); - return 1; + ret = 1; + goto out; } /* open the softsynth. */ if (! open_softsynth()) { perror("Unable to open the softsynth device"); - return 3; + ret = 3; + goto out; + } + + if (!debug) { + /* Shut down stdout/stderr */ + null = open("/dev/null", O_RDWR); + dup2(null, STDIN_FILENO); + dup2(null, STDOUT_FILENO); + dup2(null, STDERR_FILENO); + if (null > 2) + close(null); } /* register signal handler */ signal(SIGINT, espeakup_sighandler); signal(SIGTERM, espeakup_sighandler); - if (!debug) { - /* become a daemon */ - daemon(0, 1); - } - /* initialize espeak */ espeak_Initialize(AUDIO_OUTPUT_PLAYBACK, 0, NULL, 0); @@ -138,19 +225,23 @@ int main(int argc, char **argv) /* Spawn our queue-processing thread. */ int err = pthread_create(&queue_thread_id, NULL, &queue_runner, &s); if (err != 0) { - return 4; + ret = 4; + goto out; } if (!debug) { - /* We are now ready, write our pid file. */ - if (create_pid_file() < 0) { - perror("Unable to create pid file"); - return 2; - } + /* We are now ready, notify parent */ + ret = 0; + (void) write(fd, &ret, 1); + close(fd); } /* run the main loop */ main_loop(&s); - return 0; + +out: + if (!debug) + (void) write(fd, &ret, 1); + return ret; }
_______________________________________________ Speakup mailing list Speakup@xxxxxxxxxxxxxxxxx http://linux-speakup.org/cgi-bin/mailman/listinfo/speakup