From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by befuddled.reisers.ca (Postfix, from userid 65534) id D49471EFB1F; Wed, 20 Jul 2016 19:35:43 -0400 (EDT) Received: from hera.aquilenet.fr (hera.aquilenet.fr [141.255.128.1]) by befuddled.reisers.ca (Postfix) with ESMTP id 28BFD1EFB15 for ; Wed, 20 Jul 2016 19:35:42 -0400 (EDT) Received: from localhost (localhost [127.0.0.1]) by hera.aquilenet.fr (Postfix) with ESMTP id E530C8912 for ; Thu, 21 Jul 2016 01:35:31 +0200 (CEST) Received: from hera.aquilenet.fr ([127.0.0.1]) by localhost (hera.aquilenet.fr [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 9hw1Q0YOP1Vh for ; Thu, 21 Jul 2016 01:35:31 +0200 (CEST) Received: from var.youpi.perso.aquilenet.fr (unknown [IPv6:2a01:cb19:1af:4600:3602:86ff:fe2c:6a19]) by hera.aquilenet.fr (Postfix) with ESMTPSA id A787888AF for ; Thu, 21 Jul 2016 01:35:31 +0200 (CEST) Received: from samy by var.youpi.perso.aquilenet.fr with local (Exim 4.87) (envelope-from ) id 1bQ11X-0002pH-Oe for speakup@linux-speakup.org; Thu, 21 Jul 2016 01:35:31 +0200 Date: Thu, 21 Jul 2016 01:35:31 +0200 From: Samuel Thibault To: "Speakup is a screen review system for Linux." Subject: Re: espeakup release coming soon Message-ID: <20160720233531.GC4169@var.home> References: <20160306185459.GA6674@linux1> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="5mCyUwZo2JvN/JJP" Content-Disposition: inline In-Reply-To: User-Agent: Mutt/1.5.21+34 (58baf7c9f32f) (2010-12-30) X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 X-BeenThere: speakup@linux-speakup.org X-Mailman-Version: 2.1.22 Precedence: list List-Id: "Speakup is a screen review system for Linux." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 20 Jul 2016 23:35:43 -0000 --5mCyUwZo2JvN/JJP Content-Type: text/plain; charset=us-ascii Content-Disposition: inline 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 --5mCyUwZo2JvN/JJP Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename=daemon --- a/espeakup.c +++ b/espeakup.c @@ -24,6 +24,8 @@ #include #include #include +#include +#include #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; } --5mCyUwZo2JvN/JJP--