void pa_memchunk_dump_to_file(pa_memchunk *c, const char *fn) { FILE *f; void *p; pa_assert(c); pa_assert(fn); /* Only for debugging purposes */ f = pa_fopen_cloexec(fn, "a"); if (!f) { pa_log_warn("Failed to open '%s': %s", fn, pa_cstrerror(errno)); return; } p = pa_memblock_acquire(c->memblock); if (fwrite((uint8_t*) p + c->index, 1, c->length, f) != c->length) pa_log_warn("Failed to write to '%s': %s", fn, pa_cstrerror(errno)); pa_memblock_release(c->memblock); fclose(f); }
/* 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; }
/* Raise the priority of the current process as much as possible that * is <= the specified nice level..*/ int pa_raise_priority(int nice_level) { #ifdef HAVE_SYS_RESOURCE_H if (setpriority(PRIO_PROCESS, 0, nice_level) < 0) { int n; for (n = nice_level+1; n < 0; n++) { if (setpriority(PRIO_PROCESS, 0, n) == 0) { pa_log_info("Successfully acquired nice level %i, which is lower than the requested %i.", n, nice_level); return 0; } } pa_log_warn("setpriority(): %s", pa_cstrerror(errno)); return -1; } pa_log_info("Successfully gained nice level %i.", nice_level); #endif #ifdef OS_IS_WIN32 if (nice_level < 0) { if (!SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS)) { pa_log_warn("SetPriorityClass() failed: 0x%08X", GetLastError()); return .-1; } else
static pa_dbus_connection *register_dbus(pa_core *c) { DBusError error; pa_dbus_connection *conn; dbus_error_init(&error); if (!(conn = pa_dbus_bus_get(c, pa_in_system_mode() ? DBUS_BUS_SYSTEM : DBUS_BUS_SESSION, &error)) || dbus_error_is_set(&error)) { pa_log_warn("Unable to contact D-Bus: %s: %s", error.name, error.message); goto fail; } if (dbus_bus_request_name(pa_dbus_connection_get(conn), "org.pulseaudio.Server", DBUS_NAME_FLAG_DO_NOT_QUEUE, &error) == DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) { pa_log_debug("Got org.pulseaudio.Server!"); return conn; } if (dbus_error_is_set(&error)) pa_log_warn("Failed to acquire org.pulseaudio.Server: %s: %s", error.name, error.message); else pa_log_warn("D-Bus name org.pulseaudio.Server already taken. Weird shit!"); /* PA cannot be started twice by the same user and hence we can * ignore mostly the case that org.pulseaudio.Server is already * taken. */ fail: if (conn) pa_dbus_connection_unref(conn); dbus_error_free(&error); return NULL; }
/* 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 struct entry* read_entry(struct userdata *u, const char *name) { pa_datum key, data; struct entry *e; pa_assert(u); pa_assert(name); key.data = (char*) name; key.size = strlen(name); pa_zero(data); if (!pa_database_get(u->database, &key, &data)) goto fail; if (data.size != sizeof(struct entry)) { pa_log_debug("Database contains entry for device %s of wrong size %lu != %lu. Probably due to upgrade, ignoring.", name, (unsigned long) data.size, (unsigned long) sizeof(struct entry)); goto fail; } e = (struct entry*) data.data; if (e->version != ENTRY_VERSION) { pa_log_debug("Version of database entry for device %s doesn't match our version. Probably due to upgrade, ignoring.", name); goto fail; } if (!memchr(e->port, 0, sizeof(e->port))) { pa_log_warn("Database contains entry for device %s with missing NUL byte in port name", name); goto fail; } if (e->volume_valid && !pa_channel_map_valid(&e->channel_map)) { pa_log_warn("Invalid channel map stored in database for device %s", name); goto fail; } if (e->volume_valid && (!pa_cvolume_valid(&e->volume) || !pa_cvolume_compatible_with_channel_map(&e->volume, &e->channel_map))) { pa_log_warn("Volume and channel map don't match in database entry for device %s", name); goto fail; } return e; fail: pa_datum_free(&data); return NULL; }
static int sco_acquire_cb(pa_bluetooth_transport *t, bool optional, size_t *imtu, size_t *omtu) { int sock; socklen_t len; if (optional) sock = sco_do_accept(t); else sock = sco_do_connect(t); if (sock < 0) goto fail; if (imtu) *imtu = 48; if (omtu) *omtu = 48; if (t->device->autodetect_mtu) { struct sco_options sco_opt; len = sizeof(sco_opt); memset(&sco_opt, 0, len); if (getsockopt(sock, SOL_SCO, SCO_OPTIONS, &sco_opt, &len) < 0) pa_log_warn("getsockopt(SCO_OPTIONS) failed, loading defaults"); else { if (imtu) *imtu = sco_opt.mtu; if (omtu) *omtu = sco_opt.mtu; } } return sock; fail: return -1; }
static int parse_rlimit(const char *filename, unsigned line, const char *section, const char *lvalue, const char *rvalue, void *data, void *userdata) { #ifdef HAVE_SYS_RESOURCE_H struct pa_rlimit *r = data; pa_assert(filename); pa_assert(lvalue); pa_assert(rvalue); pa_assert(r); if (rvalue[strspn(rvalue, "\t ")] == 0) { /* Empty string */ r->is_set = 0; r->value = 0; } else { int32_t k; if (pa_atoi(rvalue, &k) < 0) { pa_log(_("[%s:%u] Invalid rlimit '%s'."), filename, line, rvalue); return -1; } r->is_set = k >= 0; r->value = k >= 0 ? (rlim_t) k : 0; } #else pa_log_warn(_("[%s:%u] rlimit not supported on this platform."), filename, line); #endif return 0; }
static pa_dbus_connection *register_dbus_name(pa_core *c, DBusBusType bus, const char* name) { DBusError error; pa_dbus_connection *conn; dbus_error_init(&error); if (!(conn = pa_dbus_bus_get(c, bus, &error)) || dbus_error_is_set(&error)) { pa_log_warn("Unable to contact D-Bus: %s: %s", error.name, error.message); goto fail; } if (dbus_bus_request_name(pa_dbus_connection_get(conn), name, DBUS_NAME_FLAG_DO_NOT_QUEUE, &error) == DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) { pa_log_debug("Got %s!", name); return conn; } if (dbus_error_is_set(&error)) pa_log_error("Failed to acquire %s: %s: %s", name, error.name, error.message); else pa_log_error("D-Bus name %s already taken.", name); /* PA cannot be started twice by the same user and hence we can * ignore mostly the case that a name is already taken. */ fail: if (conn) pa_dbus_connection_unref(conn); dbus_error_free(&error); return NULL; }
static void inotify_cb( pa_mainloop_api *a, pa_io_event *e, int fd, pa_io_event_flags_t events, void *userdata) { struct { struct inotify_event event; char name[NAME_MAX+1]; } buf; pa_inotify *i = userdata; int pid_fd; pa_assert(i); if (pa_read(fd, &buf, sizeof(buf), NULL) < (int) sizeof(buf.event)) pa_log_warn("inotify did not read a full event."); else pa_log_debug("inotify callback, event mask: 0x%x", (int) buf.event.mask); pid_fd = pa_open_cloexec(i->filename, O_RDONLY #ifdef O_NOFOLLOW |O_NOFOLLOW #endif , S_IRUSR); if (pid_fd < 0) { if (i->callback) i->callback(i->callback_data); } else pa_close(pid_fd); }
static void load_null_sink_if_needed(pa_core *c, pa_sink *sink, struct userdata* u) { pa_sink *target; uint32_t idx; char *t; pa_module *m; pa_assert(c); pa_assert(u); pa_assert(u->null_module == PA_INVALID_INDEX); /* Loop through all sinks and check to see if we have *any* * sinks. Ignore the sink passed in (if it's not null) */ for (target = pa_idxset_first(c->sinks, &idx); target; target = pa_idxset_next(c->sinks, &idx)) if (!sink || target != sink) break; if (target) return; pa_log_debug("Autoloading null-sink as no other sinks detected."); u->ignore = TRUE; t = pa_sprintf_malloc("sink_name=%s sink_properties='device.description=\"%s\"'", u->sink_name, _("Dummy Output")); m = pa_module_load(c, "module-null-sink", t); u->null_module = m ? m->index : PA_INVALID_INDEX; pa_xfree(t); u->ignore = FALSE; if (!m) pa_log_warn("Unable to load module-null-sink"); }
void pa_mempool_free(pa_mempool *p) { pa_assert(p); pa_mutex_lock(p->mutex); while (p->imports) pa_memimport_free(p->imports); while (p->exports) pa_memexport_free(p->exports); pa_mutex_unlock(p->mutex); pa_flist_free(p->free_slots, NULL); if (pa_atomic_load(&p->stat.n_allocated) > 0) { /* raise(SIGTRAP); */ pa_log_warn("Memory pool destroyed but not all memory blocks freed! %u remain.", pa_atomic_load(&p->stat.n_allocated)); } pa_shm_free(&p->memory); pa_mutex_free(p->mutex); pa_semaphore_free(p->semaphore); pa_xfree(p); }
pa_dbusobj_server_lookup *pa_dbusobj_server_lookup_new(pa_core *c) { pa_dbusobj_server_lookup *sl; DBusError error; dbus_error_init(&error); sl = pa_xnew(pa_dbusobj_server_lookup, 1); sl->core = c; sl->path_registered = false; if (!(sl->conn = pa_dbus_bus_get(c, DBUS_BUS_SESSION, &error)) || dbus_error_is_set(&error)) { pa_log_warn("Unable to contact D-Bus: %s: %s", error.name, error.message); goto fail; } if (!dbus_connection_register_object_path(pa_dbus_connection_get(sl->conn), OBJECT_PATH, &vtable, sl)) { pa_log("dbus_connection_register_object_path() failed for " OBJECT_PATH "."); goto fail; } sl->path_registered = true; return sl; fail: dbus_error_free(&error); pa_dbusobj_server_lookup_free(sl); return NULL; }
static bool parse_device_list(const char *str, audio_devices_t *dst) { char *dev; const char *state = NULL; pa_assert(str); pa_assert(dst); *dst = 0; while ((dev = pa_split(str, "|", &state))) { audio_devices_t d; if (!pa_string_convert_input_device_str_to_num(dev, &d)) { pa_log_warn("Unknown device %s", dev); pa_xfree(dev); return false; } *dst |= d; pa_xfree(dev); } return true; }
static void jack_error_func(const char*t) { char *s; s = pa_xstrndup(t, strcspn(t, "\n\r")); pa_log_warn("JACK error >%s<", s); pa_xfree(s); }
int pa__init(pa_module*m) { pa_modargs *ma = NULL; int ret = -1; uint32_t pid = 0; pa_assert(m); if (!(ma = pa_modargs_new(m->argument, valid_modargs)) || pa_modargs_get_value_u32(ma, "pid", &pid) < 0 || !pid) { pa_log("Failed to parse module arguments"); goto finish; } if (kill((pid_t) pid, SIGUSR1) < 0) pa_log_warn("kill(%u) failed: %s", pid, pa_cstrerror(errno)); pa_module_unload_request(m, true); ret = 0; finish: if (ma) pa_modargs_free(ma); return ret; }
void pa_asyncq_post(pa_asyncq*l, void *p) { struct localq *q; pa_assert(l); pa_assert(p); if (flush_postq(l, FALSE)) if (pa_asyncq_push(l, p, FALSE) >= 0) return; /* OK, we couldn't push anything in the queue. So let's queue it * locally and push it later */ if (pa_log_ratelimit()) pa_log_warn("q overrun, queuing locally"); if (!(q = pa_flist_pop(PA_STATIC_FLIST_GET(localq)))) q = pa_xnew(struct localq, 1); q->data = p; PA_LLIST_PREPEND(struct localq, l->localq, q); if (!l->last_localq) l->last_localq = q; return; }
static struct pa_policy_group* get_group(struct userdata *u, const char *group_name, pa_proplist *sinp_proplist, uint32_t *flags_ret) { struct pa_policy_group *group = NULL; const void *flags; size_t len_flags = 0; pa_assert(u); pa_assert(sinp_proplist); /* If group name is provided use that, otherwise check sink input proplist. */ if (!group_name) /* Just grab the group name from the proplist to avoid classifying multiple * times (and to avoid classifying incorrectly if properties are * overwritten when handling PA_CORE_HOOK_SINK_INPUT_NEW).*/ group_name = pa_proplist_gets(sinp_proplist, PA_PROP_POLICY_GROUP); if (group_name && (group = pa_policy_group_find(u, group_name)) != NULL) { /* Only update flags if flags_ret is non null */ if (flags_ret) { if (pa_proplist_get(sinp_proplist, PA_PROP_POLICY_STREAM_FLAGS, &flags, &len_flags) < 0 || len_flags != sizeof(uint32_t)) { pa_log_warn("No stream flags in proplist or malformed flags."); *flags_ret = 0; } else *flags_ret = *(uint32_t *)flags; } } return group; }
int pa__init(pa_module*m) { pa_modargs *ma = NULL; int ret = -1; int32_t fd = -1; char x = 1; pa_assert(m); if (!(ma = pa_modargs_new(m->argument, valid_modargs)) || pa_modargs_get_value_s32(ma, "fd", &fd) < 0 || fd < 0) { pa_log("Failed to parse module arguments"); goto finish; } if (pa_loop_write(fd, &x, sizeof(x), NULL) != sizeof(x)) pa_log_warn("write(%u, 1, 1) failed: %s", fd, pa_cstrerror(errno)); pa_assert_se(pa_close(fd) == 0); pa_module_unload_request(m, true); ret = 0; finish: if (ma) pa_modargs_free(ma); return ret; }
void pa_rtclock_hrtimer_enable(void) { #ifdef PR_SET_TIMERSLACK int slack_ns; if ((slack_ns = prctl(PR_GET_TIMERSLACK, 0, 0, 0, 0)) < 0) { pa_log_info("PR_GET_TIMERSLACK/PR_SET_TIMERSLACK not supported."); return; } pa_log_debug("Timer slack is set to %i us.", (int) (slack_ns/PA_NSEC_PER_USEC)); if (slack_ns > TIMER_SLACK_NS) { slack_ns = TIMER_SLACK_NS; pa_log_debug("Setting timer slack to %i us.", (int) (slack_ns/PA_NSEC_PER_USEC)); if (prctl(PR_SET_TIMERSLACK, slack_ns, 0, 0, 0) < 0) { pa_log_warn("PR_SET_TIMERSLACK failed: %s", pa_cstrerror(errno)); return; } } #elif defined(OS_IS_WIN32) LARGE_INTEGER freq; pa_assert_se(QueryPerformanceFrequency(&freq)); counter_freq = freq.QuadPart; #endif }
/* pa_io_event_cb_t IO event handler */ static void handle_io_event(pa_mainloop_api *ea, pa_io_event *e, int fd, pa_io_event_flags_t events, void *userdata) { unsigned int flags = 0; DBusWatch *watch = userdata; #if HAVE_DBUS_WATCH_GET_UNIX_FD pa_assert(fd == dbus_watch_get_unix_fd(watch)); #else pa_assert(fd == dbus_watch_get_fd(watch)); #endif if (!dbus_watch_get_enabled(watch)) { pa_log_warn("Asked to handle disabled watch: %p %i", (void*) watch, fd); return; } if (events & PA_IO_EVENT_INPUT) flags |= DBUS_WATCH_READABLE; if (events & PA_IO_EVENT_OUTPUT) flags |= DBUS_WATCH_WRITABLE; if (events & PA_IO_EVENT_HANGUP) flags |= DBUS_WATCH_HANGUP; if (events & PA_IO_EVENT_ERROR) flags |= DBUS_WATCH_ERROR; dbus_watch_handle(watch, flags); }
static void load(struct userdata *u) { FILE *f; /* We never overwrite manually configured settings */ if (u->core->configured_default_sink) pa_log_info("Manually configured default sink, not overwriting."); else if ((f = pa_fopen_cloexec(u->sink_filename, "r"))) { char ln[256] = ""; if (fgets(ln, sizeof(ln)-1, f)) pa_strip_nl(ln); fclose(f); if (!ln[0]) pa_log_info("No previous default sink setting, ignoring."); else if (!pa_namereg_is_valid_name(ln)) pa_log_warn("Invalid sink name: %s", ln); else { pa_log_info("Restoring default sink '%s'.", ln); pa_core_set_configured_default_sink(u->core, ln); } } else if (errno != ENOENT) pa_log("Failed to load default sink: %s", pa_cstrerror(errno)); if (u->core->configured_default_source) pa_log_info("Manually configured default source, not overwriting."); else if ((f = pa_fopen_cloexec(u->source_filename, "r"))) { char ln[256] = ""; if (fgets(ln, sizeof(ln)-1, f)) pa_strip_nl(ln); fclose(f); if (!ln[0]) pa_log_info("No previous default source setting, ignoring."); else if (!pa_namereg_is_valid_name(ln)) pa_log_warn("Invalid source name: %s", ln); else { pa_log_info("Restoring default source '%s'.", ln); pa_core_set_configured_default_source(u->core, ln); } } else if (errno != ENOENT) pa_log("Failed to load default source: %s", pa_cstrerror(errno)); }
/* Called from main context */ static void adjust_rates(struct userdata *u) { size_t buffer, fs; uint32_t old_rate, base_rate, new_rate; pa_usec_t buffer_latency; pa_assert(u); pa_assert_ctl_context(); pa_asyncmsgq_send(u->source_output->source->asyncmsgq, PA_MSGOBJECT(u->source_output), SOURCE_OUTPUT_MESSAGE_LATENCY_SNAPSHOT, NULL, 0, NULL); pa_asyncmsgq_send(u->sink_input->sink->asyncmsgq, PA_MSGOBJECT(u->sink_input), SINK_INPUT_MESSAGE_LATENCY_SNAPSHOT, NULL, 0, NULL); buffer = u->latency_snapshot.sink_input_buffer + u->latency_snapshot.source_output_buffer; if (u->latency_snapshot.recv_counter <= u->latency_snapshot.send_counter) buffer += (size_t) (u->latency_snapshot.send_counter - u->latency_snapshot.recv_counter); else buffer += PA_CLIP_SUB(buffer, (size_t) (u->latency_snapshot.recv_counter - u->latency_snapshot.send_counter)); buffer_latency = pa_bytes_to_usec(buffer, &u->sink_input->sample_spec); pa_log_debug("Loopback overall latency is %0.2f ms + %0.2f ms + %0.2f ms = %0.2f ms", (double) u->latency_snapshot.sink_latency / PA_USEC_PER_MSEC, (double) buffer_latency / PA_USEC_PER_MSEC, (double) u->latency_snapshot.source_latency / PA_USEC_PER_MSEC, ((double) u->latency_snapshot.sink_latency + buffer_latency + u->latency_snapshot.source_latency) / PA_USEC_PER_MSEC); pa_log_debug("Should buffer %zu bytes, buffered at minimum %zu bytes", u->latency_snapshot.max_request*2, u->latency_snapshot.min_memblockq_length); fs = pa_frame_size(&u->sink_input->sample_spec); old_rate = u->sink_input->sample_spec.rate; base_rate = u->source_output->sample_spec.rate; if (u->latency_snapshot.min_memblockq_length < u->latency_snapshot.max_request*2) new_rate = base_rate - (((u->latency_snapshot.max_request*2 - u->latency_snapshot.min_memblockq_length) / fs) *PA_USEC_PER_SEC)/u->adjust_time; else new_rate = base_rate + (((u->latency_snapshot.min_memblockq_length - u->latency_snapshot.max_request*2) / fs) *PA_USEC_PER_SEC)/u->adjust_time; if (new_rate < (uint32_t) (base_rate*0.8) || new_rate > (uint32_t) (base_rate*1.25)) { pa_log_warn("Sample rates too different, not adjusting (%u vs. %u).", base_rate, new_rate); new_rate = base_rate; } else { if (base_rate < new_rate + 20 && new_rate < base_rate + 20) new_rate = base_rate; /* Do the adjustment in small steps; 2‰ can be considered inaudible */ if (new_rate < (uint32_t) (old_rate*0.998) || new_rate > (uint32_t) (old_rate*1.002)) { pa_log_info("New rate of %u Hz not within 2‰ of %u Hz, forcing smaller adjustment", new_rate, old_rate); new_rate = PA_CLAMP(new_rate, (uint32_t) (old_rate*0.998), (uint32_t) (old_rate*1.002)); } } pa_sink_input_set_rate(u->sink_input, new_rate); pa_log_debug("[%s] Updated sampling rate to %lu Hz.", u->sink_input->sink->name, (unsigned long) new_rate); pa_core_rttime_restart(u->core, u->time_event, pa_rtclock_now() + u->adjust_time); }
/** Creates a directory securely */ int pa_make_secure_dir(const char* dir, mode_t m, uid_t uid, gid_t gid) { struct stat st; int r; pa_assert(dir); #ifdef OS_IS_WIN32 r = mkdir(dir); #else { mode_t u; u = umask(~m); r = mkdir(dir, m); umask(u); } #endif if (r < 0 && errno != EEXIST) return -1; #ifdef HAVE_CHOWN if (uid == (uid_t)-1) uid = getuid(); if (gid == (gid_t)-1) gid = getgid(); (void) chown(dir, uid, gid); #endif #ifdef HAVE_CHMOD chmod(dir, m); #endif #ifdef HAVE_LSTAT if (lstat(dir, &st) < 0) #else if (stat(dir, &st) < 0) #endif goto fail; #ifndef OS_IS_WIN32 if (!S_ISDIR(st.st_mode) || (st.st_uid != uid) || (st.st_gid != gid) || ((st.st_mode & 0777) != m)) { errno = EACCES; goto fail; } #else pa_log_warn("secure directory creation not supported on Win32."); #endif return 0; fail: rmdir(dir); return -1; }
/* 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; }
static int do_write(struct userdata *u) { ssize_t r; pa_assert(u); if (!pa_iochannel_is_writable(u->io)) return 0; if (u->write_data) { pa_assert(u->write_index < u->write_length); if ((r = pa_iochannel_write(u->io, (uint8_t*) u->write_data + u->write_index, u->write_length - u->write_index)) <= 0) { pa_log("write() failed: %s", pa_cstrerror(errno)); return -1; } u->write_index += (size_t) r; pa_assert(u->write_index <= u->write_length); if (u->write_index == u->write_length) { pa_xfree(u->write_data); u->write_data = NULL; u->write_index = u->write_length = 0; } } if (!u->write_data && u->state == STATE_PREPARE) { int so_sndbuf = 0; socklen_t sl = sizeof(int); /* OK, we're done with sending all control data we need to, so * let's hand the socket over to the IO thread now */ pa_assert(u->fd < 0); u->fd = pa_iochannel_get_send_fd(u->io); pa_iochannel_set_noclose(u->io, TRUE); pa_iochannel_free(u->io); u->io = NULL; pa_make_tcp_socket_low_delay(u->fd); if (getsockopt(u->fd, SOL_SOCKET, SO_SNDBUF, &so_sndbuf, &sl) < 0) pa_log_warn("getsockopt(SO_SNDBUF) failed: %s", pa_cstrerror(errno)); else { pa_log_debug("SO_SNDBUF is %zu.", (size_t) so_sndbuf); pa_sink_set_max_request(u->sink, PA_MAX((size_t) so_sndbuf, u->block_size)); } pa_log_debug("Connection authenticated, handing fd to IO thread..."); pa_asyncmsgq_post(u->thread_mq.inq, PA_MSGOBJECT(u->sink), SINK_MESSAGE_PASS_SOCKET, NULL, 0, NULL, NULL); u->state = STATE_RUNNING; } return 0; }
void pa_client_kill(pa_client *c) { pa_assert(c); if (!c->kill) { pa_log_warn("kill() operation not implemented for client %u", c->index); return; } c->kill(c); }
static void callback(pa_mainloop_api *mainloop, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata) { pa_socket_server *s = userdata; pa_iochannel *io; int nfd; pa_assert(s); pa_assert(PA_REFCNT_VALUE(s) >= 1); pa_assert(s->mainloop == mainloop); pa_assert(s->io_event == e); pa_assert(e); pa_assert(fd >= 0); pa_assert(fd == s->fd); pa_socket_server_ref(s); if ((nfd = pa_accept_cloexec(fd, NULL, NULL)) < 0) { pa_log("accept(): %s", pa_cstrerror(errno)); goto finish; } if (!s->on_connection) { pa_close(nfd); goto finish; } #ifdef HAVE_LIBWRAP if (s->tcpwrap_service) { struct request_info req; request_init(&req, RQ_DAEMON, s->tcpwrap_service, RQ_FILE, nfd, NULL); fromhost(&req); if (!hosts_access(&req)) { pa_log_warn("TCP connection refused by tcpwrap."); pa_close(nfd); goto finish; } pa_log_info("TCP connection accepted by tcpwrap."); } #endif /* There should be a check for socket type here */ if (s->type == SOCKET_SERVER_IPV4) pa_make_tcp_socket_low_delay(fd); else pa_make_socket_low_delay(fd); pa_assert_se(io = pa_iochannel_new(s->mainloop, nfd, nfd)); s->on_connection(s, io, s->userdata); finish: pa_socket_server_unref(s); }
int mv_parse_steps(struct mv_userdata *u, const char *route, const char *step_string_call, const char *step_string_media) { int count1 = 0; int count2 = 0; struct mv_volume_steps_set *set; struct mv_volume_steps call_steps; struct mv_volume_steps media_steps; pa_assert(u); pa_assert(u->steps); pa_assert(route); if (!step_string_call || !step_string_media) { return 0; } count1 = mv_parse_single_steps(&call_steps, step_string_call); if (count1 < 1) { pa_log_warn("failed to parse call steps; %s", step_string_call); return -1; } mv_normalize_steps(&call_steps); count2 = mv_parse_single_steps(&media_steps, step_string_media); if (count2 < 1) { pa_log_warn("failed to parse media steps; %s", step_string_media); return -1; } mv_normalize_steps(&media_steps); set = pa_xnew0(struct mv_volume_steps_set, 1); set->route = pa_xstrdup(route); set->call = call_steps; set->media = media_steps; pa_log_debug("adding %d call and %d media steps with route %s", set->call.n_steps, set->media.n_steps, set->route); pa_hashmap_put(u->steps, set->route, set); return count1 + count2; }