Skip to content

Commit

Permalink
pulse: create pidfile
Browse files Browse the repository at this point in the history
Create a pidfile and take a lock on it. Prevent starting multiple
instances for the same VM.

Fixes QubesOS/qubes-issues#5760
  • Loading branch information
marmarek committed Apr 5, 2020
1 parent ad3b39c commit dff304a
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 0 deletions.
59 changes: 59 additions & 0 deletions pulse/pacat-simple-vchan.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
#include <config.h>
#endif

#define _GNU_SOURCE
#include <stdio.h>
#include <unistd.h>
#include <string.h>
Expand All @@ -52,6 +53,7 @@
#include <stdarg.h>
#include <assert.h>
#include <sys/time.h>
#include <sys/file.h>

#include <pulse/pulseaudio.h>
#include <pulse/error.h>
Expand Down Expand Up @@ -580,6 +582,54 @@ static void context_state_callback(pa_context *c, void *userdata) {

}

/*
* domid: remote end domid (IN)
* pidfile_path: path to the created file (OUT)
* pidfile_fd: open FD of the pidfile, used also as a lockfile (OUT)
*
* Returns: 0 on success -1 otherwise
*/
static int create_pidfile(int domid, char **pidfile_path, int *pidfile_fd)
{
int fd, ret;
char pid_s[16];

if (asprintf(pidfile_path, PACAT_PIDFILE_PATH_TPL, domid) < 0) {
pacat_log("Failed to construct pidfile path, out of memory?");
return -1;
}

fd = open(*pidfile_path, O_RDWR | O_CREAT | O_CLOEXEC, 0644);
if (fd < 0) {
pacat_log("Failed to create pidfile %s: %s", *pidfile_path, strerror(errno));
return -1;
}

if (flock(fd, LOCK_EX | LOCK_NB) < 0) {
if (errno == EWOULDBLOCK) {
ret = read(fd, pid_s, sizeof(pid_s)-1);
if (ret <= 0) {
pacat_log("Another instance of pacat-simple-vchan is already running for this VM, but failed to get its PID");
} else {
pid_s[ret] = '\0';
if (pid_s[ret-1] == '\n')
pid_s[ret-1] = '\0';
pacat_log("Another instance of pacat-simple-vchan is already running for this VM (PID: %s)", pid_s);
}
} else {
pacat_log("Failed to obtain a lock on the pid file: %s", pa_strerror(errno));
}
close(fd);
return -1;
}

ret = snprintf(pid_s, sizeof(pid_s), "%d\n", getpid());
write(fd, pid_s, ret);

*pidfile_fd = fd;
return 0;
}

static void check_vchan_eof_timer(pa_mainloop_api*a, pa_time_event* e,
const struct timeval *UNUSED(tv), void *userdata)
{
Expand Down Expand Up @@ -607,6 +657,8 @@ int main(int argc, char *argv[])
char *server = NULL;
char *domname = NULL;
int domid = -1;
char *pidfile_path;
int pidfile_fd;
int i;

if (argc <= 2) {
Expand Down Expand Up @@ -640,6 +692,10 @@ int main(int argc, char *argv[])
exit(1);
}

if (create_pidfile(domid, &pidfile_path, &pidfile_fd) < 0)
/* error already printed by create_pidfile() */
exit(1);

memset(&u, 0, sizeof(u));
u.ret = 1;

Expand Down Expand Up @@ -786,5 +842,8 @@ int main(int argc, char *argv[])
pa_proplist_free(u.proplist);

g_mutex_clear(&u.prop_mutex);

unlink(pidfile_path);
close(pidfile_fd);
return u.ret;
}
2 changes: 2 additions & 0 deletions pulse/pacat-simple-vchan.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
#include <dbus/dbus-glib-bindings.h>
#include <libvchan.h>

#define PACAT_PIDFILE_PATH_TPL "/var/run/qubes/pacat.%d"

struct userdata {
pa_mainloop_api *mainloop_api;
GMainLoop *loop;
Expand Down

0 comments on commit dff304a

Please sign in to comment.