/* Load an authorization cookie from file fn and store it in data. If * the cookie file doesn't exist, create it */ static int load(const char *fn, void *data, size_t length) { int fd = -1; int writable = 1; int unlock = 0, ret = -1; ssize_t r; pa_assert(fn); pa_assert(data); pa_assert(length > 0); if ((fd = pa_open_cloexec(fn, O_RDWR|O_CREAT|O_BINARY, S_IRUSR|S_IWUSR)) < 0) { if (errno != EACCES || (fd = open(fn, O_RDONLY|O_BINARY)) < 0) { pa_log_warn("Failed to open cookie file '%s': %s", fn, pa_cstrerror(errno)); goto finish; } else writable = 0; } unlock = pa_lock_fd(fd, 1) >= 0; if ((r = pa_loop_read(fd, data, length, NULL)) < 0) { pa_log("Failed to read cookie file '%s': %s", fn, pa_cstrerror(errno)); goto finish; } if ((size_t) r != length) { pa_log_debug("Got %d bytes from cookie file '%s', expected %d", (int) r, fn, (int) length); if (!writable) { pa_log_warn("Unable to write cookie to read-only file"); goto finish; } if (generate(fd, data, length) < 0) goto finish; } ret = 0; finish: if (fd >= 0) { if (unlock) pa_lock_fd(fd, 0); if (pa_close(fd) < 0) { pa_log_warn("Failed to close cookie file: %s", pa_cstrerror(errno)); ret = -1; } } return ret; }
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 save_rules(struct userdata *u) { FILE *f; int ret = -1; void *state = NULL; struct rule *rule; if (!u->modified) return 0; pa_log_info("Saving rules..."); f = u->table_file ? fopen(u->table_file, "w") : pa_open_config_file(NULL, DEFAULT_VOLUME_TABLE_FILE, NULL, &u->table_file, "w"); if (!f) { pa_log("Failed to open file '%s': %s", u->table_file, pa_cstrerror(errno)); goto finish; } pa_lock_fd(fileno(f), 1); while ((rule = pa_hashmap_iterate(u->hashmap, &state, NULL))) { unsigned i; fprintf(f, "%s\n", rule->name); if (rule->volume_is_set) { fprintf(f, "%u", rule->volume.channels); for (i = 0; i < rule->volume.channels; i++) fprintf(f, " %u", rule->volume.values[i]); } fprintf(f, "\n%s\n%s\n", rule->sink ? rule->sink : "", rule->source ? rule->source : ""); } ret = 0; u->modified = FALSE; pa_log_debug("Successfully saved rules..."); finish: if (f) { pa_lock_fd(fileno(f), 0); fclose(f); } return ret; }
/* 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; }
/* Store the specified cookie in the specified cookie file */ int pa_authkey_save(const char *fn, const void *data, size_t length) { int fd = -1; int unlock = 0, ret = -1; ssize_t r; char *p; pa_assert(fn); pa_assert(data); pa_assert(length > 0); if (!(p = normalize_path(fn))) return -2; if ((fd = pa_open_cloexec(p, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR)) < 0) { pa_log_warn("Failed to open cookie file '%s': %s", fn, pa_cstrerror(errno)); goto finish; } unlock = pa_lock_fd(fd, 1) >= 0; if ((r = pa_loop_write(fd, data, length, NULL)) < 0 || (size_t) r != length) { pa_log("Failed to read cookie file '%s': %s", fn, pa_cstrerror(errno)); goto finish; } ret = 0; finish: if (fd >= 0) { if (unlock) pa_lock_fd(fd, 0); if (pa_close(fd) < 0) { pa_log_warn("Failed to close cookie file: %s", pa_cstrerror(errno)); ret = -1; } } pa_xfree(p); return ret; }
/* 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. " "Asssuming 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; }
static int load_rules(struct userdata *u) { FILE *f; int n = 0; int ret = -1; char buf_name[256], buf_volume[256], buf_sink[256], buf_source[256]; char *ln = buf_name; f = u->table_file ? fopen(u->table_file, "r") : pa_open_config_file(NULL, DEFAULT_VOLUME_TABLE_FILE, NULL, &u->table_file, "r"); if (!f) { if (errno == ENOENT) { pa_log_info("starting with empty ruleset."); ret = 0; } else pa_log("failed to open file '%s': %s", u->table_file, pa_cstrerror(errno)); goto finish; } pa_lock_fd(fileno(f), 1); while (!feof(f)) { struct rule *rule; pa_cvolume v; pa_bool_t v_is_set; if (!fgets(ln, sizeof(buf_name), f)) break; n++; pa_strip_nl(ln); if (ln[0] == '#') continue; if (ln == buf_name) { ln = buf_volume; continue; } if (ln == buf_volume) { ln = buf_sink; continue; } if (ln == buf_sink) { ln = buf_source; continue; } pa_assert(ln == buf_source); if (buf_volume[0]) { if (!parse_volume(buf_volume, &v)) { pa_log("parse failure in %s:%u, stopping parsing", u->table_file, n); goto finish; } v_is_set = TRUE; } else v_is_set = FALSE; ln = buf_name; if (pa_hashmap_get(u->hashmap, buf_name)) { pa_log("double entry in %s:%u, ignoring", u->table_file, n); continue; } rule = pa_xnew(struct rule, 1); rule->name = pa_xstrdup(buf_name); if ((rule->volume_is_set = v_is_set)) rule->volume = v; rule->sink = buf_sink[0] ? pa_xstrdup(buf_sink) : NULL; rule->source = buf_source[0] ? pa_xstrdup(buf_source) : NULL; pa_hashmap_put(u->hashmap, rule->name, rule); } if (ln != buf_name) { pa_log("invalid number of lines in %s.", u->table_file); goto finish; } ret = 0; finish: if (f) { pa_lock_fd(fileno(f), 0); fclose(f); } return ret; }