diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 16:03:18 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 16:03:18 +0000 |
commit | 2dd5bc6a074165ddfbd57c4bd52c2d2dac8f47a1 (patch) | |
tree | 465b29cb405d3af0b0ad50c78e1dccc636594fec /src/pulsecore/pid.c | |
parent | Initial commit. (diff) | |
download | pulseaudio-2dd5bc6a074165ddfbd57c4bd52c2d2dac8f47a1.tar.xz pulseaudio-2dd5bc6a074165ddfbd57c4bd52c2d2dac8f47a1.zip |
Adding upstream version 14.2.upstream/14.2upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/pulsecore/pid.c')
-rw-r--r-- | src/pulsecore/pid.c | 398 |
1 files changed, 398 insertions, 0 deletions
diff --git a/src/pulsecore/pid.c b/src/pulsecore/pid.c new file mode 100644 index 0000000..8749b42 --- /dev/null +++ b/src/pulsecore/pid.c @@ -0,0 +1,398 @@ +/*** + This file is part of PulseAudio. + + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, see <http://www.gnu.org/licenses/>. +***/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <fcntl.h> +#include <unistd.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <string.h> +#include <stdio.h> +#include <stdlib.h> +#include <limits.h> +#include <signal.h> + +#ifdef HAVE_WINDOWS_H +#include <windows.h> +#endif + +#include <pulse/xmalloc.h> + +#include <pulsecore/core-error.h> +#include <pulsecore/core-util.h> +#include <pulsecore/log.h> +#include <pulsecore/macro.h> + +#include "pid.h" + +/* Read the PID data from the file descriptor fd, and return it. If no + * pid could be read, return 0, on failure (pid_t) -1 */ +static pid_t read_pid(const char *fn, int fd) { + ssize_t r; + char t[20], *e; + uint32_t pid; + + pa_assert(fn); + pa_assert(fd >= 0); + + if ((r = pa_loop_read(fd, t, sizeof(t)-1, NULL)) < 0) { + pa_log_warn("Failed to read PID file '%s': %s", fn, pa_cstrerror(errno)); + return (pid_t) -1; + } + + if (r == 0) + return (pid_t) 0; + + t[r] = 0; + if ((e = strchr(t, '\n'))) + *e = 0; + + if (pa_atou(t, &pid) < 0) { + pa_log_warn("Failed to parse PID file '%s'", fn); + errno = EINVAL; + return (pid_t) -1; + } + + return (pid_t) pid; +} + +static int open_pid_file(const char *fn, int mode) { + int fd; + + pa_assert(fn); + + for (;;) { + struct stat st; + + if ((fd = pa_open_cloexec(fn, mode +#ifdef O_NOFOLLOW + |O_NOFOLLOW +#endif + , S_IRUSR|S_IWUSR + )) < 0) { + if (mode != O_RDONLY || errno != ENOENT) + pa_log_warn("Failed to open PID file '%s': %s", fn, pa_cstrerror(errno)); + goto fail; + } + + /* Try to lock the file. If that fails, go without */ + if (pa_lock_fd(fd, 1) < 0) + goto fail; + + if (fstat(fd, &st) < 0) { + pa_log_warn("Failed to fstat() PID file '%s': %s", fn, pa_cstrerror(errno)); + goto fail; + } + + /* Does the file still exist in the file system? When yes, we're done, otherwise restart */ + if (st.st_nlink >= 1) + break; + + if (pa_lock_fd(fd, 0) < 0) + goto fail; + + if (pa_close(fd) < 0) { + pa_log_warn("Failed to close file '%s': %s", fn, pa_cstrerror(errno)); + fd = -1; + goto fail; + } + } + + return fd; + +fail: + + if (fd >= 0) { + int saved_errno = errno; + pa_lock_fd(fd, 0); + pa_close(fd); + errno = saved_errno; + } + + return -1; +} + +static int proc_name_ours(pid_t pid, const char *procname) { +#ifdef __linux__ + char bn[PATH_MAX]; + FILE *f; + + pa_snprintf(bn, sizeof(bn), "/proc/%lu/stat", (unsigned long) pid); + + if (!(f = pa_fopen_cloexec(bn, "r"))) { + pa_log_info("Failed to open %s: %s", bn, pa_cstrerror(errno)); + return -1; + } else { + char *expected; + bool good; + char stored[64]; + + if (!(fgets(stored, sizeof(stored), f))) { + int saved_errno = feof(f) ? EINVAL : errno; + pa_log_info("Failed to read from %s: %s", bn, feof(f) ? "EOF" : pa_cstrerror(errno)); + fclose(f); + + errno = saved_errno; + return -1; + } + + fclose(f); + + expected = pa_sprintf_malloc("%lu (%s)", (unsigned long) pid, procname); + good = pa_startswith(stored, expected); + pa_xfree(expected); + +/*#if !defined(__OPTIMIZE__)*/ + if (!good) { + /* libtool likes to rename our binary names ... */ + expected = pa_sprintf_malloc("%lu (lt-%s)", (unsigned long) pid, procname); + good = pa_startswith(stored, expected); + pa_xfree(expected); + } +/*#endif*/ + + return good; + } +#else + + return 1; +#endif + +} + +/* Create a new PID file for the current process. */ +int pa_pid_file_create(const char *procname) { + int fd = -1; + int ret = -1; + char t[20]; + pid_t pid; + size_t l; + char *fn; + +#ifdef OS_IS_WIN32 + HANDLE process; +#endif + + if (!(fn = pa_runtime_path("pid"))) + goto fail; + + if ((fd = open_pid_file(fn, O_CREAT|O_RDWR)) < 0) + goto fail; + + if ((pid = read_pid(fn, fd)) == (pid_t) -1) + pa_log_warn("Corrupt PID file, overwriting."); + else if (pid > 0) { + int ours = 1; + +#ifdef OS_IS_WIN32 + if ((process = OpenProcess(PROCESS_QUERY_INFORMATION, false, pid)) != NULL) { + CloseHandle(process); +#else + if (kill(pid, 0) >= 0 || errno != ESRCH) { +#endif + + if (procname) + if ((ours = proc_name_ours(pid, procname)) < 0) { + pa_log_warn("Could not check to see if pid %lu is a pulseaudio process. " + "Assuming it is and the daemon is already running.", (unsigned long) pid); + goto fail; + } + + if (ours) { + pa_log("Daemon already running."); + ret = 1; + goto fail; + } + } + + pa_log_warn("Stale PID file, overwriting."); + } + + /* Overwrite the current PID file */ + if (lseek(fd, (off_t) 0, SEEK_SET) == (off_t) -1 || ftruncate(fd, (off_t) 0) < 0) { + pa_log("Failed to truncate PID file '%s': %s", fn, pa_cstrerror(errno)); + goto fail; + } + + pa_snprintf(t, sizeof(t), "%lu\n", (unsigned long) getpid()); + l = strlen(t); + + if (pa_loop_write(fd, t, l, NULL) != (ssize_t) l) { + pa_log("Failed to write PID file."); + goto fail; + } + + ret = 0; + +fail: + if (fd >= 0) { + pa_lock_fd(fd, 0); + + if (pa_close(fd) < 0) { + pa_log("Failed to close PID file '%s': %s", fn, pa_cstrerror(errno)); + ret = -1; + } + } + + pa_xfree(fn); + + return ret; +} + +/* Remove the PID file, if it is ours */ +int pa_pid_file_remove(void) { + int fd = -1; + char *fn; + int ret = -1; + pid_t pid; + + if (!(fn = pa_runtime_path("pid"))) + goto fail; + + if ((fd = open_pid_file(fn, O_RDWR)) < 0) { + pa_log_warn("Failed to open PID file '%s': %s", fn, pa_cstrerror(errno)); + goto fail; + } + + if ((pid = read_pid(fn, fd)) == (pid_t) -1) + goto fail; + + if (pid != getpid()) { + pa_log("PID file '%s' not mine!", fn); + goto fail; + } + + if (ftruncate(fd, (off_t) 0) < 0) { + pa_log_warn("Failed to truncate PID file '%s': %s", fn, pa_cstrerror(errno)); + goto fail; + } + +#ifdef OS_IS_WIN32 + pa_lock_fd(fd, 0); + pa_close(fd); + fd = -1; +#endif + + if (unlink(fn) < 0) { + pa_log_warn("Failed to remove PID file '%s': %s", fn, pa_cstrerror(errno)); + goto fail; + } + + ret = 0; + +fail: + + if (fd >= 0) { + pa_lock_fd(fd, 0); + + if (pa_close(fd) < 0) { + pa_log_warn("Failed to close PID file '%s': %s", fn, pa_cstrerror(errno)); + ret = -1; + } + } + + pa_xfree(fn); + + return ret; +} + +/* Check whether the daemon is currently running, i.e. if a PID file + * exists and the PID therein too. Returns 0 on success, -1 + * otherwise. If pid is non-NULL and a running daemon was found, + * return its PID therein */ +int pa_pid_file_check_running(pid_t *pid, const char *procname) { + return pa_pid_file_kill(0, pid, procname); +} + +#ifndef OS_IS_WIN32 + +/* Kill a current running daemon. Return non-zero on success, -1 + * otherwise. If successful *pid contains the PID of the daemon + * process. */ +int pa_pid_file_kill(int sig, pid_t *pid, const char *procname) { + int fd = -1; + char *fn; + int ret = -1; + pid_t _pid; +#ifdef __linux__ + char *e = NULL; +#endif + + if (!pid) + pid = &_pid; + + if (!(fn = pa_runtime_path("pid"))) + goto fail; + + if ((fd = open_pid_file(fn, O_RDONLY)) < 0) { + + if (errno == ENOENT) + errno = ESRCH; + + goto fail; + } + + if ((*pid = read_pid(fn, fd)) == (pid_t) -1) + goto fail; + + if (procname) { + int ours; + + if ((ours = proc_name_ours(*pid, procname)) < 0) + goto fail; + + if (!ours) { + errno = ESRCH; + goto fail; + } + } + + ret = kill(*pid, sig); + +fail: + + if (fd >= 0) { + int saved_errno = errno; + pa_lock_fd(fd, 0); + pa_close(fd); + errno = saved_errno; + } + +#ifdef __linux__ + pa_xfree(e); +#endif + + pa_xfree(fn); + + return ret; + +} + +#else /* OS_IS_WIN32 */ + +int pa_pid_file_kill(int sig, pid_t *pid, const char *exe_name) { + return -1; +} + +#endif |