some commenting

change alogrithm for checking for configuration files


git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@273 fefdeb5f-60dc-0310-8127-8f9354f1896f
This commit is contained in:
Lennart Poettering 2004-11-04 21:27:12 +00:00
parent 2aad9e3ae2
commit 5844a33f0b
9 changed files with 156 additions and 84 deletions

View file

@ -24,9 +24,7 @@ modlibdir=$(libdir)/polypaudio-@PA_MAJORMINOR@
AM_CFLAGS=-D_GNU_SOURCE -I$(top_srcdir) $(PTHREAD_CFLAGS) AM_CFLAGS=-D_GNU_SOURCE -I$(top_srcdir) $(PTHREAD_CFLAGS)
AM_CFLAGS+=-DDLSEARCHPATH=\"$(modlibdir)\" AM_CFLAGS+=-DDLSEARCHPATH=\"$(modlibdir)\"
AM_CFLAGS+=-DDEFAULT_SCRIPT_FILE=\"$(polypconfdir)/default.pa\" AM_CFLAGS+=-DDEFAULT_CONFIG_DIR=\"$(polypconfdir)\"
AM_CFLAGS+=-DDEFAULT_CONFIG_FILE=\"$(polypconfdir)/daemon.conf\"
AM_CFLAGS+=-DDEFAULT_CLIENT_CONFIG_FILE=\"$(polypconfdir)/client.conf\"
AM_CFLAGS+=-DPOLYPAUDIO_BINARY=\"$(bindir)/polypaudio\" AM_CFLAGS+=-DPOLYPAUDIO_BINARY=\"$(bindir)/polypaudio\"
AM_LDADD=$(PTHREAD_LIBS) -lm AM_LDADD=$(PTHREAD_LIBS) -lm

View file

@ -22,6 +22,8 @@
#include <stdlib.h> #include <stdlib.h>
#include <assert.h> #include <assert.h>
#include <unistd.h> #include <unistd.h>
#include <errno.h>
#include <string.h>
#include "client-conf.h" #include "client-conf.h"
#include "xmalloc.h" #include "xmalloc.h"
@ -29,13 +31,12 @@
#include "conf-parser.h" #include "conf-parser.h"
#include "util.h" #include "util.h"
#ifndef DEFAULT_CLIENT_CONFIG_FILE #ifndef DEFAULT_CONFIG_DIR
#define DEFAULT_CLIENT_CONFIG_FILE "/etc/polypaudio/client.conf" #define DEFAULT_CONFIG_DIR "/etc/polypaudio"
#endif #endif
#ifndef DEFAULT_CLIENT_CONFIG_FILE_USER #define DEFAULT_CLIENT_CONFIG_FILE DEFAULT_CONFIG_DIR"/client.conf"
#define DEFAULT_CLIENT_CONFIG_FILE_USER ".polypaudio/client.conf" #define DEFAULT_CLIENT_CONFIG_FILE_USER ".polypaudio/client.conf"
#endif
#define ENV_CLIENT_CONFIG_FILE "POLYP_CLIENTCONFIG" #define ENV_CLIENT_CONFIG_FILE "POLYP_CLIENTCONFIG"
#define ENV_DEFAULT_SINK "POLYP_SINK" #define ENV_DEFAULT_SINK "POLYP_SINK"
@ -71,8 +72,9 @@ void pa_client_conf_free(struct pa_client_conf *c) {
pa_xfree(c); pa_xfree(c);
} }
int pa_client_conf_load(struct pa_client_conf *c, const char *filename) { int pa_client_conf_load(struct pa_client_conf *c, const char *filename) {
char *def = NULL; FILE *f = NULL;
int r; char *fn = NULL;
int r = -1;
struct pa_config_item table[] = { struct pa_config_item table[] = {
{ "daemon-binary", pa_config_parse_string, NULL }, { "daemon-binary", pa_config_parse_string, NULL },
@ -91,29 +93,23 @@ int pa_client_conf_load(struct pa_client_conf *c, const char *filename) {
table[4].data = &c->default_server; table[4].data = &c->default_server;
table[5].data = &c->autospawn; table[5].data = &c->autospawn;
if (!filename) f = filename ?
filename = getenv(ENV_CLIENT_CONFIG_FILE); fopen((fn = pa_xstrdup(filename)), "r") :
pa_open_config_file(DEFAULT_CLIENT_CONFIG_FILE, DEFAULT_CLIENT_CONFIG_FILE_USER, ENV_CLIENT_CONFIG_FILE, &fn);
if (!filename) { if (!f && errno != EINTR) {
char *h; pa_log(__FILE__": WARNING: failed to open configuration file '%s': %s\n", filename, strerror(errno));
goto finish;
if ((h = getenv("HOME"))) {
def = pa_sprintf_malloc("%s/%s", h, DEFAULT_CLIENT_CONFIG_FILE_USER);
if (!access(def, F_OK))
filename = def;
else {
pa_xfree(def);
def = NULL;
}
}
} }
if (!filename)
filename = DEFAULT_CLIENT_CONFIG_FILE;
r = pa_config_parse(filename, table, NULL); r = pa_config_parse(fn, f, table, NULL);
pa_xfree(def);
finish:
pa_xfree(fn);
if (f)
fclose(f);
return r; return r;
} }

View file

@ -89,13 +89,13 @@ static int parse_line(const char *filename, unsigned line, const struct pa_confi
} }
int pa_config_parse(const char *filename, const struct pa_config_item *t, void *userdata) { int pa_config_parse(const char *filename, FILE *f, const struct pa_config_item *t, void *userdata) {
FILE *f;
int r = -1; int r = -1;
unsigned line = 0; unsigned line = 0;
int do_close = !f;
assert(filename && t); assert(filename && t);
if (!(f = fopen(filename, "r"))) { if (!f && !(f = fopen(filename, "r"))) {
if (errno == ENOENT) { if (errno == ENOENT) {
r = 0; r = 0;
goto finish; goto finish;
@ -123,7 +123,7 @@ int pa_config_parse(const char *filename, const struct pa_config_item *t, void *
finish: finish:
if (f) if (do_close && f)
fclose(f); fclose(f);
return r; return r;

View file

@ -22,13 +22,15 @@
USA. USA.
***/ ***/
#include <stdio.h>
struct pa_config_item { struct pa_config_item {
const char *lvalue; const char *lvalue;
int (*parse)(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata); int (*parse)(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata);
void *data; void *data;
}; };
int pa_config_parse(const char *filename, const struct pa_config_item *t, void *userdata); int pa_config_parse(const char *filename, FILE *f, const struct pa_config_item *t, void *userdata);
int pa_config_parse_int(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata); int pa_config_parse_int(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata);
int pa_config_parse_bool(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata); int pa_config_parse_bool(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata);

View file

@ -36,21 +36,14 @@
#include "strbuf.h" #include "strbuf.h"
#include "conf-parser.h" #include "conf-parser.h"
#ifndef DEFAULT_SCRIPT_FILE #ifndef DEFAULT_CONFIG_DIR
#define DEFAULT_SCRIPT_FILE "/etc/polypaudio/default.pa" #define DEFAULT_CONFIG_DIR "/etc/polypaudio"
#endif #endif
#ifndef DEFAULT_SCRIPT_FILE_USER #define DEFAULT_SCRIPT_FILE DEFAULT_CONFIG_DIR"/default.pa"
#define DEFAULT_SCRIPT_FILE_USER ".polypaudio/default.pa" #define DEFAULT_SCRIPT_FILE_USER ".polypaudio/default.pa"
#endif #define DEFAULT_CONFIG_FILE DEFAULT_CONFIG_DIR"/daemon.conf"
#ifndef DEFAULT_CONFIG_FILE
#define DEFAULT_CONFIG_FILE "/etc/polypaudio/daemon.conf"
#endif
#ifndef DEFAULT_CONFIG_FILE_USER
#define DEFAULT_CONFIG_FILE_USER ".polypaudio/daemon.conf" #define DEFAULT_CONFIG_FILE_USER ".polypaudio/daemon.conf"
#endif
#define ENV_SCRIPT_FILE "POLYP_SCRIPT" #define ENV_SCRIPT_FILE "POLYP_SCRIPT"
#define ENV_CONFIG_FILE "POLYP_CONFIG" #define ENV_CONFIG_FILE "POLYP_CONFIG"
@ -71,31 +64,17 @@ static const struct pa_daemon_conf default_conf = {
.dl_search_path = NULL, .dl_search_path = NULL,
.default_script_file = NULL, .default_script_file = NULL,
.log_target = PA_LOG_SYSLOG, .log_target = PA_LOG_SYSLOG,
.resample_method = SRC_SINC_FASTEST .resample_method = SRC_SINC_FASTEST,
.config_file = NULL,
}; };
char* default_file(const char *envvar, const char *global, const char *local) {
char *p, *h;
assert(envvar && global && local);
if ((p = getenv(envvar)))
return pa_xstrdup(p);
if ((h = getenv("HOME"))) {
p = pa_sprintf_malloc("%s/%s", h, local);
if (!access(p, F_OK))
return p;
pa_xfree(p);
}
return pa_xstrdup(global);
}
struct pa_daemon_conf* pa_daemon_conf_new(void) { struct pa_daemon_conf* pa_daemon_conf_new(void) {
FILE *f;
struct pa_daemon_conf *c = pa_xmemdup(&default_conf, sizeof(default_conf)); struct pa_daemon_conf *c = pa_xmemdup(&default_conf, sizeof(default_conf));
c->default_script_file = default_file(ENV_SCRIPT_FILE, DEFAULT_SCRIPT_FILE, DEFAULT_SCRIPT_FILE_USER);
if ((f = pa_open_config_file(DEFAULT_SCRIPT_FILE, DEFAULT_SCRIPT_FILE_USER, ENV_SCRIPT_FILE, &c->default_script_file)))
fclose(f);
#ifdef DLSEARCHPATH #ifdef DLSEARCHPATH
c->dl_search_path = pa_xstrdup(DLSEARCHPATH); c->dl_search_path = pa_xstrdup(DLSEARCHPATH);
#endif #endif
@ -107,6 +86,7 @@ void pa_daemon_conf_free(struct pa_daemon_conf *c) {
pa_xfree(c->script_commands); pa_xfree(c->script_commands);
pa_xfree(c->dl_search_path); pa_xfree(c->dl_search_path);
pa_xfree(c->default_script_file); pa_xfree(c->default_script_file);
pa_xfree(c->config_file);
pa_xfree(c); pa_xfree(c);
} }
@ -163,8 +143,8 @@ int parse_resample_method(const char *filename, unsigned line, const char *lvalu
} }
int pa_daemon_conf_load(struct pa_daemon_conf *c, const char *filename) { int pa_daemon_conf_load(struct pa_daemon_conf *c, const char *filename) {
char *def = NULL; int r = -1;
int r; FILE *f = NULL;
struct pa_config_item table[] = { struct pa_config_item table[] = {
{ "verbose", pa_config_parse_bool, NULL }, { "verbose", pa_config_parse_bool, NULL },
@ -195,11 +175,24 @@ int pa_daemon_conf_load(struct pa_daemon_conf *c, const char *filename) {
table[10].data = c; table[10].data = c;
table[11].data = c; table[11].data = c;
if (!filename) pa_xfree(c->config_file);
filename = def = default_file(ENV_CONFIG_FILE, DEFAULT_CONFIG_FILE, DEFAULT_CONFIG_FILE_USER); c->config_file = NULL;
f = filename ?
fopen(c->config_file = pa_xstrdup(filename), "r") :
pa_open_config_file(DEFAULT_CONFIG_FILE, DEFAULT_CONFIG_FILE_USER, ENV_CONFIG_FILE, &c->config_file);
if (!f && errno != EINTR) {
pa_log(__FILE__": WARNING: failed to open configuration file '%s': %s\n", filename, strerror(errno));
goto finish;
}
r = pa_config_parse(c->config_file, f, table, NULL);
finish:
if (f)
fclose(f);
r = pa_config_parse(filename, table, NULL);
pa_xfree(def);
return r; return r;
} }
@ -220,7 +213,6 @@ int pa_daemon_conf_env(struct pa_daemon_conf *c) {
char *pa_daemon_conf_dump(struct pa_daemon_conf *c) { char *pa_daemon_conf_dump(struct pa_daemon_conf *c) {
struct pa_strbuf *s = pa_strbuf_new(); struct pa_strbuf *s = pa_strbuf_new();
char *d;
static const char const* resample_methods[] = { static const char const* resample_methods[] = {
"sinc-best-quality", "sinc-best-quality",
@ -230,8 +222,8 @@ char *pa_daemon_conf_dump(struct pa_daemon_conf *c) {
"linear" "linear"
}; };
d = default_file(ENV_CONFIG_FILE, DEFAULT_CONFIG_FILE, DEFAULT_CONFIG_FILE_USER); if (c->config_file)
pa_strbuf_printf(s, "### Default configuration file: %s ###\n", d); pa_strbuf_printf(s, "### Read from configuration file: %s ###\n", c->config_file);
pa_strbuf_printf(s, "verbose = %i\n", !!c->verbose); pa_strbuf_printf(s, "verbose = %i\n", !!c->verbose);
pa_strbuf_printf(s, "daemonize = %i\n", !!c->daemonize); pa_strbuf_printf(s, "daemonize = %i\n", !!c->daemonize);
@ -248,7 +240,5 @@ char *pa_daemon_conf_dump(struct pa_daemon_conf *c) {
assert(c->resample_method <= 4 && c->resample_method >= 0); assert(c->resample_method <= 4 && c->resample_method >= 0);
pa_strbuf_printf(s, "resample-method = %s\n", resample_methods[c->resample_method]); pa_strbuf_printf(s, "resample-method = %s\n", resample_methods[c->resample_method]);
pa_xfree(d);
return pa_strbuf_tostring_free(s); return pa_strbuf_tostring_free(s);
} }

View file

@ -46,6 +46,7 @@ struct pa_daemon_conf {
char *script_commands, *dl_search_path, *default_script_file; char *script_commands, *dl_search_path, *default_script_file;
enum pa_log_target log_target; enum pa_log_target log_target;
int resample_method; int resample_method;
char *config_file;
}; };
struct pa_daemon_conf* pa_daemon_conf_new(void); struct pa_daemon_conf* pa_daemon_conf_new(void);

View file

@ -48,6 +48,13 @@ PA_MODULE_VERSION(PACKAGE_VERSION)
#define WHITESPACE "\n\r \t" #define WHITESPACE "\n\r \t"
#ifndef DEFAULT_CONFIG_DIR
#define DEFAULT_CONFIG_DIR "/etc/polypaudio"
#endif
#define DEFAULT_MATCH_TABLE_FILE DEFAULT_CONFIG_DIR"/match.table"
#define DEFAULT_MATCH_TABLE_FILE_USER ".polypaudio/.match.table"
static const char* const valid_modargs[] = { static const char* const valid_modargs[] = {
"table", "table",
NULL, NULL,
@ -69,9 +76,14 @@ static int load_rules(struct userdata *u, const char *filename) {
int n = 0; int n = 0;
int ret = -1; int ret = -1;
struct rule *end = NULL; struct rule *end = NULL;
char *fn = NULL;
if (!(f = fopen(filename, "r"))) { f = filename ?
pa_log(__FILE__": failed to open file '%s': %s\n", filename, strerror(errno)); fopen(fn = pa_xstrdup(filename), "r") :
pa_open_config_file(DEFAULT_MATCH_TABLE_FILE, DEFAULT_MATCH_TABLE_FILE_USER, NULL, &fn);
if (!f) {
pa_log(__FILE__": failed to open file '%s': %s\n", fn, strerror(errno));
goto finish; goto finish;
} }
@ -135,6 +147,9 @@ finish:
if (f) if (f)
fclose(f); fclose(f);
if (fn)
pa_xfree(fn);
return ret; return ret;
} }

View file

@ -254,7 +254,7 @@ char *pa_get_host_name(char *s, size_t l) {
} }
/* Return the home directory of the current user */ /* Return the home directory of the current user */
char *pa_get_home(char *s, size_t l) { char *pa_get_home_dir(char *s, size_t l) {
char *e; char *e;
char buf[1024]; char buf[1024];
struct passwd pw, *r; struct passwd pw, *r;
@ -353,8 +353,7 @@ void pa_timeval_add(struct timeval *tv, pa_usec_t v) {
/* Raise the priority of the current process as much as possible and /* Raise the priority of the current process as much as possible and
sensible: set the nice level to -15 and enable realtime scheduling if sensible: set the nice level to -15 and enable realtime scheduling if
supportted.*/ supported.*/
void pa_raise_priority(void) { void pa_raise_priority(void) {
if (setpriority(PRIO_PROCESS, 0, NICE_LEVEL) < 0) if (setpriority(PRIO_PROCESS, 0, NICE_LEVEL) < 0)
@ -381,6 +380,7 @@ void pa_raise_priority(void) {
#endif #endif
} }
/* Reset the priority to normal, inverting the changes made by pa_raise_priority() */
void pa_reset_priority(void) { void pa_reset_priority(void) {
#ifdef _POSIX_PRIORITY_SCHEDULING #ifdef _POSIX_PRIORITY_SCHEDULING
{ {
@ -394,6 +394,7 @@ void pa_reset_priority(void) {
setpriority(PRIO_PROCESS, 0, 0); setpriority(PRIO_PROCESS, 0, 0);
} }
/* Set the FD_CLOEXEC flag for a fd */
int pa_fd_set_cloexec(int fd, int b) { int pa_fd_set_cloexec(int fd, int b) {
int v; int v;
assert(fd >= 0); assert(fd >= 0);
@ -409,6 +410,9 @@ int pa_fd_set_cloexec(int fd, int b) {
return 0; return 0;
} }
/* Return the binary file name of the current process. Works on Linux
* only. This shoul be used for eyecandy only, don't rely on return
* non-NULL! */
char *pa_get_binary_name(char *s, size_t l) { char *pa_get_binary_name(char *s, size_t l) {
char path[PATH_MAX]; char path[PATH_MAX];
int i; int i;
@ -424,6 +428,8 @@ char *pa_get_binary_name(char *s, size_t l) {
return s; return s;
} }
/* Return a pointer to the filename inside a path (which is the last
* component). */
char *pa_path_get_filename(const char *p) { char *pa_path_get_filename(const char *p) {
char *fn; char *fn;
@ -433,6 +439,7 @@ char *pa_path_get_filename(const char *p) {
return (char*) p; return (char*) p;
} }
/* Try to parse a boolean string value.*/
int pa_parse_boolean(const char *v) { int pa_parse_boolean(const char *v) {
if (!strcmp(v, "1") || v[0] == 'y' || v[0] == 'Y' || v[0] == 't' || v[0] == 'T' || !strcasecmp(v, "on")) if (!strcmp(v, "1") || v[0] == 'y' || v[0] == 'Y' || v[0] == 't' || v[0] == 'T' || !strcasecmp(v, "on"))
@ -443,6 +450,10 @@ int pa_parse_boolean(const char *v) {
return -1; return -1;
} }
/* Split the specified string wherever one of the strings in delimiter
* occurs. Each time it is called returns a newly allocated string
* with pa_xmalloc(). The variable state points to, should be
* initiallized to NULL before the first call. */
char *pa_split(const char *c, const char *delimiter, const char**state) { char *pa_split(const char *c, const char *delimiter, const char**state) {
const char *current = *state ? *state : c; const char *current = *state ? *state : c;
size_t l; size_t l;
@ -459,8 +470,10 @@ char *pa_split(const char *c, const char *delimiter, const char**state) {
return pa_xstrndup(current, l); return pa_xstrndup(current, l);
} }
/* What is interpreted as whitespace? */
#define WHITESPACE " \t\n" #define WHITESPACE " \t\n"
/* Split a string into words. Otherwise similar to pa_split(). */
char *pa_split_spaces(const char *c, const char **state) { char *pa_split_spaces(const char *c, const char **state) {
const char *current = *state ? *state : c; const char *current = *state ? *state : c;
size_t l; size_t l;
@ -476,6 +489,7 @@ char *pa_split_spaces(const char *c, const char **state) {
return pa_xstrndup(current, l); return pa_xstrndup(current, l);
} }
/* Return the name of an UNIX signal. Similar to GNU's strsignal() */
const char *pa_strsignal(int sig) { const char *pa_strsignal(int sig) {
switch(sig) { switch(sig) {
case SIGINT: return "SIGINT"; case SIGINT: return "SIGINT";
@ -490,6 +504,7 @@ const char *pa_strsignal(int sig) {
} }
} }
/* Parse a libsamplrate compatible resampling implementation */
int pa_parse_resample_method(const char *string) { int pa_parse_resample_method(const char *string) {
assert(string); assert(string);
@ -507,6 +522,7 @@ int pa_parse_resample_method(const char *string) {
return -1; return -1;
} }
/* Check whether the specified GID and the group name match */
static int is_group(gid_t gid, const char *name) { static int is_group(gid_t gid, const char *name) {
struct group group, *result = NULL; struct group group, *result = NULL;
long n; long n;
@ -548,6 +564,7 @@ finish:
return r; return r;
} }
/* Check the current user is member of the specified group */
int pa_uid_in_group(const char *name, gid_t *gid) { int pa_uid_in_group(const char *name, gid_t *gid) {
gid_t *gids, tgid; gid_t *gids, tgid;
long n = sysconf(_SC_NGROUPS_MAX); long n = sysconf(_SC_NGROUPS_MAX);
@ -584,6 +601,7 @@ finish:
return r; return r;
} }
/* Lock or unlock a file entirely. (advisory) */
int pa_lock_fd(int fd, int b) { int pa_lock_fd(int fd, int b) {
struct flock flock; struct flock flock;
@ -601,6 +619,7 @@ int pa_lock_fd(int fd, int b) {
return 0; return 0;
} }
/* Remove trailing newlines from a string */
char* pa_strip_nl(char *s) { char* pa_strip_nl(char *s) {
assert(s); assert(s);
@ -608,6 +627,7 @@ char* pa_strip_nl(char *s) {
return s; return s;
} }
/* Create a temporary lock file and lock it. */
int pa_lock_lockfile(const char *fn) { int pa_lock_lockfile(const char *fn) {
int fd; int fd;
assert(fn); assert(fn);
@ -630,7 +650,7 @@ fail:
return -1; return -1;
} }
/* Unlock a temporary lcok file */
int pa_unlock_lockfile(int fd) { int pa_unlock_lockfile(int fd) {
int r = 0; int r = 0;
assert(fd >= 0); assert(fd >= 0);
@ -648,3 +668,50 @@ int pa_unlock_lockfile(int fd) {
return r; return r;
} }
/* 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 *e;
char h[PATH_MAX];
if (env && (e = getenv(env))) {
if (result)
*result = pa_xstrdup(e);
return fopen(e, "r");
}
if (local && pa_get_home_dir(h, sizeof(h))) {
FILE *f;
char *l;
l = pa_sprintf_malloc("%s/%s", h, local);
f = fopen(l, "r");
if (f || errno != ENOENT) {
if (result)
*result = l;
else
pa_xfree(l);
return f;
}
pa_xfree(l);
}
if (!global) {
if (result)
*result = NULL;
errno = ENOENT;
return NULL;
}
if (result)
*result = pa_xstrdup(global);
return fopen(global, "r");
}

View file

@ -25,6 +25,7 @@
#include <sys/types.h> #include <sys/types.h>
#include <inttypes.h> #include <inttypes.h>
#include <stdarg.h> #include <stdarg.h>
#include <stdio.h>
#include "gcc-printf.h" #include "gcc-printf.h"
#include "sample.h" #include "sample.h"
@ -46,7 +47,7 @@ char *pa_strlcpy(char *b, const char *s, size_t l);
char *pa_get_user_name(char *s, size_t l); char *pa_get_user_name(char *s, size_t l);
char *pa_get_host_name(char *s, size_t l); char *pa_get_host_name(char *s, size_t l);
char *pa_get_binary_name(char *s, size_t l); char *pa_get_binary_name(char *s, size_t l);
char *pa_get_home(char *s, size_t l); char *pa_get_home_dir(char *s, size_t l);
char *pa_path_get_filename(const char *p); char *pa_path_get_filename(const char *p);
@ -78,4 +79,6 @@ int pa_lock_fd(int fd, int b);
int pa_lock_lockfile(const char *fn); int pa_lock_lockfile(const char *fn);
int pa_unlock_lockfile(int fd); int pa_unlock_lockfile(int fd);
FILE *pa_open_config_file(const char *env, const char *global, const char *local, char **result);
#endif #endif