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