xref: /third_party/pulseaudio/src/pulsecore/pid.c (revision 53a5a1b3)
1/***
2  This file is part of PulseAudio.
3
4  Copyright 2004-2006 Lennart Poettering
5  Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
6
7  PulseAudio is free software; you can redistribute it and/or modify
8  it under the terms of the GNU Lesser General Public License as
9  published by the Free Software Foundation; either version 2.1 of the
10  License, or (at your option) any later version.
11
12  PulseAudio is distributed in the hope that it will be useful, but
13  WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  General Public License for more details.
16
17  You should have received a copy of the GNU Lesser General Public
18  License along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
19***/
20
21#ifdef HAVE_CONFIG_H
22#include <config.h>
23#endif
24
25#include <fcntl.h>
26#include <unistd.h>
27#include <errno.h>
28#include <sys/types.h>
29#include <sys/stat.h>
30#include <string.h>
31#include <stdio.h>
32#include <stdlib.h>
33#include <limits.h>
34#include <signal.h>
35
36#ifdef HAVE_WINDOWS_H
37#include <windows.h>
38#endif
39
40#include <pulse/xmalloc.h>
41
42#include <pulsecore/core-error.h>
43#include <pulsecore/core-util.h>
44#include <pulsecore/log.h>
45#include <pulsecore/macro.h>
46
47#include "pid.h"
48
49/* Read the PID data from the file descriptor fd, and return it. If no
50 * pid could be read, return 0, on failure (pid_t) -1 */
51static pid_t read_pid(const char *fn, int fd) {
52    ssize_t r;
53    char t[20], *e;
54    uint32_t pid;
55
56    pa_assert(fn);
57    pa_assert(fd >= 0);
58
59    if ((r = pa_loop_read(fd, t, sizeof(t)-1, NULL)) < 0) {
60        pa_log_warn("Failed to read PID file '%s': %s", fn, pa_cstrerror(errno));
61        return (pid_t) -1;
62    }
63
64    if (r == 0)
65        return (pid_t) 0;
66
67    t[r] = 0;
68    if ((e = strchr(t, '\n')))
69        *e = 0;
70
71    if (pa_atou(t, &pid) < 0) {
72        pa_log_warn("Failed to parse PID file '%s'", fn);
73        errno = EINVAL;
74        return (pid_t) -1;
75    }
76
77    return (pid_t) pid;
78}
79
80static int open_pid_file(const char *fn, int mode) {
81    int fd;
82
83    pa_assert(fn);
84
85    for (;;) {
86        struct stat st;
87
88        if ((fd = pa_open_cloexec(fn, mode
89#ifdef O_NOFOLLOW
90                       |O_NOFOLLOW
91#endif
92                       , S_IRUSR|S_IWUSR
93             )) < 0) {
94            if (mode != O_RDONLY || errno != ENOENT)
95                pa_log_warn("Failed to open PID file '%s': %s", fn, pa_cstrerror(errno));
96            goto fail;
97        }
98
99        /* Try to lock the file. If that fails, go without */
100        if (pa_lock_fd(fd, 1) < 0)
101            goto fail;
102
103        if (fstat(fd, &st) < 0) {
104            pa_log_warn("Failed to fstat() PID file '%s': %s", fn, pa_cstrerror(errno));
105            goto fail;
106        }
107
108        /* Does the file still exist in the file system? When yes, we're done, otherwise restart */
109        if (st.st_nlink >= 1)
110            break;
111
112        if (pa_lock_fd(fd, 0) < 0)
113            goto fail;
114
115        if (pa_close(fd) < 0) {
116            pa_log_warn("Failed to close file '%s': %s", fn, pa_cstrerror(errno));
117            fd = -1;
118            goto fail;
119        }
120    }
121
122    return fd;
123
124fail:
125
126    if (fd >= 0) {
127        int saved_errno = errno;
128        pa_lock_fd(fd, 0);
129        pa_close(fd);
130        errno = saved_errno;
131    }
132
133    return -1;
134}
135
136static int proc_name_ours(pid_t pid, const char *procname) {
137#ifdef __linux__
138    char bn[PATH_MAX];
139    FILE *f;
140
141    pa_snprintf(bn, sizeof(bn), "/proc/%lu/stat", (unsigned long) pid);
142
143    if (!(f = pa_fopen_cloexec(bn, "r"))) {
144        pa_log_info("Failed to open %s: %s", bn, pa_cstrerror(errno));
145        return -1;
146    } else {
147        char *expected;
148        bool good;
149        char stored[64];
150
151        if (!(fgets(stored, sizeof(stored), f))) {
152            int saved_errno = feof(f) ? EINVAL : errno;
153            pa_log_info("Failed to read from %s: %s", bn, feof(f) ? "EOF" : pa_cstrerror(errno));
154            fclose(f);
155
156            errno = saved_errno;
157            return -1;
158        }
159
160        fclose(f);
161
162        expected = pa_sprintf_malloc("%lu (%s)", (unsigned long) pid, procname);
163        good = pa_startswith(stored, expected);
164        pa_xfree(expected);
165
166/*#if !defined(__OPTIMIZE__)*/
167        if (!good) {
168            /* libtool likes to rename our binary names ... */
169            expected = pa_sprintf_malloc("%lu (lt-%s)", (unsigned long) pid, procname);
170            good = pa_startswith(stored, expected);
171            pa_xfree(expected);
172        }
173/*#endif*/
174
175        return good;
176    }
177#else
178
179    return 1;
180#endif
181
182}
183
184/* Create a new PID file for the current process. */
185int pa_pid_file_create(const char *procname) {
186    int fd = -1;
187    int ret = -1;
188    char t[20];
189    pid_t pid;
190    size_t l;
191    char *fn;
192
193#ifdef OS_IS_WIN32
194    HANDLE process;
195#endif
196
197    if (!(fn = pa_runtime_path("pid")))
198        goto fail;
199
200    if ((fd = open_pid_file(fn, O_CREAT|O_RDWR)) < 0)
201        goto fail;
202
203    if ((pid = read_pid(fn, fd)) == (pid_t) -1)
204        pa_log_warn("Corrupt PID file, overwriting.");
205    else if (pid > 0) {
206        int ours = 1;
207
208#ifdef OS_IS_WIN32
209        if ((process = OpenProcess(PROCESS_QUERY_INFORMATION, false, pid)) != NULL) {
210            CloseHandle(process);
211#else
212        if (kill(pid, 0) >= 0 || errno != ESRCH) {
213#endif
214
215            if (procname)
216                if ((ours = proc_name_ours(pid, procname)) < 0) {
217                    pa_log_warn("Could not check to see if pid %lu is a pulseaudio process. "
218                                "Assuming it is and the daemon is already running.", (unsigned long) pid);
219                    goto fail;
220                }
221
222            if (ours) {
223                pa_log("Daemon already running.");
224                ret = 1;
225                goto fail;
226            }
227        }
228
229        pa_log_warn("Stale PID file, overwriting.");
230    }
231
232    /* Overwrite the current PID file */
233    if (lseek(fd, (off_t) 0, SEEK_SET) == (off_t) -1 || ftruncate(fd, (off_t) 0) < 0) {
234        pa_log("Failed to truncate PID file '%s': %s", fn, pa_cstrerror(errno));
235        goto fail;
236    }
237
238    pa_snprintf(t, sizeof(t), "%lu\n", (unsigned long) getpid());
239    l = strlen(t);
240
241    if (pa_loop_write(fd, t, l, NULL) != (ssize_t) l) {
242        pa_log("Failed to write PID file.");
243        goto fail;
244    }
245
246    ret = 0;
247
248fail:
249    if (fd >= 0) {
250        pa_lock_fd(fd, 0);
251
252        if (pa_close(fd) < 0) {
253            pa_log("Failed to close PID file '%s': %s", fn, pa_cstrerror(errno));
254            ret = -1;
255        }
256    }
257
258    pa_xfree(fn);
259
260    return ret;
261}
262
263/* Remove the PID file, if it is ours */
264int pa_pid_file_remove(void) {
265    int fd = -1;
266    char *fn;
267    int ret = -1;
268    pid_t pid;
269
270    if (!(fn = pa_runtime_path("pid")))
271        goto fail;
272
273    if ((fd = open_pid_file(fn, O_RDWR)) < 0) {
274        pa_log_warn("Failed to open PID file '%s': %s", fn, pa_cstrerror(errno));
275        goto fail;
276    }
277
278    if ((pid = read_pid(fn, fd)) == (pid_t) -1)
279        goto fail;
280
281    if (pid != getpid()) {
282        pa_log("PID file '%s' not mine!", fn);
283        goto fail;
284    }
285
286    if (ftruncate(fd, (off_t) 0) < 0) {
287        pa_log_warn("Failed to truncate PID file '%s': %s", fn, pa_cstrerror(errno));
288        goto fail;
289    }
290
291#ifdef OS_IS_WIN32
292    pa_lock_fd(fd, 0);
293    pa_close(fd);
294    fd = -1;
295#endif
296
297    if (unlink(fn) < 0) {
298        pa_log_warn("Failed to remove PID file '%s': %s", fn, pa_cstrerror(errno));
299        goto fail;
300    }
301
302    ret = 0;
303
304fail:
305
306    if (fd >= 0) {
307        pa_lock_fd(fd, 0);
308
309        if (pa_close(fd) < 0) {
310            pa_log_warn("Failed to close PID file '%s': %s", fn, pa_cstrerror(errno));
311            ret = -1;
312        }
313    }
314
315    pa_xfree(fn);
316
317    return ret;
318}
319
320/* Check whether the daemon is currently running, i.e. if a PID file
321 * exists and the PID therein too. Returns 0 on success, -1
322 * otherwise. If pid is non-NULL and a running daemon was found,
323 * return its PID therein */
324int pa_pid_file_check_running(pid_t *pid, const char *procname) {
325    return pa_pid_file_kill(0, pid, procname);
326}
327
328#ifndef OS_IS_WIN32
329
330/* Kill a current running daemon. Return non-zero on success, -1
331 * otherwise. If successful *pid contains the PID of the daemon
332 * process. */
333int pa_pid_file_kill(int sig, pid_t *pid, const char *procname) {
334    int fd = -1;
335    char *fn;
336    int ret = -1;
337    pid_t _pid;
338#ifdef __linux__
339    char *e = NULL;
340#endif
341
342    if (!pid)
343        pid = &_pid;
344
345    if (!(fn = pa_runtime_path("pid")))
346        goto fail;
347
348    if ((fd = open_pid_file(fn, O_RDONLY)) < 0) {
349
350        if (errno == ENOENT)
351            errno = ESRCH;
352
353        goto fail;
354    }
355
356    if ((*pid = read_pid(fn, fd)) == (pid_t) -1)
357        goto fail;
358
359    if (procname) {
360        int ours;
361
362        if ((ours = proc_name_ours(*pid, procname)) < 0)
363            goto fail;
364
365        if (!ours) {
366            errno = ESRCH;
367            goto fail;
368        }
369    }
370
371    ret = kill(*pid, sig);
372
373fail:
374
375    if (fd >= 0) {
376        int saved_errno = errno;
377        pa_lock_fd(fd, 0);
378        pa_close(fd);
379        errno = saved_errno;
380    }
381
382#ifdef __linux__
383    pa_xfree(e);
384#endif
385
386    pa_xfree(fn);
387
388    return ret;
389
390}
391
392#else /* OS_IS_WIN32 */
393
394int pa_pid_file_kill(int sig, pid_t *pid, const char *exe_name) {
395    return -1;
396}
397
398#endif
399