merge glitch-free branch back into trunk

git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@2445 fefdeb5f-60dc-0310-8127-8f9354f1896f
This commit is contained in:
Lennart Poettering 2008-05-15 23:34:41 +00:00
parent 91f092eadc
commit 045c1d602d
189 changed files with 12559 additions and 4959 deletions

View file

@ -41,6 +41,7 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <dirent.h>
#ifdef HAVE_STRTOF_L
#include <locale.h>
@ -103,12 +104,6 @@
#define MSG_NOSIGNAL 0
#endif
#ifndef OS_IS_WIN32
#define PA_USER_RUNTIME_PATH_PREFIX "/tmp/pulse-"
#else
#define PA_USER_RUNTIME_PATH_PREFIX "%TEMP%\\pulse-"
#endif
#ifdef OS_IS_WIN32
#define PULSE_ROOTENV "PULSE_ROOT"
@ -221,7 +216,7 @@ int pa_make_secure_dir(const char* dir, mode_t m, uid_t uid, gid_t gid) {
goto fail;
}
#else
pa_log_warn("secure directory creation not supported on Win32.");
pa_log_warn("Secure directory creation not supported on Win32.");
#endif
return 0;
@ -557,6 +552,82 @@ int pa_make_realtime(int rtprio) {
#endif
}
/* This is merely used for giving the user a hint. This is not correct
* for anything security related */
pa_bool_t pa_can_realtime(void) {
if (geteuid() == 0)
return TRUE;
#if defined(HAVE_SYS_RESOURCE_H) && defined(RLIMIT_RTPRIO)
{
struct rlimit rl;
if (getrlimit(RLIMIT_RTPRIO, &rl) >= 0)
if (rl.rlim_cur > 0 || rl.rlim_cur == RLIM_INFINITY)
return TRUE;
}
#endif
#if defined(HAVE_SYS_CAPABILITY_H) && defined(CAP_SYS_NICE)
{
cap_t cap;
if ((cap = cap_get_proc())) {
cap_flag_value_t flag = CAP_CLEAR;
if (cap_get_flag(cap, CAP_SYS_NICE, CAP_EFFECTIVE, &flag) >= 0)
if (flag == CAP_SET) {
cap_free(cap);
return TRUE;
}
cap_free(cap);
}
}
#endif
return FALSE;
}
/* This is merely used for giving the user a hint. This is not correct
* for anything security related */
pa_bool_t pa_can_high_priority(void) {
if (geteuid() == 0)
return TRUE;
#if defined(HAVE_SYS_RESOURCE_H) && defined(RLIMIT_RTPRIO)
{
struct rlimit rl;
if (getrlimit(RLIMIT_NICE, &rl) >= 0)
if (rl.rlim_cur >= 21 || rl.rlim_cur == RLIM_INFINITY)
return TRUE;
}
#endif
#if defined(HAVE_SYS_CAPABILITY_H) && defined(CAP_SYS_NICE)
{
cap_t cap;
if ((cap = cap_get_proc())) {
cap_flag_value_t flag = CAP_CLEAR;
if (cap_get_flag(cap, CAP_SYS_NICE, CAP_EFFECTIVE, &flag) >= 0)
if (flag == CAP_SET) {
cap_free(cap);
return TRUE;
}
cap_free(cap);
}
}
#endif
return FALSE;
}
/* Raise the priority of the current process as much as possible that
* is <= the specified nice level..*/
int pa_raise_priority(int nice_level) {
@ -612,6 +683,7 @@ void pa_reset_priority(void) {
/* Try to parse a boolean string value.*/
int pa_parse_boolean(const char *v) {
pa_assert(v);
if (!strcmp(v, "1") || v[0] == 'y' || v[0] == 'Y' || v[0] == 't' || v[0] == 'T' || !strcasecmp(v, "on"))
return 1;
@ -1093,16 +1165,126 @@ int pa_unlock_lockfile(const char *fn, int fd) {
return r;
}
char *pa_get_runtime_dir(void) {
const char *e;
char *d;
if ((e = getenv("PULSE_RUNTIME_PATH")))
d = pa_xstrdup(e);
else {
char h[PATH_MAX];
if (!pa_get_home_dir(h, sizeof(h))) {
pa_log_error("Failed to get home directory.");
return NULL;
}
d = pa_sprintf_malloc("%s" PA_PATH_SEP ".pulse", h);
}
if (pa_make_secure_dir(d, 0700, (pid_t) -1, (pid_t) -1) < 0) {
pa_log_error("Failed to create secure directory: %s", pa_cstrerror(errno));
return NULL;
}
return d;
}
/* Try to open a configuration file. If "env" is specified, open the
* value of the specified environment variable. Otherwise look for a
* file "local" in the home directory or a file "global" in global
* file system. If "result" is non-NULL, a pointer to a newly
* allocated buffer containing the used configuration file is
* stored there.*/
FILE *pa_open_config_file(const char *global, const char *local, const char *env, char **result, const char *mode) {
FILE *pa_open_config_file(const char *global, const char *local, const char *env, char **result) {
const char *fn;
char h[PATH_MAX];
#ifdef OS_IS_WIN32
char buf[PATH_MAX];
if (!getenv(PULSE_ROOTENV))
pa_set_root(NULL);
#endif
if (env && (fn = getenv(env))) {
FILE *f;
#ifdef OS_IS_WIN32
if (!ExpandEnvironmentStrings(fn, buf, PATH_MAX))
return NULL;
fn = buf;
#endif
if ((f = fopen(fn, "r"))) {
if (result)
*result = pa_xstrdup(fn);
return f;
}
pa_log_warn("Failed to open configuration file '%s': %s", fn, pa_cstrerror(errno));
return NULL;
}
if (local) {
const char *e;
char *lfn;
char h[PATH_MAX];
FILE *f;
if ((e = getenv("PULSE_CONFIG_PATH")))
fn = lfn = pa_sprintf_malloc("%s" PA_PATH_SEP "%s", e, local);
else if (pa_get_home_dir(h, sizeof(h)))
fn = lfn = pa_sprintf_malloc("%s" PA_PATH_SEP ".pulse" PA_PATH_SEP "%s", h, local);
#ifdef OS_IS_WIN32
if (!ExpandEnvironmentStrings(lfn, buf, PATH_MAX)) {
pa_xfree(lfn);
return NULL;
}
fn = buf;
#endif
if ((f = fopen(fn, "r"))) {
if (result)
*result = pa_xstrdup(fn);
pa_xfree(lfn);
return f;
}
if (errno != ENOENT) {
pa_log_warn("Failed to open configuration file '%s': %s", fn, pa_cstrerror(errno));
pa_xfree(lfn);
return NULL;
}
pa_xfree(lfn);
}
if (global) {
FILE *f;
#ifdef OS_IS_WIN32
if (!ExpandEnvironmentStrings(global, buf, PATH_MAX))
return NULL;
global = buf;
#endif
if ((f = fopen(global, "r"))) {
if (result)
*result = pa_xstrdup(global);
return f;
}
} else
errno = ENOENT;
return NULL;
}
char *pa_find_config_file(const char *global, const char *local, const char *env) {
const char *fn;
#ifdef OS_IS_WIN32
char buf[PATH_MAX];
@ -1117,69 +1299,59 @@ FILE *pa_open_config_file(const char *global, const char *local, const char *env
fn = buf;
#endif
if (result)
*result = pa_xstrdup(fn);
if (access(fn, R_OK) == 0)
return pa_xstrdup(fn);
return fopen(fn, mode);
pa_log_warn("Failed to access configuration file '%s': %s", fn, pa_cstrerror(errno));
return NULL;
}
if (local) {
const char *e;
char *lfn = NULL;
char *lfn;
char h[PATH_MAX];
if ((e = getenv("PULSE_CONFIG_PATH")))
fn = lfn = pa_sprintf_malloc("%s/%s", e, local);
else if (pa_get_home_dir(h, sizeof(h))) {
char *d;
d = pa_sprintf_malloc("%s/.pulse", h);
mkdir(d, 0755);
pa_xfree(d);
fn = lfn = pa_sprintf_malloc("%s/.pulse/%s", h, local);
}
if (lfn) {
FILE *f;
fn = lfn = pa_sprintf_malloc("%s" PA_PATH_SEP "%s", e, local);
else if (pa_get_home_dir(h, sizeof(h)))
fn = lfn = pa_sprintf_malloc("%s" PA_PATH_SEP ".pulse" PA_PATH_SEP "%s", h, local);
#ifdef OS_IS_WIN32
if (!ExpandEnvironmentStrings(lfn, buf, PATH_MAX))
return NULL;
fn = buf;
#endif
f = fopen(fn, mode);
if (f != NULL) {
if (result)
*result = pa_xstrdup(fn);
pa_xfree(lfn);
return f;
}
if (errno != ENOENT)
pa_log_warn("Failed to open configuration file '%s': %s", lfn, pa_cstrerror(errno));
if (!ExpandEnvironmentStrings(lfn, buf, PATH_MAX)) {
pa_xfree(lfn);
return NULL;
}
}
if (!global) {
if (result)
*result = NULL;
errno = ENOENT;
return NULL;
}
#ifdef OS_IS_WIN32
if (!ExpandEnvironmentStrings(global, buf, PATH_MAX))
return NULL;
global = buf;
fn = buf;
#endif
if (result)
*result = pa_xstrdup(global);
if (access(fn, R_OK) == 0) {
char *r = pa_xstrdup(fn);
pa_xfree(lfn);
return r;
}
return fopen(global, mode);
if (errno != ENOENT) {
pa_log_warn("Failed to access configuration file '%s': %s", fn, pa_cstrerror(errno));
pa_xfree(lfn);
return NULL;
}
pa_xfree(lfn);
}
if (global) {
#ifdef OS_IS_WIN32
if (!ExpandEnvironmentStrings(global, buf, PATH_MAX))
return NULL;
global = buf;
#endif
if (access(fn, R_OK) == 0)
return pa_xstrdup(global);
} else
errno = ENOENT;
return NULL;
}
/* Format the specified data as a hexademical string */
@ -1270,45 +1442,51 @@ int pa_endswith(const char *s, const char *sfx) {
return l1 >= l2 && strcmp(s+l1-l2, sfx) == 0;
}
/* if fn is null return the PulseAudio run time path in s (/tmp/pulse)
* if fn is non-null and starts with / return fn in s
* otherwise append fn to the run time path and return it in s */
char *pa_runtime_path(const char *fn, char *s, size_t l) {
const char *e;
pa_bool_t pa_is_path_absolute(const char *fn) {
pa_assert(fn);
#ifndef OS_IS_WIN32
if (fn && *fn == '/')
return *fn == '/';
#else
if (fn && strlen(fn) >= 3 && isalpha(fn[0]) && fn[1] == ':' && fn[2] == '\\')
return strlen(fn) >= 3 && isalpha(fn[0]) && fn[1] == ':' && fn[2] == '\\';
#endif
return pa_strlcpy(s, fn, l);
}
if ((e = getenv("PULSE_RUNTIME_PATH"))) {
char *pa_make_path_absolute(const char *p) {
char *r;
char *cwd;
if (fn)
pa_snprintf(s, l, "%s%c%s", e, PA_PATH_SEP_CHAR, fn);
else
pa_snprintf(s, l, "%s", e);
pa_assert(p);
} else {
char u[256];
if (pa_is_path_absolute(p))
return pa_xstrdup(p);
if (fn)
pa_snprintf(s, l, "%s%s%c%s", PA_USER_RUNTIME_PATH_PREFIX, pa_get_user_name(u, sizeof(u)), PA_PATH_SEP_CHAR, fn);
else
pa_snprintf(s, l, "%s%s", PA_USER_RUNTIME_PATH_PREFIX, pa_get_user_name(u, sizeof(u)));
}
if (!(cwd = pa_getcwd()))
return pa_xstrdup(p);
r = pa_sprintf_malloc("%s" PA_PATH_SEP "%s", cwd, p);
pa_xfree(cwd);
return r;
}
#ifdef OS_IS_WIN32
{
char buf[l];
strcpy(buf, s);
ExpandEnvironmentStrings(buf, s, l);
}
#endif
/* if fn is null return the PulseAudio run time path in s (~/.pulse)
* if fn is non-null and starts with / return fn
* otherwise append fn to the run time path and return it */
char *pa_runtime_path(const char *fn) {
char *rtp;
return s;
if (pa_is_path_absolute(fn))
return pa_xstrdup(fn);
rtp = pa_get_runtime_dir();
if (fn) {
char *r;
r = pa_sprintf_malloc("%s" PA_PATH_SEP "%s", rtp, fn);
pa_xfree(rtp);
return r;
} else
return rtp;
}
/* Convert the string s to a signed integer in *ret_i */
@ -1414,12 +1592,28 @@ int pa_snprintf(char *str, size_t size, const char *format, ...) {
pa_assert(format);
va_start(ap, format);
ret = vsnprintf(str, size, format, ap);
ret = pa_vsnprintf(str, size, format, ap);
va_end(ap);
return ret;
}
/* Same as vsnprintf, but guarantees NUL-termination on every platform */
int pa_vsnprintf(char *str, size_t size, const char *format, va_list ap) {
int ret;
pa_assert(str);
pa_assert(size > 0);
pa_assert(format);
ret = vsnprintf(str, size, format, ap);
str[size-1] = 0;
return ret;
if (ret < 0)
ret = strlen(str);
return PA_MIN((int) size-1, ret);
}
/* Truncate the specified string, but guarantee that the string
@ -1455,23 +1649,6 @@ char *pa_getcwd(void) {
}
}
char *pa_make_path_absolute(const char *p) {
char *r;
char *cwd;
pa_assert(p);
if (p[0] == '/')
return pa_xstrdup(p);
if (!(cwd = pa_getcwd()))
return pa_xstrdup(p);
r = pa_sprintf_malloc("%s/%s", cwd, p);
pa_xfree(cwd);
return r;
}
void *pa_will_need(const void *p, size_t l) {
#ifdef RLIMIT_MEMLOCK
struct rlimit rlim;
@ -1577,3 +1754,249 @@ char *pa_readlink(const char *p) {
l *= 2;
}
}
int pa_close_all(int except_fd, ...) {
va_list ap;
int n = 0, i, r;
int *p;
va_start(ap, except_fd);
if (except_fd >= 0)
for (n = 1; va_arg(ap, int) >= 0; n++)
;
va_end(ap);
p = pa_xnew(int, n+1);
va_start(ap, except_fd);
i = 0;
if (except_fd >= 0) {
p[i++] = except_fd;
while ((p[i++] = va_arg(ap, int)) >= 0)
;
}
p[i] = -1;
va_end(ap);
r = pa_close_allv(p);
free(p);
return r;
}
int pa_close_allv(const int except_fds[]) {
struct rlimit rl;
int fd;
int saved_errno;
#ifdef __linux__
DIR *d;
if ((d = opendir("/proc/self/fd"))) {
struct dirent *de;
while ((de = readdir(d))) {
long l;
char *e = NULL;
int i;
if (de->d_name[0] == '.')
continue;
errno = 0;
l = strtol(de->d_name, &e, 10);
if (errno != 0 || !e || *e) {
closedir(d);
errno = EINVAL;
return -1;
}
fd = (int) l;
if ((long) fd != l) {
closedir(d);
errno = EINVAL;
return -1;
}
if (fd <= 3)
continue;
if (fd == dirfd(d))
continue;
for (i = 0; except_fds[i] >= 0; i++)
if (except_fds[i] == fd)
continue;
if (close(fd) < 0) {
saved_errno = errno;
closedir(d);
errno = saved_errno;
return -1;
}
}
closedir(d);
return 0;
}
#endif
if (getrlimit(RLIMIT_NOFILE, &rl) < 0)
return -1;
for (fd = 0; fd < (int) rl.rlim_max; fd++) {
int i;
if (fd <= 3)
continue;
for (i = 0; except_fds[i] >= 0; i++)
if (except_fds[i] == fd)
continue;
if (close(fd) < 0 && errno != EBADF)
return -1;
}
return 0;
}
int pa_unblock_sigs(int except, ...) {
va_list ap;
int n = 0, i, r;
int *p;
va_start(ap, except);
if (except >= 1)
for (n = 1; va_arg(ap, int) >= 0; n++)
;
va_end(ap);
p = pa_xnew(int, n+1);
va_start(ap, except);
i = 0;
if (except >= 1) {
p[i++] = except;
while ((p[i++] = va_arg(ap, int)) >= 0)
;
}
p[i] = -1;
va_end(ap);
r = pa_unblock_sigsv(p);
pa_xfree(p);
return r;
}
int pa_unblock_sigsv(const int except[]) {
int i;
sigset_t ss;
if (sigemptyset(&ss) < 0)
return -1;
for (i = 0; except[i] > 0; i++)
if (sigaddset(&ss, except[i]) < 0)
return -1;
return sigprocmask(SIG_SETMASK, &ss, NULL);
}
int pa_reset_sigs(int except, ...) {
va_list ap;
int n = 0, i, r;
int *p;
va_start(ap, except);
if (except >= 1)
for (n = 1; va_arg(ap, int) >= 0; n++)
;
va_end(ap);
p = pa_xnew(int, n+1);
va_start(ap, except);
i = 0;
if (except >= 1) {
p[i++] = except;
while ((p[i++] = va_arg(ap, int)) >= 0)
;
}
p[i] = -1;
va_end(ap);
r = pa_reset_sigsv(p);
pa_xfree(p);
return r;
}
int pa_reset_sigsv(const int except[]) {
int sig;
for (sig = 1; sig < _NSIG; sig++) {
int reset = 1;
switch (sig) {
case SIGKILL:
case SIGSTOP:
reset = 0;
break;
default: {
int i;
for (i = 0; except[i] > 0; i++) {
if (sig == except[i]) {
reset = 0;
break;
}
}
}
}
if (reset) {
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
sa.sa_handler = SIG_DFL;
/* On Linux the first two RT signals are reserved by
* glibc, and sigaction() will return EINVAL for them. */
if ((sigaction(sig, &sa, NULL) < 0))
if (errno != EINVAL)
return -1;
}
}
return 0;
}
void pa_set_env(const char *key, const char *value) {
pa_assert(key);
pa_assert(value);
putenv(pa_sprintf_malloc("%s=%s", key, value));
}