This file is part of polypaudio.
polypaudio is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published
- by the Free Software Foundation; either version 2 of the License,
- or (at your option) any later version.
+ it under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation; either version 2.1 of the
+ License, or (at your option) any later version.
polypaudio is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
+ Lesser General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with polypaudio; if not, write to the Free Software
+ You should have received a copy of the GNU Lesser General Public
+ License along with polypaudio; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
USA.
***/
#include <limits.h>
#include <unistd.h>
#include <grp.h>
+#include <netdb.h>
#include <samplerate.h>
#include "xmalloc.h"
#include "log.h"
+#define PA_RUNTIME_PATH_PREFIX "/tmp/polypaudio-"
+
/** Make a file descriptor nonblock. Doesn't do any error checking */
void pa_make_nonblock_fd(int fd) {
int v;
return -1;
}
+/* Creates a the parent directory of the specified path securely */
+int pa_make_secure_parent_dir(const char *fn) {
+ int ret = -1;
+ char *slash, *dir = pa_xstrdup(fn);
+
+ if (!(slash = strrchr(dir, '/')))
+ goto finish;
+ *slash = 0;
+
+ if (pa_make_secure_dir(dir) < 0)
+ goto finish;
+
+ ret = 0;
+
+finish:
+ pa_xfree(dir);
+ return ret;
+}
+
+
/** Calls read() in a loop. Makes sure that as much as 'size' bytes,
* unless EOF is reached or an error occured */
ssize_t pa_loop_read(int fd, void*data, size_t size) {
char *p;
assert(s && l > 0);
- if (!(p = getenv("USER")))
- if (!(p = getenv("LOGNAME")))
- if (!(p = getenv("USERNAME"))) {
-
+ if (!(p = getenv("USER")) && !(p = getenv("LOGNAME")) && !(p = getenv("USERNAME"))) {
+
#ifdef HAVE_GETPWUID_R
- if (getpwuid_r(getuid(), &pw, buf, sizeof(buf), &r) != 0 || !r) {
+ if (getpwuid_r(getuid(), &pw, buf, sizeof(buf), &r) != 0 || !r) {
#else
- /* XXX Not thread-safe, but needed on OSes (e.g. FreeBSD 4.X)
- * that do not support getpwuid_r. */
- if ((r = getpwuid(getuid())) == NULL) {
+ /* XXX Not thread-safe, but needed on OSes (e.g. FreeBSD 4.X)
+ * that do not support getpwuid_r. */
+ if ((r = getpwuid(getuid())) == NULL) {
#endif
- snprintf(s, l, "%lu", (unsigned long) getuid());
- return s;
- }
-
- p = r->pw_name;
+ snprintf(s, l, "%lu", (unsigned long) getuid());
+ return s;
}
+
+ p = r->pw_name;
+ }
return pa_strlcpy(s, p, l);
-}
+ }
/* Return the current hostname in the specified buffer. */
char *pa_get_host_name(char *s, size_t l) {
assert(s && l > 0);
- gethostname(s, l);
+ if (gethostname(s, l) < 0) {
+ pa_log(__FILE__": gethostname(): %s\n", strerror(errno));
+ return NULL;
+ }
s[l-1] = 0;
return s;
}
/* 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 buf[1024];
struct passwd pw, *r;
if ((e = getenv("HOME")))
return pa_strlcpy(s, e, l);
- if (getpwuid_r(getuid(), &pw, buf, sizeof(buf), &r) != 0 || !r)
+ if (getpwuid_r(getuid(), &pw, buf, sizeof(buf), &r) != 0 || !r) {
+ pa_log(__FILE__": getpwuid_r() failed\n");
return NULL;
+ }
return pa_strlcpy(s, r->pw_dir, l);
}
/* Raise the priority of the current process as much as possible and
sensible: set the nice level to -15 and enable realtime scheduling if
-supportted.*/
-
+supported.*/
void pa_raise_priority(void) {
if (setpriority(PRIO_PROCESS, 0, NICE_LEVEL) < 0)
#endif
}
+/* Reset the priority to normal, inverting the changes made by pa_raise_priority() */
void pa_reset_priority(void) {
#ifdef _POSIX_PRIORITY_SCHEDULING
{
setpriority(PRIO_PROCESS, 0, 0);
}
+/* Set the FD_CLOEXEC flag for a fd */
int pa_fd_set_cloexec(int fd, int b) {
int v;
assert(fd >= 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 path[PATH_MAX];
int i;
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 *fn;
return (char*) p;
}
+/* Try to parse a boolean string value.*/
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"))
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) {
const char *current = *state ? *state : c;
size_t l;
return pa_xstrndup(current, l);
}
+/* What is interpreted as whitespace? */
#define WHITESPACE " \t\n"
+/* Split a string into words. Otherwise similar to pa_split(). */
char *pa_split_spaces(const char *c, const char **state) {
const char *current = *state ? *state : c;
size_t l;
- if (!*current)
+ if (!*current || *c == 0)
return NULL;
current += strspn(current, WHITESPACE);
return pa_xstrndup(current, l);
}
+/* Return the name of an UNIX signal. Similar to GNU's strsignal() */
const char *pa_strsignal(int sig) {
switch(sig) {
case SIGINT: return "SIGINT";
}
}
+/* Parse a libsamplrate compatible resampling implementation */
int pa_parse_resample_method(const char *string) {
assert(string);
return -1;
}
+/* Check whether the specified GID and the group name match */
static int is_group(gid_t gid, const char *name) {
struct group group, *result = NULL;
long n;
return r;
}
+/* Check the current user is member of the specified group */
int pa_uid_in_group(const char *name, gid_t *gid) {
gid_t *gids, tgid;
long n = sysconf(_SC_NGROUPS_MAX);
return r;
}
+/* Lock or unlock a file entirely. (advisory) */
int pa_lock_fd(int fd, int b) {
struct flock flock;
return 0;
}
+/* Remove trailing newlines from a string */
char* pa_strip_nl(char *s) {
assert(s);
return s;
}
+/* Create a temporary lock file and lock it. */
int pa_lock_lockfile(const char *fn) {
int fd;
assert(fn);
return -1;
}
-
+/* Unlock a temporary lcok file */
int pa_unlock_lockfile(int fd) {
int r = 0;
assert(fd >= 0);
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");
+}
+
+/* Format the specified data as a hexademical string */
+char *pa_hexstr(const uint8_t* d, size_t dlength, char *s, size_t slength) {
+ size_t i = 0, j = 0;
+ const char hex[] = "0123456789abcdef";
+ assert(d && s && slength > 0);
+
+ while (i < dlength && j+3 <= slength) {
+ s[j++] = hex[*d >> 4];
+ s[j++] = hex[*d & 0xF];
+
+ d++;
+ i++;
+ }
+
+ s[j < slength ? j : slength] = 0;
+ return s;
+}
+
+/* Convert a hexadecimal digit to a number or -1 if invalid */
+static int hexc(char c) {
+ if (c >= '0' && c <= '9')
+ return c - '0';
+
+ if (c >= 'A' && c <= 'F')
+ return c - 'A' + 10;
+
+ if (c >= 'a' && c <= 'f')
+ return c - 'a' + 10;
+
+ return -1;
+}
+
+/* Parse a hexadecimal string as created by pa_hexstr() to a BLOB */
+size_t pa_parsehex(const char *p, uint8_t *d, size_t dlength) {
+ size_t j = 0;
+ assert(p && d);
+
+ while (j < dlength && *p) {
+ int b;
+
+ if ((b = hexc(*(p++))) < 0)
+ return (size_t) -1;
+
+ d[j] = (uint8_t) (b << 4);
+
+ if (!*p)
+ return (size_t) -1;
+
+ if ((b = hexc(*(p++))) < 0)
+ return (size_t) -1;
+
+ d[j] |= (uint8_t) b;
+ j++;
+ }
+
+ return j;
+}
+
+/* Return the fully qualified domain name in *s */
+char *pa_get_fqdn(char *s, size_t l) {
+ char hn[256];
+ struct addrinfo *a, hints;
+
+ if (!pa_get_host_name(hn, sizeof(hn)))
+ return NULL;
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_flags = AI_CANONNAME;
+
+ if (getaddrinfo(hn, NULL, &hints, &a) < 0 || !a || !a->ai_canonname || !*a->ai_canonname)
+ return pa_strlcpy(s, hn, l);
+
+ pa_strlcpy(s, a->ai_canonname, l);
+ freeaddrinfo(a);
+ return s;
+}
+
+/* Returns nonzero when *s starts with *pfx */
+int pa_startswith(const char *s, const char *pfx) {
+ size_t l;
+ assert(s && pfx);
+ l = strlen(pfx);
+
+ return strlen(s) >= l && strncmp(s, pfx, l) == 0;
+}
+
+/* if fn is null return the polypaudio run time path in s (/tmp/polypaudio)
+ * 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) {
+ char u[256];
+
+ if (fn && *fn == '/')
+ return pa_strlcpy(s, fn, l);
+
+ snprintf(s, l, PA_RUNTIME_PATH_PREFIX"%s%s%s", pa_get_user_name(u, sizeof(u)), fn ? "/" : "", fn ? fn : "");
+ return s;
+}