From c47e937011f00eebab7230cedb58fd59f16487b4 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 17 May 2006 20:09:57 +0000 Subject: split polypcore/util.[ch] into polypcore/core-util.[ch] and polyp/util.[ch] git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@917 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 31 +- src/modules/module-alsa-sink.c | 2 +- src/modules/module-alsa-source.c | 2 +- src/modules/module-combine.c | 2 +- src/modules/module-detect.c | 2 +- src/modules/module-esound-compat-spawnfd.c | 2 +- src/modules/module-esound-compat-spawnpid.c | 2 +- src/modules/module-esound-sink.c | 2 +- src/modules/module-jack-sink.c | 2 +- src/modules/module-jack-source.c | 2 +- src/modules/module-match.c | 4 +- src/modules/module-mmkbd-evdev.c | 2 +- src/modules/module-null-sink.c | 2 +- src/modules/module-oss-mmap.c | 2 +- src/modules/module-oss.c | 2 +- src/modules/module-pipe-sink.c | 2 +- src/modules/module-pipe-source.c | 2 +- src/modules/module-protocol-stub.c | 2 +- src/modules/module-solaris.c | 2 +- src/modules/module-tunnel.c | 2 +- src/modules/module-volume-restore.c | 4 +- src/modules/module-waveout.c | 2 +- src/modules/module-x11-publish.c | 2 +- src/modules/module-zeroconf-publish.c | 2 +- src/modules/oss-util.c | 2 +- src/polyp/util.c | 350 ++++++++ src/polyp/util.h | 48 + src/polypcore/authkey.c | 2 +- src/polypcore/cli-command.c | 2 +- src/polypcore/conf-parser.c | 2 +- src/polypcore/core-scache.c | 2 +- src/polypcore/core-util.c | 1012 +++++++++++++++++++++ src/polypcore/core-util.h | 89 ++ src/polypcore/core.c | 2 +- src/polypcore/iochannel.c | 2 +- src/polypcore/log.c | 2 +- src/polypcore/modargs.c | 2 +- src/polypcore/modinfo.c | 2 +- src/polypcore/module.c | 2 +- src/polypcore/namereg.c | 2 +- src/polypcore/parseaddr.c | 2 +- src/polypcore/pdispatch.c | 2 +- src/polypcore/pid.c | 2 +- src/polypcore/poll.c | 2 +- src/polypcore/protocol-esound.c | 2 +- src/polypcore/protocol-native.c | 2 +- src/polypcore/random.c | 2 +- src/polypcore/sink.c | 2 +- src/polypcore/socket-client.c | 2 +- src/polypcore/socket-server.c | 2 +- src/polypcore/socket-util.c | 2 +- src/polypcore/strlist.c | 2 +- src/polypcore/util.c | 1293 --------------------------- src/polypcore/util.h | 105 --- src/utils/pabrowse.c | 4 +- 55 files changed, 1562 insertions(+), 1468 deletions(-) create mode 100644 src/polyp/util.c create mode 100644 src/polyp/util.h create mode 100644 src/polypcore/core-util.c create mode 100644 src/polypcore/core-util.h delete mode 100644 src/polypcore/util.c delete mode 100644 src/polypcore/util.h diff --git a/src/Makefile.am b/src/Makefile.am index 72db5f80..e7ad2fd4 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -271,17 +271,9 @@ mainloop_test_glib12_CFLAGS = $(mainloop_test_CFLAGS) $(GLIB12_CFLAGS) -DGLIB_MA mainloop_test_glib12_LDADD = $(mainloop_test_LDADD) $(GLIB12_LIBS) libpolyp-mainloop-glib12.la mainloop_test_glib12_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) -memblockq_test_SOURCES = \ - tests/memblockq-test.c \ - polyp/xmalloc.c \ - polypcore/memblockq.c \ - polypcore/log.c \ - polypcore/memblock.c \ - polypcore/util.c \ - polypcore/mcalign.c \ - polypcore/memchunk.c +memblockq_test_SOURCES = tests/memblockq-test.c memblockq_test_CFLAGS = $(AM_CFLAGS) -memblockq_test_LDADD = $(AM_LDADD) $(WINSOCK_LIBS) +memblockq_test_LDADD = $(AM_LDADD) $(WINSOCK_LIBS) libpolypcore.la memblockq_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) sync_playback_SOURCES = tests/sync-playback.c @@ -315,7 +307,8 @@ polypinclude_HEADERS = \ polyp/sample.h \ polyp/utf8.h \ polyp/volume.h \ - polyp/xmalloc.h + polyp/xmalloc.h \ + polyp/util.h if HAVE_HOWL polypinclude_HEADERS += \ @@ -364,8 +357,7 @@ libpolyp_la_SOURCES = \ polyp/mainloop-signal.c polyp/mainloop-signal.h \ polyp/thread-mainloop.c polyp/thread-mainloop.h \ polyp/xmalloc.c polyp/xmalloc.h \ - polypcore/pipe.c polypcore/pipe.h \ - polypcore/poll.c polypcore/poll.h + polyp/util.c polyp/util.h # Internal stuff that is shared with libpolypcore libpolyp_la_SOURCES += \ @@ -394,9 +386,11 @@ libpolyp_la_SOURCES += \ polypcore/strbuf.c polypcore/strbuf.h \ polypcore/strlist.c polypcore/strlist.h \ polypcore/tagstruct.c polypcore/tagstruct.h \ - polypcore/util.c polypcore/util.h \ + polypcore/core-util.c polypcore/core-util.h \ polypcore/winsock.h \ - polypcore/llist.h + polypcore/llist.h \ + polypcore/pipe.c polypcore/pipe.h \ + polypcore/poll.c polypcore/poll.h if OS_IS_WIN32 libpolyp_la_SOURCES += \ @@ -487,7 +481,7 @@ polypcoreinclude_HEADERS = \ polypcore/source-output.h \ polypcore/strbuf.h \ polypcore/tokenizer.h \ - polypcore/util.h + polypcore/core-util.h lib_LTLIBRARIES += libpolypcore.la @@ -500,7 +494,8 @@ libpolypcore_la_SOURCES = \ polyp/sample.c polyp/sample.h \ polyp/volume.c polyp/volume.h \ polyp/utf8.c polyp/utf8.h \ - polyp/xmalloc.c polyp/xmalloc.h + polyp/xmalloc.c polyp/xmalloc.h \ + polyp/util.c polyp/util.h # Pure core stuff (some are shared in libpolyp though). libpolypcore_la_SOURCES += \ @@ -547,7 +542,7 @@ libpolypcore_la_SOURCES += \ polypcore/source-output.c polypcore/source-output.h \ polypcore/strbuf.c polypcore/strbuf.h \ polypcore/tokenizer.c polypcore/tokenizer.h \ - polypcore/util.c polypcore/util.h \ + polypcore/core-util.c polypcore/core-util.h \ polypcore/winsock.h if OS_IS_WIN32 diff --git a/src/modules/module-alsa-sink.c b/src/modules/module-alsa-sink.c index 94de771c..e768e16a 100644 --- a/src/modules/module-alsa-sink.c +++ b/src/modules/module-alsa-sink.c @@ -41,7 +41,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/modules/module-alsa-source.c b/src/modules/module-alsa-source.c index b9d1ff87..654f3e49 100644 --- a/src/modules/module-alsa-source.c +++ b/src/modules/module-alsa-source.c @@ -41,7 +41,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/modules/module-combine.c b/src/modules/module-combine.c index b31fe56e..5047fc30 100644 --- a/src/modules/module-combine.c +++ b/src/modules/module-combine.c @@ -34,7 +34,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/modules/module-detect.c b/src/modules/module-detect.c index ea14e68f..2edbea5e 100644 --- a/src/modules/module-detect.c +++ b/src/modules/module-detect.c @@ -38,7 +38,7 @@ #include #include #include -#include +#include #include "module-detect-symdef.h" diff --git a/src/modules/module-esound-compat-spawnfd.c b/src/modules/module-esound-compat-spawnfd.c index 9b72448f..bf89ca70 100644 --- a/src/modules/module-esound-compat-spawnfd.c +++ b/src/modules/module-esound-compat-spawnfd.c @@ -30,7 +30,7 @@ #include #include -#include +#include #include #include "module-esound-compat-spawnfd-symdef.h" diff --git a/src/modules/module-esound-compat-spawnpid.c b/src/modules/module-esound-compat-spawnpid.c index f8c07d31..895abec3 100644 --- a/src/modules/module-esound-compat-spawnpid.c +++ b/src/modules/module-esound-compat-spawnpid.c @@ -29,7 +29,7 @@ #include #include -#include +#include #include #include diff --git a/src/modules/module-esound-sink.c b/src/modules/module-esound-sink.c index 1d61e01b..cf3ce807 100644 --- a/src/modules/module-esound-sink.c +++ b/src/modules/module-esound-sink.c @@ -38,7 +38,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/modules/module-jack-sink.c b/src/modules/module-jack-sink.c index 1aa73495..96db837a 100644 --- a/src/modules/module-jack-sink.c +++ b/src/modules/module-jack-sink.c @@ -41,7 +41,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/modules/module-jack-source.c b/src/modules/module-jack-source.c index 29c46d85..3d783145 100644 --- a/src/modules/module-jack-source.c +++ b/src/modules/module-jack-source.c @@ -41,7 +41,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/modules/module-match.c b/src/modules/module-match.c index 1692b5d8..c7ca12a5 100644 --- a/src/modules/module-match.c +++ b/src/modules/module-match.c @@ -35,12 +35,12 @@ #include #include -#include +#include #include #include #include #include -#include +#include #include "module-match-symdef.h" diff --git a/src/modules/module-mmkbd-evdev.c b/src/modules/module-mmkbd-evdev.c index 654fbaa4..55f0b2c8 100644 --- a/src/modules/module-mmkbd-evdev.c +++ b/src/modules/module-mmkbd-evdev.c @@ -40,7 +40,7 @@ #include #include #include -#include +#include #include "module-mmkbd-evdev-symdef.h" diff --git a/src/modules/module-null-sink.c b/src/modules/module-null-sink.c index 2cc49063..78850011 100644 --- a/src/modules/module-null-sink.c +++ b/src/modules/module-null-sink.c @@ -38,7 +38,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/modules/module-oss-mmap.c b/src/modules/module-oss-mmap.c index 82e7d66d..a1b40389 100644 --- a/src/modules/module-oss-mmap.c +++ b/src/modules/module-oss-mmap.c @@ -43,7 +43,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/modules/module-oss.c b/src/modules/module-oss.c index 46d100f1..9233420d 100644 --- a/src/modules/module-oss.c +++ b/src/modules/module-oss.c @@ -42,7 +42,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/modules/module-pipe-sink.c b/src/modules/module-pipe-sink.c index b59808fc..6492ba6a 100644 --- a/src/modules/module-pipe-sink.c +++ b/src/modules/module-pipe-sink.c @@ -38,7 +38,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/modules/module-pipe-source.c b/src/modules/module-pipe-source.c index 4f3f9a6c..9f755440 100644 --- a/src/modules/module-pipe-source.c +++ b/src/modules/module-pipe-source.c @@ -38,7 +38,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/modules/module-protocol-stub.c b/src/modules/module-protocol-stub.c index 79a59cd5..cfe661a3 100644 --- a/src/modules/module-protocol-stub.c +++ b/src/modules/module-protocol-stub.c @@ -47,7 +47,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/modules/module-solaris.c b/src/modules/module-solaris.c index d82e3362..77eb4e49 100644 --- a/src/modules/module-solaris.c +++ b/src/modules/module-solaris.c @@ -48,7 +48,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/modules/module-tunnel.c b/src/modules/module-tunnel.c index a2a1e33d..81c32287 100644 --- a/src/modules/module-tunnel.c +++ b/src/modules/module-tunnel.c @@ -35,7 +35,7 @@ #include #include -#include +#include #include #include #include diff --git a/src/modules/module-volume-restore.c b/src/modules/module-volume-restore.c index ea40d862..e74567bc 100644 --- a/src/modules/module-volume-restore.c +++ b/src/modules/module-volume-restore.c @@ -35,12 +35,12 @@ #include #include -#include +#include #include #include #include #include -#include +#include #include #include "module-volume-restore-symdef.h" diff --git a/src/modules/module-waveout.c b/src/modules/module-waveout.c index 3d1f1b01..ce9ea84d 100644 --- a/src/modules/module-waveout.c +++ b/src/modules/module-waveout.c @@ -36,7 +36,7 @@ #include #include #include -#include +#include #include #include "module-waveout-symdef.h" diff --git a/src/modules/module-x11-publish.c b/src/modules/module-x11-publish.c index e974487d..eddcb3b8 100644 --- a/src/modules/module-x11-publish.c +++ b/src/modules/module-x11-publish.c @@ -41,7 +41,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/modules/module-zeroconf-publish.c b/src/modules/module-zeroconf-publish.c index e5dce755..5c5db286 100644 --- a/src/modules/module-zeroconf-publish.c +++ b/src/modules/module-zeroconf-publish.c @@ -35,7 +35,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/modules/oss-util.c b/src/modules/oss-util.c index 2c573b2f..a84276f1 100644 --- a/src/modules/oss-util.c +++ b/src/modules/oss-util.c @@ -34,7 +34,7 @@ #include #include -#include +#include #include #include "oss-util.h" diff --git a/src/polyp/util.c b/src/polyp/util.c new file mode 100644 index 00000000..dd597322 --- /dev/null +++ b/src/polyp/util.c @@ -0,0 +1,350 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + 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 + Lesser General Public License for more details. + + 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. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_NETDB_H +#include +#endif + +#ifdef HAVE_PWD_H +#include +#endif + +#ifdef HAVE_GRP_H +#include +#endif + +#ifdef HAVE_WINDOWS_H +#include +#endif + +#include +#include +#include + +#include "util.h" + +#ifndef OS_IS_WIN32 +#define PATH_SEP '/' +#else +#define PATH_SEP '\\' +#endif + +/* Return the current username in the specified string buffer. */ +char *pa_get_user_name(char *s, size_t l) { + char *p; + char buf[1024]; + +#ifdef HAVE_PWD_H + struct passwd pw, *r; +#endif + + assert(s && l > 0); + + if (!(p = getenv("USER")) && !(p = getenv("LOGNAME")) && !(p = getenv("USERNAME"))) { +#ifdef HAVE_PWD_H + +#ifdef HAVE_GETPWUID_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) { +#endif + snprintf(s, l, "%lu", (unsigned long) getuid()); + return s; + } + + p = r->pw_name; + +#elif defined(OS_IS_WIN32) /* HAVE_PWD_H */ + DWORD size = sizeof(buf); + + if (!GetUserName(buf, &size)) + return NULL; + + p = buf; + +#else /* HAVE_PWD_H */ + return NULL; +#endif /* HAVE_PWD_H */ + } + + 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); + if (gethostname(s, l) < 0) { + pa_log(__FILE__": gethostname(): %s", strerror(errno)); + return NULL; + } + s[l-1] = 0; + return s; +} + +/* Return the home directory of the current user */ +char *pa_get_home_dir(char *s, size_t l) { + char *e; + +#ifdef HAVE_PWD_H + char buf[1024]; + struct passwd pw, *r; +#endif + + assert(s && l); + + if ((e = getenv("HOME"))) + return pa_strlcpy(s, e, l); + + if ((e = getenv("USERPROFILE"))) + return pa_strlcpy(s, e, l); + +#ifdef HAVE_PWD_H +#ifdef HAVE_GETPWUID_R + if (getpwuid_r(getuid(), &pw, buf, sizeof(buf), &r) != 0 || !r) { + pa_log(__FILE__": getpwuid_r() failed"); +#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) { + pa_log(__FILE__": getpwuid_r() failed"); +#endif + return NULL; + } + + return pa_strlcpy(s, r->pw_dir, l); +#else /* HAVE_PWD_H */ + return NULL; +#endif +} + +struct timeval *pa_gettimeofday(struct timeval *tv) { +#ifdef HAVE_GETTIMEOFDAY + assert(tv); + + return gettimeofday(tv, NULL) < 0 ? NULL : tv; +#elif defined(OS_IS_WIN32) + /* + * Copied from implementation by Steven Edwards (LGPL). + * Found on wine mailing list. + */ + +#if defined(_MSC_VER) || defined(__BORLANDC__) +#define EPOCHFILETIME (116444736000000000i64) +#else +#define EPOCHFILETIME (116444736000000000LL) +#endif + + FILETIME ft; + LARGE_INTEGER li; + __int64 t; + + assert(tv); + + GetSystemTimeAsFileTime(&ft); + li.LowPart = ft.dwLowDateTime; + li.HighPart = ft.dwHighDateTime; + t = li.QuadPart; /* In 100-nanosecond intervals */ + t -= EPOCHFILETIME; /* Offset to the Epoch time */ + t /= 10; /* In microseconds */ + tv->tv_sec = (long)(t / 1000000); + tv->tv_usec = (long)(t % 1000000); + + return tv; +#else +#error "Platform lacks gettimeofday() or equivalent function." +#endif +} + +/* Calculate the difference between the two specfified timeval + * timestamsps. */ +pa_usec_t pa_timeval_diff(const struct timeval *a, const struct timeval *b) { + pa_usec_t r; + assert(a && b); + + /* Check which whan is the earlier time and swap the two arguments if reuqired. */ + if (pa_timeval_cmp(a, b) < 0) { + const struct timeval *c; + c = a; + a = b; + b = c; + } + + /* Calculate the second difference*/ + r = ((pa_usec_t) a->tv_sec - b->tv_sec)* 1000000; + + /* Calculate the microsecond difference */ + if (a->tv_usec > b->tv_usec) + r += ((pa_usec_t) a->tv_usec - b->tv_usec); + else if (a->tv_usec < b->tv_usec) + r -= ((pa_usec_t) b->tv_usec - a->tv_usec); + + return r; +} + +/* Compare the two timeval structs and return 0 when equal, negative when a < b, positive otherwse */ +int pa_timeval_cmp(const struct timeval *a, const struct timeval *b) { + assert(a && b); + + if (a->tv_sec < b->tv_sec) + return -1; + + if (a->tv_sec > b->tv_sec) + return 1; + + if (a->tv_usec < b->tv_usec) + return -1; + + if (a->tv_usec > b->tv_usec) + return 1; + + return 0; +} + +/* Return the time difference between now and the specified timestamp */ +pa_usec_t pa_timeval_age(const struct timeval *tv) { + struct timeval now; + assert(tv); + + return pa_timeval_diff(pa_gettimeofday(&now), tv); +} + +/* Add the specified time inmicroseconds to the specified timeval structure */ +void pa_timeval_add(struct timeval *tv, pa_usec_t v) { + unsigned long secs; + assert(tv); + + secs = (v/1000000); + tv->tv_sec += (unsigned long) secs; + v -= secs*1000000; + + tv->tv_usec += v; + + /* Normalize */ + while (tv->tv_usec >= 1000000) { + tv->tv_sec++; + tv->tv_usec -= 1000000; + } +} + +/* 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) { + +#ifdef HAVE_READLINK + char path[PATH_MAX]; + int i; + assert(s && l); + + /* This works on Linux only */ + + snprintf(path, sizeof(path), "/proc/%u/exe", (unsigned) getpid()); + if ((i = readlink(path, s, l-1)) < 0) + return NULL; + + s[i] = 0; + return s; +#elif defined(OS_IS_WIN32) + char path[PATH_MAX]; + if (!GetModuleFileName(NULL, path, PATH_MAX)) + return NULL; + pa_strlcpy(s, pa_path_get_filename(path), l); + return s; +#else + return NULL; +#endif +} + +/* Return a pointer to the filename inside a path (which is the last + * component). */ +const char *pa_path_get_filename(const char *p) { + char *fn; + + if ((fn = strrchr(p, PATH_SEP))) + return fn+1; + + return (const char*) p; +} + +/* Return the fully qualified domain name in *s */ +char *pa_get_fqdn(char *s, size_t l) { + char hn[256]; +#ifdef HAVE_GETADDRINFO + struct addrinfo *a, hints; +#endif + + if (!pa_get_host_name(hn, sizeof(hn))) + return NULL; + +#ifdef HAVE_GETADDRINFO + 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; +#else + return pa_strlcpy(s, hn, l); +#endif +} + +/* Wait t milliseconds */ +int pa_msleep(unsigned long t) { +#ifdef OS_IS_WIN32 + Sleep(t); + return 0; +#elif defined(HAVE_NANOSLEEP) + struct timespec ts; + + ts.tv_sec = t/1000; + ts.tv_nsec = (t % 1000) * 1000000; + + return nanosleep(&ts, NULL); +#else +#error "Platform lacks a sleep function." +#endif +} diff --git a/src/polyp/util.h b/src/polyp/util.h new file mode 100644 index 00000000..37232d9f --- /dev/null +++ b/src/polyp/util.h @@ -0,0 +1,48 @@ +#ifndef fooutilhfoo +#define fooutilhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + 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 + Lesser General Public License for more details. + + 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 +#include + +#include + +struct timeval; + +char *pa_get_user_name(char *s, size_t l); +char *pa_get_host_name(char *s, size_t l); +char *pa_get_fqdn(char *s, size_t l); +char *pa_get_home_dir(char *s, size_t l); + +char *pa_get_binary_name(char *s, size_t l); +const char *pa_path_get_filename(const char *p); + +struct timeval *pa_gettimeofday(struct timeval *tv); +pa_usec_t pa_timeval_diff(const struct timeval *a, const struct timeval *b); +int pa_timeval_cmp(const struct timeval *a, const struct timeval *b); +pa_usec_t pa_timeval_age(const struct timeval *tv); +void pa_timeval_add(struct timeval *tv, pa_usec_t v); + +int pa_msleep(unsigned long t); + +#endif diff --git a/src/polypcore/authkey.c b/src/polypcore/authkey.c index 6eafb672..1231c7a2 100644 --- a/src/polypcore/authkey.c +++ b/src/polypcore/authkey.c @@ -35,7 +35,7 @@ #include #include -#include +#include #include #include diff --git a/src/polypcore/cli-command.c b/src/polypcore/cli-command.c index 5556bcb3..3adc9a21 100644 --- a/src/polypcore/cli-command.c +++ b/src/polypcore/cli-command.c @@ -48,7 +48,7 @@ #include #include #include -#include +#include #include "cli-command.h" diff --git a/src/polypcore/conf-parser.c b/src/polypcore/conf-parser.c index 64e66c2e..bc99b871 100644 --- a/src/polypcore/conf-parser.c +++ b/src/polypcore/conf-parser.c @@ -31,7 +31,7 @@ #include #include -#include +#include #include "conf-parser.h" diff --git a/src/polypcore/core-scache.c b/src/polypcore/core-scache.c index 8080fcd6..068f2361 100644 --- a/src/polypcore/core-scache.c +++ b/src/polypcore/core-scache.c @@ -52,7 +52,7 @@ #include #include #include -#include +#include #include #include "core-scache.h" diff --git a/src/polypcore/core-util.c b/src/polypcore/core-util.c new file mode 100644 index 00000000..36044c81 --- /dev/null +++ b/src/polypcore/core-util.c @@ -0,0 +1,1012 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + 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 + Lesser General Public License for more details. + + 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. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_SCHED_H +#include +#endif + +#ifdef HAVE_SYS_RESOURCE_H +#include +#endif + +#ifdef HAVE_PTHREAD +#include +#endif + +#ifdef HAVE_NETDB_H +#include +#endif + +#ifdef HAVE_WINDOWS_H +#include +#endif + +#ifdef HAVE_PWD_H +#include +#endif + +#ifdef HAVE_GRP_H +#include +#endif + +#include + +#include +#include + +#include +#include + +#include "core-util.h" + +#ifndef OS_IS_WIN32 +#define PA_RUNTIME_PATH_PREFIX "/tmp/polypaudio-" +#define PATH_SEP '/' +#else +#define PA_RUNTIME_PATH_PREFIX "%TEMP%\\polypaudio-" +#define PATH_SEP '\\' +#endif + +#ifdef OS_IS_WIN32 + +#define POLYP_ROOTENV "POLYP_ROOT" + +int pa_set_root(HANDLE handle) { + char library_path[MAX_PATH + sizeof(POLYP_ROOTENV) + 1], *sep; + + strcpy(library_path, POLYP_ROOTENV "="); + + if (!GetModuleFileName(handle, library_path + sizeof(POLYP_ROOTENV), MAX_PATH)) + return 0; + + sep = strrchr(library_path, '\\'); + if (sep) + *sep = '\0'; + + if (_putenv(library_path) < 0) + return 0; + + return 1; +} + +#endif + +/** Make a file descriptor nonblock. Doesn't do any error checking */ +void pa_make_nonblock_fd(int fd) { +#ifdef O_NONBLOCK + int v; + assert(fd >= 0); + + if ((v = fcntl(fd, F_GETFL)) >= 0) + if (!(v & O_NONBLOCK)) + fcntl(fd, F_SETFL, v|O_NONBLOCK); +#elif defined(OS_IS_WIN32) + u_long arg = 1; + if (ioctlsocket(fd, FIONBIO, &arg) < 0) { + if (WSAGetLastError() == WSAENOTSOCK) + pa_log_warn(__FILE__": WARNING: Only sockets can be made non-blocking!"); + } +#else + pa_log_warn(__FILE__": WARNING: Non-blocking I/O not supported.!"); +#endif +} + +/** Creates a directory securely */ +int pa_make_secure_dir(const char* dir) { + struct stat st; + assert(dir); + +#ifdef OS_IS_WIN32 + if (mkdir(dir) < 0) +#else + if (mkdir(dir, 0700) < 0) +#endif + if (errno != EEXIST) + return -1; + +#ifdef HAVE_CHOWN + chown(dir, getuid(), getgid()); +#endif +#ifdef HAVE_CHMOD + chmod(dir, 0700); +#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 != getuid()) || ((st.st_mode & 0777) != 0700)) + goto fail; +#else + fprintf(stderr, "FIXME: pa_make_secure_dir()\n"); +#endif + + return 0; + +fail: + rmdir(dir); + return -1; +} + +/* Return a newly allocated sting containing the parent directory of the specified file */ +char *pa_parent_dir(const char *fn) { + char *slash, *dir = pa_xstrdup(fn); + + slash = (char*) pa_path_get_filename(dir); + if (slash == fn) + return NULL; + + *(slash-1) = 0; + return dir; +} + +/* Creates a the parent directory of the specified path securely */ +int pa_make_secure_parent_dir(const char *fn) { + int ret = -1; + char *dir; + + if (!(dir = pa_parent_dir(fn))) + goto finish; + + if (pa_make_secure_dir(dir) < 0) + goto finish; + + ret = 0; + +finish: + pa_xfree(dir); + return ret; +} + +/** Platform independent read function. Necessary since not all systems + * treat all file descriptors equal. */ +ssize_t pa_read(int fd, void *buf, size_t count) { + ssize_t r; + +#ifdef OS_IS_WIN32 + r = recv(fd, buf, count, 0); + if (r < 0) { + if (WSAGetLastError() != WSAENOTSOCK) { + errno = WSAGetLastError(); + return r; + } + } + + if (r < 0) +#endif + r = read(fd, buf, count); + + return r; +} + +/** Similar to pa_read(), but handles writes */ +ssize_t pa_write(int fd, const void *buf, size_t count) { + ssize_t r; + +#ifdef OS_IS_WIN32 + r = send(fd, buf, count, 0); + if (r < 0) { + if (WSAGetLastError() != WSAENOTSOCK) { + errno = WSAGetLastError(); + return r; + } + } + + if (r < 0) +#endif + r = write(fd, buf, count); + + return r; +} + +/** 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) { + ssize_t ret = 0; + assert(fd >= 0 && data && size); + + while (size > 0) { + ssize_t r; + + if ((r = pa_read(fd, data, size)) < 0) + return r; + + if (r == 0) + break; + + ret += r; + data = (uint8_t*) data + r; + size -= r; + } + + return ret; +} + +/** Similar to pa_loop_read(), but wraps write() */ +ssize_t pa_loop_write(int fd, const void*data, size_t size) { + ssize_t ret = 0; + assert(fd >= 0 && data && size); + + while (size > 0) { + ssize_t r; + + if ((r = pa_write(fd, data, size)) < 0) + return r; + + if (r == 0) + break; + + ret += r; + data = (const uint8_t*) data + r; + size -= r; + } + + return ret; +} + +/* Print a warning messages in case that the given signal is not + * blocked or trapped */ +void pa_check_signal_is_blocked(int sig) { +#ifdef HAVE_SIGACTION + struct sigaction sa; + sigset_t set; + + /* If POSIX threads are supported use thread-aware + * pthread_sigmask() function, to check if the signal is + * blocked. Otherwise fall back to sigprocmask() */ + +#ifdef HAVE_PTHREAD + if (pthread_sigmask(SIG_SETMASK, NULL, &set) < 0) { +#endif + if (sigprocmask(SIG_SETMASK, NULL, &set) < 0) { + pa_log(__FILE__": sigprocmask() failed: %s", strerror(errno)); + return; + } +#ifdef HAVE_PTHREAD + } +#endif + + if (sigismember(&set, sig)) + return; + + /* Check whether the signal is trapped */ + + if (sigaction(sig, NULL, &sa) < 0) { + pa_log(__FILE__": sigaction() failed: %s", strerror(errno)); + return; + } + + if (sa.sa_handler != SIG_DFL) + return; + + pa_log(__FILE__": WARNING: %s is not trapped. This might cause malfunction!", pa_strsignal(sig)); +#else /* HAVE_SIGACTION */ + pa_log(__FILE__": WARNING: %s might not be trapped. This might cause malfunction!", pa_strsignal(sig)); +#endif +} + +/* The following function is based on an example from the GNU libc + * documentation. This function is similar to GNU's asprintf(). */ +char *pa_sprintf_malloc(const char *format, ...) { + int size = 100; + char *c = NULL; + + assert(format); + + for(;;) { + int r; + va_list ap; + + c = pa_xrealloc(c, size); + + va_start(ap, format); + r = vsnprintf(c, size, format, ap); + va_end(ap); + + if (r > -1 && r < size) + return c; + + if (r > -1) /* glibc 2.1 */ + size = r+1; + else /* glibc 2.0 */ + size *= 2; + } +} + +/* Same as the previous function, but use a va_list instead of an + * ellipsis */ +char *pa_vsprintf_malloc(const char *format, va_list ap) { + int size = 100; + char *c = NULL; + + assert(format); + + for(;;) { + int r; + c = pa_xrealloc(c, size); + r = vsnprintf(c, size, format, ap); + + if (r > -1 && r < size) + return c; + + if (r > -1) /* glibc 2.1 */ + size = r+1; + else /* glibc 2.0 */ + size *= 2; + } +} + +/* Similar to OpenBSD's strlcpy() function */ +char *pa_strlcpy(char *b, const char *s, size_t l) { + assert(b && s && l > 0); + + strncpy(b, s, l); + b[l-1] = 0; + return b; +} + +#define NICE_LEVEL (-15) + +/* Raise the priority of the current process as much as possible and +sensible: set the nice level to -15 and enable realtime scheduling if +supported.*/ +void pa_raise_priority(void) { + +#ifdef HAVE_SYS_RESOURCE_H + if (setpriority(PRIO_PROCESS, 0, NICE_LEVEL) < 0) + pa_log_warn(__FILE__": setpriority() failed: %s", strerror(errno)); + else + pa_log_info(__FILE__": Successfully gained nice level %i.", NICE_LEVEL); +#endif + +#ifdef _POSIX_PRIORITY_SCHEDULING + { + struct sched_param sp; + + if (sched_getparam(0, &sp) < 0) { + pa_log(__FILE__": sched_getparam() failed: %s", strerror(errno)); + return; + } + + sp.sched_priority = 1; + if (sched_setscheduler(0, SCHED_FIFO, &sp) < 0) { + pa_log_warn(__FILE__": sched_setscheduler() failed: %s", strerror(errno)); + return; + } + + pa_log_info(__FILE__": Successfully enabled SCHED_FIFO scheduling."); + } +#endif + +#ifdef OS_IS_WIN32 + if (!SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS)) + pa_log_warn(__FILE__": SetPriorityClass() failed: 0x%08X", GetLastError()); + else + pa_log_info(__FILE__": Successfully gained high priority class."); +#endif +} + +/* Reset the priority to normal, inverting the changes made by pa_raise_priority() */ +void pa_reset_priority(void) { +#ifdef OS_IS_WIN32 + SetPriorityClass(GetCurrentProcess(), NORMAL_PRIORITY_CLASS); +#endif + +#ifdef _POSIX_PRIORITY_SCHEDULING + { + struct sched_param sp; + sched_getparam(0, &sp); + sp.sched_priority = 0; + sched_setscheduler(0, SCHED_OTHER, &sp); + } +#endif + +#ifdef HAVE_SYS_RESOURCE_H + setpriority(PRIO_PROCESS, 0, 0); +#endif +} + +/* Set the FD_CLOEXEC flag for a fd */ +int pa_fd_set_cloexec(int fd, int b) { + +#ifdef FD_CLOEXEC + int v; + assert(fd >= 0); + + if ((v = fcntl(fd, F_GETFD, 0)) < 0) + return -1; + + v = (v & ~FD_CLOEXEC) | (b ? FD_CLOEXEC : 0); + + if (fcntl(fd, F_SETFD, v) < 0) + return -1; +#endif + + return 0; +} + +/* 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; + else if (!strcmp(v, "0") || v[0] == 'n' || v[0] == 'N' || v[0] == 'f' || v[0] == 'F' || !strcasecmp(v, "off")) + return 0; + + 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; + + if (!*current) + return NULL; + + l = strcspn(current, delimiter); + *state = current+l; + + if (**state) + (*state)++; + + 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 || *c == 0) + return NULL; + + current += strspn(current, WHITESPACE); + l = strcspn(current, WHITESPACE); + + *state = 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) { + switch(sig) { + case SIGINT: return "SIGINT"; + case SIGTERM: return "SIGTERM"; +#ifdef SIGUSR1 + case SIGUSR1: return "SIGUSR1"; +#endif +#ifdef SIGUSR2 + case SIGUSR2: return "SIGUSR2"; +#endif +#ifdef SIGXCPU + case SIGXCPU: return "SIGXCPU"; +#endif +#ifdef SIGPIPE + case SIGPIPE: return "SIGPIPE"; +#endif +#ifdef SIGCHLD + case SIGCHLD: return "SIGCHLD"; +#endif +#ifdef SIGHUP + case SIGHUP: return "SIGHUP"; +#endif + default: return "UNKNOWN SIGNAL"; + } +} + +#ifdef HAVE_GRP_H + +/* 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; + void *data; + int r = -1; + +#ifdef HAVE_GETGRGID_R +#ifdef _SC_GETGR_R_SIZE_MAX + n = sysconf(_SC_GETGR_R_SIZE_MAX); +#else + n = -1; +#endif + if (n < 0) n = 512; + data = pa_xmalloc(n); + + if (getgrgid_r(gid, &group, data, n, &result) < 0 || !result) { + pa_log(__FILE__ ": getgrgid_r(%u) failed: %s", gid, strerror(errno)); + goto finish; + } + + r = strcmp(name, result->gr_name) == 0; + +finish: + pa_xfree(data); +#else + /* XXX Not thread-safe, but needed on OSes (e.g. FreeBSD 4.X) that do not + * support getgrgid_r. */ + if ((result = getgrgid(gid)) == NULL) { + pa_log(__FILE__ ": getgrgid(%u) failed: %s", gid, strerror(errno)); + goto finish; + } + + r = strcmp(name, result->gr_name) == 0; + +finish: +#endif + + return r; +} + +/* Check the current user is member of the specified group */ +int pa_own_uid_in_group(const char *name, gid_t *gid) { + GETGROUPS_T *gids, tgid; + int n = sysconf(_SC_NGROUPS_MAX); + int r = -1, i; + + assert(n > 0); + + gids = pa_xmalloc(sizeof(GETGROUPS_T)*n); + + if ((n = getgroups(n, gids)) < 0) { + pa_log(__FILE__": getgroups() failed: %s", strerror(errno)); + goto finish; + } + + for (i = 0; i < n; i++) { + if (is_group(gids[i], name) > 0) { + *gid = gids[i]; + r = 1; + goto finish; + } + } + + if (is_group(tgid = getgid(), name) > 0) { + *gid = tgid; + r = 1; + goto finish; + } + + r = 0; + +finish: + + pa_xfree(gids); + return r; +} + +int pa_uid_in_group(uid_t uid, const char *name) { + char *g_buf, *p_buf; + long g_n, p_n; + struct group grbuf, *gr; + char **i; + int r = -1; + + g_n = sysconf(_SC_GETGR_R_SIZE_MAX); + g_buf = pa_xmalloc(g_n); + + p_n = sysconf(_SC_GETPW_R_SIZE_MAX); + p_buf = pa_xmalloc(p_n); + + if (getgrnam_r(name, &grbuf, g_buf, (size_t) g_n, &gr) != 0 || !gr) + goto finish; + + r = 0; + for (i = gr->gr_mem; *i; i++) { + struct passwd pwbuf, *pw; + + if (getpwnam_r(*i, &pwbuf, p_buf, (size_t) p_n, &pw) != 0 || !pw) + continue; + + if (pw->pw_uid == uid) { + r = 1; + break; + } + } + +finish: + pa_xfree(g_buf); + pa_xfree(p_buf); + + return r; +} + +#else /* HAVE_GRP_H */ + +int pa_own_uid_in_group(const char *name, gid_t *gid) { + return -1; + +} + +int pa_uid_in_group(uid_t uid, const char *name) { + return -1; +} + +#endif + +/* Lock or unlock a file entirely. + (advisory on UNIX, mandatory on Windows) */ +int pa_lock_fd(int fd, int b) { +#ifdef F_SETLKW + struct flock flock; + + /* Try a R/W lock first */ + + flock.l_type = b ? F_WRLCK : F_UNLCK; + flock.l_whence = SEEK_SET; + flock.l_start = 0; + flock.l_len = 0; + + if (fcntl(fd, F_SETLKW, &flock) >= 0) + return 0; + + /* Perhaps the file descriptor qas opened for read only, than try again with a read lock. */ + if (b && errno == EBADF) { + flock.l_type = F_RDLCK; + if (fcntl(fd, F_SETLKW, &flock) >= 0) + return 0; + } + + pa_log(__FILE__": %slock failed: %s", !b ? "un" : "", strerror(errno)); +#endif + +#ifdef OS_IS_WIN32 + HANDLE h = (HANDLE)_get_osfhandle(fd); + + if (b && LockFile(h, 0, 0, 0xFFFFFFFF, 0xFFFFFFFF)) + return 0; + if (!b && UnlockFile(h, 0, 0, 0xFFFFFFFF, 0xFFFFFFFF)) + return 0; + + pa_log(__FILE__": %slock failed: 0x%08X", !b ? "un" : "", GetLastError()); +#endif + + return -1; +} + +/* Remove trailing newlines from a string */ +char* pa_strip_nl(char *s) { + assert(s); + + s[strcspn(s, "\r\n")] = 0; + return s; +} + +/* Create a temporary lock file and lock it. */ +int pa_lock_lockfile(const char *fn) { + int fd = -1; + assert(fn); + + for (;;) { + struct stat st; + + if ((fd = open(fn, O_CREAT|O_RDWR, S_IRUSR|S_IWUSR)) < 0) { + pa_log(__FILE__": failed to create lock file '%s': %s", fn, strerror(errno)); + goto fail; + } + + if (pa_lock_fd(fd, 1) < 0) { + pa_log(__FILE__": failed to lock file '%s'.", fn); + goto fail; + } + + if (fstat(fd, &st) < 0) { + pa_log(__FILE__": failed to fstat() file '%s'.", fn); + goto fail; + } + + /* Check wheter the file has been removed meanwhile. When yes, restart this loop, otherwise, we're done */ + if (st.st_nlink >= 1) + break; + + if (pa_lock_fd(fd, 0) < 0) { + pa_log(__FILE__": failed to unlock file '%s'.", fn); + goto fail; + } + + if (close(fd) < 0) { + pa_log(__FILE__": failed to close file '%s'.", fn); + goto fail; + } + + fd = -1; + } + + return fd; + +fail: + + if (fd >= 0) + close(fd); + + return -1; +} + +/* Unlock a temporary lcok file */ +int pa_unlock_lockfile(const char *fn, int fd) { + int r = 0; + assert(fn && fd >= 0); + + if (unlink(fn) < 0) { + pa_log_warn(__FILE__": WARNING: unable to remove lock file '%s': %s", fn, strerror(errno)); + r = -1; + } + + if (pa_lock_fd(fd, 0) < 0) { + pa_log_warn(__FILE__": WARNING: failed to unlock file '%s'.", fn); + r = -1; + } + + if (close(fd) < 0) { + pa_log_warn(__FILE__": WARNING: failed to close lock file '%s': %s", fn, strerror(errno)); + r = -1; + } + + 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 *mode) { + const char *fn; + char h[PATH_MAX]; + +#ifdef OS_IS_WIN32 + char buf[PATH_MAX]; + + if (!getenv(POLYP_ROOTENV)) + pa_set_root(NULL); +#endif + + if (env && (fn = getenv(env))) { +#ifdef OS_IS_WIN32 + if (!ExpandEnvironmentStrings(fn, buf, PATH_MAX)) + return NULL; + fn = buf; +#endif + + if (result) + *result = pa_xstrdup(fn); + + return fopen(fn, mode); + } + + if (local && pa_get_home_dir(h, sizeof(h))) { + FILE *f; + char *lfn; + + fn = lfn = pa_sprintf_malloc("%s/%s", h, local); + +#ifdef OS_IS_WIN32 + if (!ExpandEnvironmentStrings(lfn, buf, PATH_MAX)) + return NULL; + fn = buf; +#endif + + f = fopen(fn, mode); + + if (f || errno != ENOENT) { + if (result) + *result = pa_xstrdup(fn); + pa_xfree(lfn); + return f; + } + + pa_xfree(lfn); + } + + if (!global) { + if (result) + *result = NULL; + errno = ENOENT; + return NULL; + } + +#ifdef OS_IS_WIN32 + if (!ExpandEnvironmentStrings(global, buf, PATH_MAX)) + return NULL; + global = buf; +#endif + + if (result) + *result = pa_xstrdup(global); + + return fopen(global, mode); +} + +/* 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; +} + +/* Returns nonzero when *s starts with *pfx */ +int pa_startswith(const char *s, const char *pfx) { + size_t l; + + assert(s); + assert(pfx); + + l = strlen(pfx); + + return strlen(s) >= l && strncmp(s, pfx, l) == 0; +} + +/* Returns nonzero when *s ends with *sfx */ +int pa_endswith(const char *s, const char *sfx) { + size_t l1, l2; + + assert(s); + assert(sfx); + + l1 = strlen(s); + l2 = strlen(sfx); + + return l1 >= l2 && strcmp(s+l1-l2, sfx) == 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]; + +#ifndef OS_IS_WIN32 + if (fn && *fn == '/') +#else + if (fn && strlen(fn) >= 3 && isalpha(fn[0]) && fn[1] == ':' && fn[2] == '\\') +#endif + return pa_strlcpy(s, fn, l); + + if (fn) + snprintf(s, l, "%s%s%c%s", PA_RUNTIME_PATH_PREFIX, pa_get_user_name(u, sizeof(u)), PATH_SEP, fn); + else + snprintf(s, l, "%s%s", PA_RUNTIME_PATH_PREFIX, pa_get_user_name(u, sizeof(u))); + +#ifdef OS_IS_WIN32 + { + char buf[l]; + strcpy(buf, s); + ExpandEnvironmentStrings(buf, s, l); + } +#endif + + return s; +} + +/* Convert the string s to a signed integer in *ret_i */ +int pa_atoi(const char *s, int32_t *ret_i) { + char *x = NULL; + long l; + assert(s && ret_i); + + l = strtol(s, &x, 0); + + if (!x || *x) + return -1; + + *ret_i = (int32_t) l; + + return 0; +} + +/* Convert the string s to an unsigned integer in *ret_u */ +int pa_atou(const char *s, uint32_t *ret_u) { + char *x = NULL; + unsigned long l; + assert(s && ret_u); + + l = strtoul(s, &x, 0); + + if (!x || *x) + return -1; + + *ret_u = (uint32_t) l; + + return 0; +} diff --git a/src/polypcore/core-util.h b/src/polypcore/core-util.h new file mode 100644 index 00000000..d3db756f --- /dev/null +++ b/src/polypcore/core-util.h @@ -0,0 +1,89 @@ +#ifndef foocoreutilhfoo +#define foocoreutilhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + 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 + Lesser General Public License for more details. + + 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 +#include +#include +#include + +#include +#include + +struct timeval; + +void pa_make_nonblock_fd(int fd); + +int pa_make_secure_dir(const char* dir); +int pa_make_secure_parent_dir(const char *fn); + +ssize_t pa_read(int fd, void *buf, size_t count); +ssize_t pa_write(int fd, const void *buf, size_t count); +ssize_t pa_loop_read(int fd, void*data, size_t size); +ssize_t pa_loop_write(int fd, const void*data, size_t size); + +void pa_check_signal_is_blocked(int sig); + +char *pa_sprintf_malloc(const char *format, ...) PA_GCC_PRINTF_ATTR(1,2); +char *pa_vsprintf_malloc(const char *format, va_list ap); + +char *pa_strlcpy(char *b, const char *s, size_t l); + +char *pa_parent_dir(const char *fn); + +void pa_raise_priority(void); +void pa_reset_priority(void); + +int pa_fd_set_cloexec(int fd, int b); + +int pa_parse_boolean(const char *s); + +char *pa_split(const char *c, const char*delimiters, const char **state); +char *pa_split_spaces(const char *c, const char **state); + +char *pa_strip_nl(char *s); + +const char *pa_strsignal(int sig); + +int pa_own_uid_in_group(const char *name, gid_t *gid); +int pa_uid_in_group(uid_t uid, const char *name); + +int pa_lock_fd(int fd, int b); + +int pa_lock_lockfile(const char *fn); +int pa_unlock_lockfile(const char *fn, int fd); + +FILE *pa_open_config_file(const char *global, const char *local, const char *env, char **result, const char *mode); + +char *pa_hexstr(const uint8_t* d, size_t dlength, char *s, size_t slength); +size_t pa_parsehex(const char *p, uint8_t *d, size_t dlength); + +int pa_startswith(const char *s, const char *pfx); +int pa_endswith(const char *s, const char *sfx); + +char *pa_runtime_path(const char *fn, char *s, size_t l); + +int pa_atoi(const char *s, int32_t *ret_i); +int pa_atou(const char *s, uint32_t *ret_u); + +#endif diff --git a/src/polypcore/core.c b/src/polypcore/core.c index ff8ec081..43f7015e 100644 --- a/src/polypcore/core.c +++ b/src/polypcore/core.c @@ -34,7 +34,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/polypcore/iochannel.c b/src/polypcore/iochannel.c index a1ad5dea..b953a1d0 100644 --- a/src/polypcore/iochannel.c +++ b/src/polypcore/iochannel.c @@ -40,7 +40,7 @@ #include -#include +#include #include #include diff --git a/src/polypcore/log.c b/src/polypcore/log.c index 9908d168..3f5dfa08 100644 --- a/src/polypcore/log.c +++ b/src/polypcore/log.c @@ -35,7 +35,7 @@ #include -#include +#include #include "log.h" diff --git a/src/polypcore/modargs.c b/src/polypcore/modargs.c index 63cc779d..5d046d26 100644 --- a/src/polypcore/modargs.c +++ b/src/polypcore/modargs.c @@ -36,7 +36,7 @@ #include #include #include -#include +#include #include "modargs.h" diff --git a/src/polypcore/modinfo.c b/src/polypcore/modinfo.c index 241076c6..4a9be0f0 100644 --- a/src/polypcore/modinfo.c +++ b/src/polypcore/modinfo.c @@ -28,7 +28,7 @@ #include -#include +#include #include #include "modinfo.h" diff --git a/src/polypcore/module.c b/src/polypcore/module.c index fe177a5b..52cde9c3 100644 --- a/src/polypcore/module.c +++ b/src/polypcore/module.c @@ -34,7 +34,7 @@ #include #include -#include +#include #include "module.h" diff --git a/src/polypcore/namereg.c b/src/polypcore/namereg.c index cf11f5a4..17d75146 100644 --- a/src/polypcore/namereg.c +++ b/src/polypcore/namereg.c @@ -35,7 +35,7 @@ #include #include #include -#include +#include #include "namereg.h" diff --git a/src/polypcore/parseaddr.c b/src/polypcore/parseaddr.c index 7e518a5d..b2c7d1c7 100644 --- a/src/polypcore/parseaddr.c +++ b/src/polypcore/parseaddr.c @@ -29,7 +29,7 @@ #include -#include +#include #include "parseaddr.h" diff --git a/src/polypcore/pdispatch.c b/src/polypcore/pdispatch.c index 21e3644e..4b0d1bb2 100644 --- a/src/polypcore/pdispatch.c +++ b/src/polypcore/pdispatch.c @@ -32,7 +32,7 @@ #include #include #include -#include +#include #include "pdispatch.h" diff --git a/src/polypcore/pid.c b/src/polypcore/pid.c index 53b8ad0a..e98dc97b 100644 --- a/src/polypcore/pid.c +++ b/src/polypcore/pid.c @@ -41,7 +41,7 @@ #include -#include +#include #include #include "pid.h" diff --git a/src/polypcore/poll.c b/src/polypcore/poll.c index 6a29a953..7b1ed438 100644 --- a/src/polypcore/poll.c +++ b/src/polypcore/poll.c @@ -42,7 +42,7 @@ #ifndef HAVE_SYS_POLL_H -#include +#include #include "poll.h" diff --git a/src/polypcore/protocol-esound.c b/src/polypcore/protocol-esound.c index 8f53694e..98738728 100644 --- a/src/polypcore/protocol-esound.c +++ b/src/polypcore/protocol-esound.c @@ -46,7 +46,7 @@ #include #include #include -#include +#include #include "endianmacros.h" diff --git a/src/polypcore/protocol-native.c b/src/polypcore/protocol-native.c index 338db002..f0e50ec5 100644 --- a/src/polypcore/protocol-native.c +++ b/src/polypcore/protocol-native.c @@ -45,7 +45,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/polypcore/random.c b/src/polypcore/random.c index 1221206f..4bfce975 100644 --- a/src/polypcore/random.c +++ b/src/polypcore/random.c @@ -31,7 +31,7 @@ #include #include -#include +#include #include #include "random.h" diff --git a/src/polypcore/sink.c b/src/polypcore/sink.c index 6931d396..dc27ca2e 100644 --- a/src/polypcore/sink.c +++ b/src/polypcore/sink.c @@ -34,7 +34,7 @@ #include #include -#include +#include #include #include #include diff --git a/src/polypcore/socket-client.c b/src/polypcore/socket-client.c index a61cf582..4fb0a5d8 100644 --- a/src/polypcore/socket-client.c +++ b/src/polypcore/socket-client.c @@ -57,7 +57,7 @@ #include #include -#include +#include #include #include diff --git a/src/polypcore/socket-server.c b/src/polypcore/socket-server.c index 959173f2..96f8e073 100644 --- a/src/polypcore/socket-server.c +++ b/src/polypcore/socket-server.c @@ -65,7 +65,7 @@ #include #include -#include +#include #include #include "socket-server.h" diff --git a/src/polypcore/socket-util.c b/src/polypcore/socket-util.c index 0961db21..acbb7c1f 100644 --- a/src/polypcore/socket-util.c +++ b/src/polypcore/socket-util.c @@ -61,7 +61,7 @@ #include -#include +#include #include #include "socket-util.h" diff --git a/src/polypcore/strlist.c b/src/polypcore/strlist.c index 4d70e9e9..b9420749 100644 --- a/src/polypcore/strlist.c +++ b/src/polypcore/strlist.c @@ -29,7 +29,7 @@ #include #include -#include +#include #include "strlist.h" diff --git a/src/polypcore/util.c b/src/polypcore/util.c deleted file mode 100644 index 9783b746..00000000 --- a/src/polypcore/util.c +++ /dev/null @@ -1,1293 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - 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 - Lesser General Public License for more details. - - 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. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef HAVE_SCHED_H -#include -#endif - -#ifdef HAVE_SYS_RESOURCE_H -#include -#endif - -#ifdef HAVE_PTHREAD -#include -#endif - -#ifdef HAVE_NETDB_H -#include -#endif - -#ifdef HAVE_WINDOWS_H -#include -#endif - -#include - -#ifdef HAVE_PWD_H -#include -#endif -#ifdef HAVE_GRP_H -#include -#endif - -#include "winsock.h" - -#include - -#include - -#include "util.h" - -#ifndef OS_IS_WIN32 -#define PA_RUNTIME_PATH_PREFIX "/tmp/polypaudio-" -#define PATH_SEP '/' -#else -#define PA_RUNTIME_PATH_PREFIX "%TEMP%\\polypaudio-" -#define PATH_SEP '\\' -#endif - -#ifdef OS_IS_WIN32 - -#define POLYP_ROOTENV "POLYP_ROOT" - -int pa_set_root(HANDLE handle) { - char library_path[MAX_PATH + sizeof(POLYP_ROOTENV) + 1], *sep; - - strcpy(library_path, POLYP_ROOTENV "="); - - if (!GetModuleFileName(handle, library_path + sizeof(POLYP_ROOTENV), MAX_PATH)) - return 0; - - sep = strrchr(library_path, '\\'); - if (sep) - *sep = '\0'; - - if (_putenv(library_path) < 0) - return 0; - - return 1; -} - -#endif - -/** Make a file descriptor nonblock. Doesn't do any error checking */ -void pa_make_nonblock_fd(int fd) { -#ifdef O_NONBLOCK - int v; - assert(fd >= 0); - - if ((v = fcntl(fd, F_GETFL)) >= 0) - if (!(v & O_NONBLOCK)) - fcntl(fd, F_SETFL, v|O_NONBLOCK); -#elif defined(OS_IS_WIN32) - u_long arg = 1; - if (ioctlsocket(fd, FIONBIO, &arg) < 0) { - if (WSAGetLastError() == WSAENOTSOCK) - pa_log_warn(__FILE__": WARNING: Only sockets can be made non-blocking!"); - } -#else - pa_log_warn(__FILE__": WARNING: Non-blocking I/O not supported.!"); -#endif -} - -/** Creates a directory securely */ -int pa_make_secure_dir(const char* dir) { - struct stat st; - assert(dir); - -#ifdef OS_IS_WIN32 - if (mkdir(dir) < 0) -#else - if (mkdir(dir, 0700) < 0) -#endif - if (errno != EEXIST) - return -1; - -#ifdef HAVE_CHOWN - chown(dir, getuid(), getgid()); -#endif -#ifdef HAVE_CHMOD - chmod(dir, 0700); -#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 != getuid()) || ((st.st_mode & 0777) != 0700)) - goto fail; -#else - fprintf(stderr, "FIXME: pa_make_secure_dir()\n"); -#endif - - return 0; - -fail: - rmdir(dir); - return -1; -} - -/* Return a newly allocated sting containing the parent directory of the specified file */ -char *pa_parent_dir(const char *fn) { - char *slash, *dir = pa_xstrdup(fn); - - slash = (char*) pa_path_get_filename(dir); - if (slash == fn) - return NULL; - - *(slash-1) = 0; - return dir; -} - -/* Creates a the parent directory of the specified path securely */ -int pa_make_secure_parent_dir(const char *fn) { - int ret = -1; - char *dir; - - if (!(dir = pa_parent_dir(fn))) - goto finish; - - if (pa_make_secure_dir(dir) < 0) - goto finish; - - ret = 0; - -finish: - pa_xfree(dir); - return ret; -} - -/** Platform independent read function. Necessary since not all systems - * treat all file descriptors equal. */ -ssize_t pa_read(int fd, void *buf, size_t count) { - ssize_t r; - -#ifdef OS_IS_WIN32 - r = recv(fd, buf, count, 0); - if (r < 0) { - if (WSAGetLastError() != WSAENOTSOCK) { - errno = WSAGetLastError(); - return r; - } - } - - if (r < 0) -#endif - r = read(fd, buf, count); - - return r; -} - -/** Similar to pa_read(), but handles writes */ -ssize_t pa_write(int fd, const void *buf, size_t count) { - ssize_t r; - -#ifdef OS_IS_WIN32 - r = send(fd, buf, count, 0); - if (r < 0) { - if (WSAGetLastError() != WSAENOTSOCK) { - errno = WSAGetLastError(); - return r; - } - } - - if (r < 0) -#endif - r = write(fd, buf, count); - - return r; -} - -/** 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) { - ssize_t ret = 0; - assert(fd >= 0 && data && size); - - while (size > 0) { - ssize_t r; - - if ((r = pa_read(fd, data, size)) < 0) - return r; - - if (r == 0) - break; - - ret += r; - data = (uint8_t*) data + r; - size -= r; - } - - return ret; -} - -/** Similar to pa_loop_read(), but wraps write() */ -ssize_t pa_loop_write(int fd, const void*data, size_t size) { - ssize_t ret = 0; - assert(fd >= 0 && data && size); - - while (size > 0) { - ssize_t r; - - if ((r = pa_write(fd, data, size)) < 0) - return r; - - if (r == 0) - break; - - ret += r; - data = (const uint8_t*) data + r; - size -= r; - } - - return ret; -} - -/* Print a warning messages in case that the given signal is not - * blocked or trapped */ -void pa_check_signal_is_blocked(int sig) { -#ifdef HAVE_SIGACTION - struct sigaction sa; - sigset_t set; - - /* If POSIX threads are supported use thread-aware - * pthread_sigmask() function, to check if the signal is - * blocked. Otherwise fall back to sigprocmask() */ - -#ifdef HAVE_PTHREAD - if (pthread_sigmask(SIG_SETMASK, NULL, &set) < 0) { -#endif - if (sigprocmask(SIG_SETMASK, NULL, &set) < 0) { - pa_log(__FILE__": sigprocmask() failed: %s", strerror(errno)); - return; - } -#ifdef HAVE_PTHREAD - } -#endif - - if (sigismember(&set, sig)) - return; - - /* Check whether the signal is trapped */ - - if (sigaction(sig, NULL, &sa) < 0) { - pa_log(__FILE__": sigaction() failed: %s", strerror(errno)); - return; - } - - if (sa.sa_handler != SIG_DFL) - return; - - pa_log(__FILE__": WARNING: %s is not trapped. This might cause malfunction!", pa_strsignal(sig)); -#else /* HAVE_SIGACTION */ - pa_log(__FILE__": WARNING: %s might not be trapped. This might cause malfunction!", pa_strsignal(sig)); -#endif -} - -/* The following function is based on an example from the GNU libc - * documentation. This function is similar to GNU's asprintf(). */ -char *pa_sprintf_malloc(const char *format, ...) { - int size = 100; - char *c = NULL; - - assert(format); - - for(;;) { - int r; - va_list ap; - - c = pa_xrealloc(c, size); - - va_start(ap, format); - r = vsnprintf(c, size, format, ap); - va_end(ap); - - if (r > -1 && r < size) - return c; - - if (r > -1) /* glibc 2.1 */ - size = r+1; - else /* glibc 2.0 */ - size *= 2; - } -} - -/* Same as the previous function, but use a va_list instead of an - * ellipsis */ -char *pa_vsprintf_malloc(const char *format, va_list ap) { - int size = 100; - char *c = NULL; - - assert(format); - - for(;;) { - int r; - c = pa_xrealloc(c, size); - r = vsnprintf(c, size, format, ap); - - if (r > -1 && r < size) - return c; - - if (r > -1) /* glibc 2.1 */ - size = r+1; - else /* glibc 2.0 */ - size *= 2; - } -} - -/* Return the current username in the specified string buffer. */ -char *pa_get_user_name(char *s, size_t l) { - char *p; - char buf[1024]; - -#ifdef HAVE_PWD_H - struct passwd pw, *r; -#endif - - assert(s && l > 0); - - if (!(p = getenv("USER")) && !(p = getenv("LOGNAME")) && !(p = getenv("USERNAME"))) { -#ifdef HAVE_PWD_H - -#ifdef HAVE_GETPWUID_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) { -#endif - snprintf(s, l, "%lu", (unsigned long) getuid()); - return s; - } - - p = r->pw_name; - -#elif defined(OS_IS_WIN32) /* HAVE_PWD_H */ - DWORD size = sizeof(buf); - - if (!GetUserName(buf, &size)) - return NULL; - - p = buf; - -#else /* HAVE_PWD_H */ - return NULL; -#endif /* HAVE_PWD_H */ - } - - 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); - if (gethostname(s, l) < 0) { - pa_log(__FILE__": gethostname(): %s", strerror(errno)); - return NULL; - } - s[l-1] = 0; - return s; -} - -/* Return the home directory of the current user */ -char *pa_get_home_dir(char *s, size_t l) { - char *e; - -#ifdef HAVE_PWD_H - char buf[1024]; - struct passwd pw, *r; -#endif - - assert(s && l); - - if ((e = getenv("HOME"))) - return pa_strlcpy(s, e, l); - - if ((e = getenv("USERPROFILE"))) - return pa_strlcpy(s, e, l); - -#ifdef HAVE_PWD_H -#ifdef HAVE_GETPWUID_R - if (getpwuid_r(getuid(), &pw, buf, sizeof(buf), &r) != 0 || !r) { - pa_log(__FILE__": getpwuid_r() failed"); -#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) { - pa_log(__FILE__": getpwuid_r() failed"); -#endif - return NULL; - } - - return pa_strlcpy(s, r->pw_dir, l); -#else /* HAVE_PWD_H */ - return NULL; -#endif -} - -/* Similar to OpenBSD's strlcpy() function */ -char *pa_strlcpy(char *b, const char *s, size_t l) { - assert(b && s && l > 0); - - strncpy(b, s, l); - b[l-1] = 0; - return b; -} - -struct timeval *pa_gettimeofday(struct timeval *tv) { -#ifdef HAVE_GETTIMEOFDAY - assert(tv); - - return gettimeofday(tv, NULL) < 0 ? NULL : tv; -#elif defined(OS_IS_WIN32) - /* - * Copied from implementation by Steven Edwards (LGPL). - * Found on wine mailing list. - */ - -#if defined(_MSC_VER) || defined(__BORLANDC__) -#define EPOCHFILETIME (116444736000000000i64) -#else -#define EPOCHFILETIME (116444736000000000LL) -#endif - - FILETIME ft; - LARGE_INTEGER li; - __int64 t; - - assert(tv); - - GetSystemTimeAsFileTime(&ft); - li.LowPart = ft.dwLowDateTime; - li.HighPart = ft.dwHighDateTime; - t = li.QuadPart; /* In 100-nanosecond intervals */ - t -= EPOCHFILETIME; /* Offset to the Epoch time */ - t /= 10; /* In microseconds */ - tv->tv_sec = (long)(t / 1000000); - tv->tv_usec = (long)(t % 1000000); - - return tv; -#else -#error "Platform lacks gettimeofday() or equivalent function." -#endif -} - -/* Calculate the difference between the two specfified timeval - * timestamsps. */ -pa_usec_t pa_timeval_diff(const struct timeval *a, const struct timeval *b) { - pa_usec_t r; - assert(a && b); - - /* Check which whan is the earlier time and swap the two arguments if reuqired. */ - if (pa_timeval_cmp(a, b) < 0) { - const struct timeval *c; - c = a; - a = b; - b = c; - } - - /* Calculate the second difference*/ - r = ((pa_usec_t) a->tv_sec - b->tv_sec)* 1000000; - - /* Calculate the microsecond difference */ - if (a->tv_usec > b->tv_usec) - r += ((pa_usec_t) a->tv_usec - b->tv_usec); - else if (a->tv_usec < b->tv_usec) - r -= ((pa_usec_t) b->tv_usec - a->tv_usec); - - return r; -} - -/* Compare the two timeval structs and return 0 when equal, negative when a < b, positive otherwse */ -int pa_timeval_cmp(const struct timeval *a, const struct timeval *b) { - assert(a && b); - - if (a->tv_sec < b->tv_sec) - return -1; - - if (a->tv_sec > b->tv_sec) - return 1; - - if (a->tv_usec < b->tv_usec) - return -1; - - if (a->tv_usec > b->tv_usec) - return 1; - - return 0; -} - -/* Return the time difference between now and the specified timestamp */ -pa_usec_t pa_timeval_age(const struct timeval *tv) { - struct timeval now; - assert(tv); - - return pa_timeval_diff(pa_gettimeofday(&now), tv); -} - -/* Add the specified time inmicroseconds to the specified timeval structure */ -void pa_timeval_add(struct timeval *tv, pa_usec_t v) { - unsigned long secs; - assert(tv); - - secs = (v/1000000); - tv->tv_sec += (unsigned long) secs; - v -= secs*1000000; - - tv->tv_usec += v; - - /* Normalize */ - while (tv->tv_usec >= 1000000) { - tv->tv_sec++; - tv->tv_usec -= 1000000; - } -} - -#define NICE_LEVEL (-15) - -/* Raise the priority of the current process as much as possible and -sensible: set the nice level to -15 and enable realtime scheduling if -supported.*/ -void pa_raise_priority(void) { - -#ifdef HAVE_SYS_RESOURCE_H - if (setpriority(PRIO_PROCESS, 0, NICE_LEVEL) < 0) - pa_log_warn(__FILE__": setpriority() failed: %s", strerror(errno)); - else - pa_log_info(__FILE__": Successfully gained nice level %i.", NICE_LEVEL); -#endif - -#ifdef _POSIX_PRIORITY_SCHEDULING - { - struct sched_param sp; - - if (sched_getparam(0, &sp) < 0) { - pa_log(__FILE__": sched_getparam() failed: %s", strerror(errno)); - return; - } - - sp.sched_priority = 1; - if (sched_setscheduler(0, SCHED_FIFO, &sp) < 0) { - pa_log_warn(__FILE__": sched_setscheduler() failed: %s", strerror(errno)); - return; - } - - pa_log_info(__FILE__": Successfully enabled SCHED_FIFO scheduling."); - } -#endif - -#ifdef OS_IS_WIN32 - if (!SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS)) - pa_log_warn(__FILE__": SetPriorityClass() failed: 0x%08X", GetLastError()); - else - pa_log_info(__FILE__": Successfully gained high priority class."); -#endif -} - -/* Reset the priority to normal, inverting the changes made by pa_raise_priority() */ -void pa_reset_priority(void) { -#ifdef OS_IS_WIN32 - SetPriorityClass(GetCurrentProcess(), NORMAL_PRIORITY_CLASS); -#endif - -#ifdef _POSIX_PRIORITY_SCHEDULING - { - struct sched_param sp; - sched_getparam(0, &sp); - sp.sched_priority = 0; - sched_setscheduler(0, SCHED_OTHER, &sp); - } -#endif - -#ifdef HAVE_SYS_RESOURCE_H - setpriority(PRIO_PROCESS, 0, 0); -#endif -} - -/* Set the FD_CLOEXEC flag for a fd */ -int pa_fd_set_cloexec(int fd, int b) { - -#ifdef FD_CLOEXEC - int v; - assert(fd >= 0); - - if ((v = fcntl(fd, F_GETFD, 0)) < 0) - return -1; - - v = (v & ~FD_CLOEXEC) | (b ? FD_CLOEXEC : 0); - - if (fcntl(fd, F_SETFD, v) < 0) - return -1; -#endif - - 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) { - -#ifdef HAVE_READLINK - char path[PATH_MAX]; - int i; - assert(s && l); - - /* This works on Linux only */ - - snprintf(path, sizeof(path), "/proc/%u/exe", (unsigned) getpid()); - if ((i = readlink(path, s, l-1)) < 0) - return NULL; - - s[i] = 0; - return s; -#elif defined(OS_IS_WIN32) - char path[PATH_MAX]; - if (!GetModuleFileName(NULL, path, PATH_MAX)) - return NULL; - pa_strlcpy(s, pa_path_get_filename(path), l); - return s; -#else - return NULL; -#endif -} - -/* Return a pointer to the filename inside a path (which is the last - * component). */ -const char *pa_path_get_filename(const char *p) { - char *fn; - - if ((fn = strrchr(p, PATH_SEP))) - return fn+1; - - return (const 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; - else if (!strcmp(v, "0") || v[0] == 'n' || v[0] == 'N' || v[0] == 'f' || v[0] == 'F' || !strcasecmp(v, "off")) - return 0; - - 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; - - if (!*current) - return NULL; - - l = strcspn(current, delimiter); - *state = current+l; - - if (**state) - (*state)++; - - 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 || *c == 0) - return NULL; - - current += strspn(current, WHITESPACE); - l = strcspn(current, WHITESPACE); - - *state = 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) { - switch(sig) { - case SIGINT: return "SIGINT"; - case SIGTERM: return "SIGTERM"; -#ifdef SIGUSR1 - case SIGUSR1: return "SIGUSR1"; -#endif -#ifdef SIGUSR2 - case SIGUSR2: return "SIGUSR2"; -#endif -#ifdef SIGXCPU - case SIGXCPU: return "SIGXCPU"; -#endif -#ifdef SIGPIPE - case SIGPIPE: return "SIGPIPE"; -#endif -#ifdef SIGCHLD - case SIGCHLD: return "SIGCHLD"; -#endif -#ifdef SIGHUP - case SIGHUP: return "SIGHUP"; -#endif - default: return "UNKNOWN SIGNAL"; - } -} - -#ifdef HAVE_GRP_H - -/* 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; - void *data; - int r = -1; - -#ifdef HAVE_GETGRGID_R -#ifdef _SC_GETGR_R_SIZE_MAX - n = sysconf(_SC_GETGR_R_SIZE_MAX); -#else - n = -1; -#endif - if (n < 0) n = 512; - data = pa_xmalloc(n); - - if (getgrgid_r(gid, &group, data, n, &result) < 0 || !result) { - pa_log(__FILE__ ": getgrgid_r(%u) failed: %s", gid, strerror(errno)); - goto finish; - } - - r = strcmp(name, result->gr_name) == 0; - -finish: - pa_xfree(data); -#else - /* XXX Not thread-safe, but needed on OSes (e.g. FreeBSD 4.X) that do not - * support getgrgid_r. */ - if ((result = getgrgid(gid)) == NULL) { - pa_log(__FILE__ ": getgrgid(%u) failed: %s", gid, strerror(errno)); - goto finish; - } - - r = strcmp(name, result->gr_name) == 0; - -finish: -#endif - - return r; -} - -/* Check the current user is member of the specified group */ -int pa_own_uid_in_group(const char *name, gid_t *gid) { - GETGROUPS_T *gids, tgid; - int n = sysconf(_SC_NGROUPS_MAX); - int r = -1, i; - - assert(n > 0); - - gids = pa_xmalloc(sizeof(GETGROUPS_T)*n); - - if ((n = getgroups(n, gids)) < 0) { - pa_log(__FILE__": getgroups() failed: %s", strerror(errno)); - goto finish; - } - - for (i = 0; i < n; i++) { - if (is_group(gids[i], name) > 0) { - *gid = gids[i]; - r = 1; - goto finish; - } - } - - if (is_group(tgid = getgid(), name) > 0) { - *gid = tgid; - r = 1; - goto finish; - } - - r = 0; - -finish: - - pa_xfree(gids); - return r; -} - -int pa_uid_in_group(uid_t uid, const char *name) { - char *g_buf, *p_buf; - long g_n, p_n; - struct group grbuf, *gr; - char **i; - int r = -1; - - g_n = sysconf(_SC_GETGR_R_SIZE_MAX); - g_buf = pa_xmalloc(g_n); - - p_n = sysconf(_SC_GETPW_R_SIZE_MAX); - p_buf = pa_xmalloc(p_n); - - if (getgrnam_r(name, &grbuf, g_buf, (size_t) g_n, &gr) != 0 || !gr) - goto finish; - - r = 0; - for (i = gr->gr_mem; *i; i++) { - struct passwd pwbuf, *pw; - - if (getpwnam_r(*i, &pwbuf, p_buf, (size_t) p_n, &pw) != 0 || !pw) - continue; - - if (pw->pw_uid == uid) { - r = 1; - break; - } - } - -finish: - pa_xfree(g_buf); - pa_xfree(p_buf); - - return r; -} - -#else /* HAVE_GRP_H */ - -int pa_own_uid_in_group(const char *name, gid_t *gid) { - return -1; - -} - -int pa_uid_in_group(uid_t uid, const char *name) { - return -1; -} - -#endif - -/* Lock or unlock a file entirely. - (advisory on UNIX, mandatory on Windows) */ -int pa_lock_fd(int fd, int b) { -#ifdef F_SETLKW - struct flock flock; - - /* Try a R/W lock first */ - - flock.l_type = b ? F_WRLCK : F_UNLCK; - flock.l_whence = SEEK_SET; - flock.l_start = 0; - flock.l_len = 0; - - if (fcntl(fd, F_SETLKW, &flock) >= 0) - return 0; - - /* Perhaps the file descriptor qas opened for read only, than try again with a read lock. */ - if (b && errno == EBADF) { - flock.l_type = F_RDLCK; - if (fcntl(fd, F_SETLKW, &flock) >= 0) - return 0; - } - - pa_log(__FILE__": %slock failed: %s", !b ? "un" : "", strerror(errno)); -#endif - -#ifdef OS_IS_WIN32 - HANDLE h = (HANDLE)_get_osfhandle(fd); - - if (b && LockFile(h, 0, 0, 0xFFFFFFFF, 0xFFFFFFFF)) - return 0; - if (!b && UnlockFile(h, 0, 0, 0xFFFFFFFF, 0xFFFFFFFF)) - return 0; - - pa_log(__FILE__": %slock failed: 0x%08X", !b ? "un" : "", GetLastError()); -#endif - - return -1; -} - -/* Remove trailing newlines from a string */ -char* pa_strip_nl(char *s) { - assert(s); - - s[strcspn(s, "\r\n")] = 0; - return s; -} - -/* Create a temporary lock file and lock it. */ -int pa_lock_lockfile(const char *fn) { - int fd = -1; - assert(fn); - - for (;;) { - struct stat st; - - if ((fd = open(fn, O_CREAT|O_RDWR, S_IRUSR|S_IWUSR)) < 0) { - pa_log(__FILE__": failed to create lock file '%s': %s", fn, strerror(errno)); - goto fail; - } - - if (pa_lock_fd(fd, 1) < 0) { - pa_log(__FILE__": failed to lock file '%s'.", fn); - goto fail; - } - - if (fstat(fd, &st) < 0) { - pa_log(__FILE__": failed to fstat() file '%s'.", fn); - goto fail; - } - - /* Check wheter the file has been removed meanwhile. When yes, restart this loop, otherwise, we're done */ - if (st.st_nlink >= 1) - break; - - if (pa_lock_fd(fd, 0) < 0) { - pa_log(__FILE__": failed to unlock file '%s'.", fn); - goto fail; - } - - if (close(fd) < 0) { - pa_log(__FILE__": failed to close file '%s'.", fn); - goto fail; - } - - fd = -1; - } - - return fd; - -fail: - - if (fd >= 0) - close(fd); - - return -1; -} - -/* Unlock a temporary lcok file */ -int pa_unlock_lockfile(const char *fn, int fd) { - int r = 0; - assert(fn && fd >= 0); - - if (unlink(fn) < 0) { - pa_log_warn(__FILE__": WARNING: unable to remove lock file '%s': %s", fn, strerror(errno)); - r = -1; - } - - if (pa_lock_fd(fd, 0) < 0) { - pa_log_warn(__FILE__": WARNING: failed to unlock file '%s'.", fn); - r = -1; - } - - if (close(fd) < 0) { - pa_log_warn(__FILE__": WARNING: failed to close lock file '%s': %s", fn, strerror(errno)); - r = -1; - } - - 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 *mode) { - const char *fn; - char h[PATH_MAX]; - -#ifdef OS_IS_WIN32 - char buf[PATH_MAX]; - - if (!getenv(POLYP_ROOTENV)) - pa_set_root(NULL); -#endif - - if (env && (fn = getenv(env))) { -#ifdef OS_IS_WIN32 - if (!ExpandEnvironmentStrings(fn, buf, PATH_MAX)) - return NULL; - fn = buf; -#endif - - if (result) - *result = pa_xstrdup(fn); - - return fopen(fn, mode); - } - - if (local && pa_get_home_dir(h, sizeof(h))) { - FILE *f; - char *lfn; - - fn = lfn = pa_sprintf_malloc("%s/%s", h, local); - -#ifdef OS_IS_WIN32 - if (!ExpandEnvironmentStrings(lfn, buf, PATH_MAX)) - return NULL; - fn = buf; -#endif - - f = fopen(fn, mode); - - if (f || errno != ENOENT) { - if (result) - *result = pa_xstrdup(fn); - pa_xfree(lfn); - return f; - } - - pa_xfree(lfn); - } - - if (!global) { - if (result) - *result = NULL; - errno = ENOENT; - return NULL; - } - -#ifdef OS_IS_WIN32 - if (!ExpandEnvironmentStrings(global, buf, PATH_MAX)) - return NULL; - global = buf; -#endif - - if (result) - *result = pa_xstrdup(global); - - return fopen(global, mode); -} - -/* 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]; -#ifdef HAVE_GETADDRINFO - struct addrinfo *a, hints; -#endif - - if (!pa_get_host_name(hn, sizeof(hn))) - return NULL; - -#ifdef HAVE_GETADDRINFO - 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; -#else - return pa_strlcpy(s, hn, l); -#endif -} - -/* Returns nonzero when *s starts with *pfx */ -int pa_startswith(const char *s, const char *pfx) { - size_t l; - - assert(s); - assert(pfx); - - l = strlen(pfx); - - return strlen(s) >= l && strncmp(s, pfx, l) == 0; -} - -/* Returns nonzero when *s ends with *sfx */ -int pa_endswith(const char *s, const char *sfx) { - size_t l1, l2; - - assert(s); - assert(sfx); - - l1 = strlen(s); - l2 = strlen(sfx); - - return l1 >= l2 && strcmp(s+l1-l2, sfx) == 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]; - -#ifndef OS_IS_WIN32 - if (fn && *fn == '/') -#else - if (fn && strlen(fn) >= 3 && isalpha(fn[0]) && fn[1] == ':' && fn[2] == '\\') -#endif - return pa_strlcpy(s, fn, l); - - if (fn) - snprintf(s, l, "%s%s%c%s", PA_RUNTIME_PATH_PREFIX, pa_get_user_name(u, sizeof(u)), PATH_SEP, fn); - else - snprintf(s, l, "%s%s", PA_RUNTIME_PATH_PREFIX, pa_get_user_name(u, sizeof(u))); - -#ifdef OS_IS_WIN32 - { - char buf[l]; - strcpy(buf, s); - ExpandEnvironmentStrings(buf, s, l); - } -#endif - - return s; -} - -/* Wait t milliseconds */ -int pa_msleep(unsigned long t) { -#ifdef OS_IS_WIN32 - Sleep(t); - return 0; -#elif defined(HAVE_NANOSLEEP) - struct timespec ts; - - ts.tv_sec = t/1000; - ts.tv_nsec = (t % 1000) * 1000000; - - return nanosleep(&ts, NULL); -#else -#error "Platform lacks a sleep function." -#endif -} - -/* Convert the string s to a signed integer in *ret_i */ -int pa_atoi(const char *s, int32_t *ret_i) { - char *x = NULL; - long l; - assert(s && ret_i); - - l = strtol(s, &x, 0); - - if (!x || *x) - return -1; - - *ret_i = (int32_t) l; - - return 0; -} - -/* Convert the string s to an unsigned integer in *ret_u */ -int pa_atou(const char *s, uint32_t *ret_u) { - char *x = NULL; - unsigned long l; - assert(s && ret_u); - - l = strtoul(s, &x, 0); - - if (!x || *x) - return -1; - - *ret_u = (uint32_t) l; - - return 0; -} diff --git a/src/polypcore/util.h b/src/polypcore/util.h deleted file mode 100644 index df71672f..00000000 --- a/src/polypcore/util.h +++ /dev/null @@ -1,105 +0,0 @@ -#ifndef fooutilhfoo -#define fooutilhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - 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 - Lesser General Public License for more details. - - 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 -#include -#include -#include - -#include -#include - -struct timeval; - -void pa_make_nonblock_fd(int fd); - -int pa_make_secure_dir(const char* dir); -int pa_make_secure_parent_dir(const char *fn); - -ssize_t pa_read(int fd, void *buf, size_t count); -ssize_t pa_write(int fd, const void *buf, size_t count); -ssize_t pa_loop_read(int fd, void*data, size_t size); -ssize_t pa_loop_write(int fd, const void*data, size_t size); - -void pa_check_signal_is_blocked(int sig); - -char *pa_sprintf_malloc(const char *format, ...) PA_GCC_PRINTF_ATTR(1,2); -char *pa_vsprintf_malloc(const char *format, va_list ap); - -char *pa_strlcpy(char *b, const 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_fqdn(char *s, size_t l); -char *pa_get_binary_name(char *s, size_t l); -char *pa_get_home_dir(char *s, size_t l); - -const char *pa_path_get_filename(const char *p); - -char *pa_parent_dir(const char *fn); - -struct timeval *pa_gettimeofday(struct timeval *tv); -pa_usec_t pa_timeval_diff(const struct timeval *a, const struct timeval *b); -int pa_timeval_cmp(const struct timeval *a, const struct timeval *b); -pa_usec_t pa_timeval_age(const struct timeval *tv); -void pa_timeval_add(struct timeval *tv, pa_usec_t v); - -void pa_raise_priority(void); -void pa_reset_priority(void); - -int pa_fd_set_cloexec(int fd, int b); - -int pa_parse_boolean(const char *s); - -char *pa_split(const char *c, const char*delimiters, const char **state); -char *pa_split_spaces(const char *c, const char **state); - -char *pa_strip_nl(char *s); - -const char *pa_strsignal(int sig); - -int pa_own_uid_in_group(const char *name, gid_t *gid); -int pa_uid_in_group(uid_t uid, const char *name); - -int pa_lock_fd(int fd, int b); - -int pa_lock_lockfile(const char *fn); -int pa_unlock_lockfile(const char *fn, int fd); - -FILE *pa_open_config_file(const char *global, const char *local, const char *env, char **result, const char *mode); - -char *pa_hexstr(const uint8_t* d, size_t dlength, char *s, size_t slength); -size_t pa_parsehex(const char *p, uint8_t *d, size_t dlength); - -int pa_startswith(const char *s, const char *pfx); -int pa_endswith(const char *s, const char *sfx); - -char *pa_runtime_path(const char *fn, char *s, size_t l); - -int pa_msleep(unsigned long t); - -int pa_atoi(const char *s, int32_t *ret_i); -int pa_atou(const char *s, uint32_t *ret_u); - -#endif diff --git a/src/utils/pabrowse.c b/src/utils/pabrowse.c index c1bab6b1..8063a28b 100644 --- a/src/utils/pabrowse.c +++ b/src/utils/pabrowse.c @@ -27,8 +27,7 @@ #include #include -#include -#include +#include #include static void exit_signal_callback(pa_mainloop_api*m, pa_signal_event *e, int sig, void *userdata) { @@ -108,7 +107,6 @@ static void browser_callback(pa_browser *b, pa_browse_opcode_t c, const pa_brows } } - int main(int argc, char *argv[]) { pa_mainloop *mainloop = NULL; pa_browser *browser = NULL; -- cgit