]> git.tuebingen.mpg.de Git - paraslash.git/commitdiff
Merge branch 'refs/heads/t/para_play_fixes'
authorAndre Noll <maan@tuebingen.mpg.de>
Sat, 30 Jan 2016 12:07:11 +0000 (13:07 +0100)
committerAndre Noll <maan@tuebingen.mpg.de>
Sat, 30 Jan 2016 12:07:11 +0000 (13:07 +0100)
Was cooking in next since 2015-10-25.

* refs/heads/t/para_play_fixes:
  i9e: Avoid key binding macros.
  play: Fix off-by-one in jmp 100.

36 files changed:
Doxyfile
Makefile.real
NEWS
aac_afh.c
afh.h
afh_common.c
afh_recv.c
afs.c
afs.h
aft.c
audiod.c
client_common.c
command.c
configure.ac
daemon.c
daemon.h
error.h
filter.c
filter.h
filter_common.c
m4/gengetopt/afh_recv.m4
m4/gengetopt/audiod.m4
m4/gengetopt/priority.m4 [new file with mode: 0644]
m4/gengetopt/server.m4
mp3_afh.c
ogg_afh_common.c
para.h
play.c
recv_common.c
server.c
string.c
t/makefile.test
t/t0004-server.sh
t/t0005-man.sh
udp_send.c
web/manual.m4

index 4009ac40352504283f364a09d7021331ee270aca..50c74695da5e8c690127511a7b21958972d721e0 100644 (file)
--- a/Doxyfile
+++ b/Doxyfile
@@ -1471,7 +1471,7 @@ MATHJAX_CODEFILE       =
 # The default value is: YES.
 # This tag requires that the tag GENERATE_HTML is set to YES.
 
-SEARCHENGINE           = YES
+SEARCHENGINE           = NO
 
 # When the SERVER_BASED_SEARCH tag is enabled the search engine will be
 # implemented using a web server instead of a web client using Javascript. There
index 00175bea7aa94036a0b720a7038f8eec600d9af2..ee0bf447b53eb5ae957d63fb8977a0d7a5a85538 100644 (file)
@@ -1,3 +1,12 @@
+# Implicit rules are implemented in make as suffix rules. The following rule
+# empties the suffix list to disable the predefined implicit rules. This
+# increases performance and avoids hard-to-debug behaviour.
+.SUFFIXES:
+MAKEFLAGS += -Rr
+ifeq ("$(origin CC)", "default")
+        CC := cc
+endif
+
 vardir := /var/paraslash
 mandir := $(datarootdir)/man/man1
 STRIP := $(CROSS_COMPILE)strip
@@ -10,6 +19,7 @@ uname_s := $(shell uname -s 2>/dev/null || echo "UNKNOWN_OS")
 uname_rs := $(shell uname -rs)
 cc_version := $(shell $(CC) --version | head -n 1)
 GIT_VERSION := $(shell ./GIT-VERSION-GEN git-version.h)
+build_date := $(shell date)
 
 ifeq ("$(origin O)", "command line")
        build_dir := $(O)
@@ -82,11 +92,10 @@ $(subst u,U,$(subst v,V,$(subst w,W,$(subst x,X,$(subst y,Y,\
 $(subst z,Z,$1))))))))))))))))))))))))))
 
 CPPFLAGS += -DBINDIR='"$(bindir)"'
-CPPFLAGS += -DBUILD_DATE='"$(shell date)"'
-CPPFLAGS += -DUNAME_RS='"$(shell uname -rs)"'
-CPPFLAGS += -DCC_VERSION='"$(shell $(CC) --version | head -n 1)"'
+CPPFLAGS += -DBUILD_DATE='"$(build_date)"'
+CPPFLAGS += -DUNAME_RS='"$(uname_rs)"'
+CPPFLAGS += -DCC_VERSION='"$(cc_version)"'
 CPPFLAGS += -DMAIN_INPUT_FILE_IS_$(*F)
-CPPFLAGS += $(arch_cppflags)
 CPPFLAGS += -I/usr/local/include
 CPPFLAGS += -I$(cmdline_dir)
 CPPFLAGS += -I$(cmdlist_dir)
@@ -147,9 +156,9 @@ $(cmdlist_dir)/afs.command_list.man \
 $(cmdlist_dir)/afs.completion.h \
 : afs.c aft.c attribute.c
 
-$(cmdlist_dir)/audiod,command_list.h \
-$(cmdlist_dir)/audiod,command_list.man \
-$(cmdlist_dir)/audiod,completion.h \
+$(cmdlist_dir)/audiod.command_list.h \
+$(cmdlist_dir)/audiod.command_list.man \
+$(cmdlist_dir)/audiod.completion.h \
 : audiod_command.c
 
 server_command_lists := $(cmdlist_dir)/server.command_list.man \
diff --git a/NEWS b/NEWS
index 7faa0dddfd6c08954a03b3ef79d768dc14014d6e..a5bef9f633eb8f25319865ea48f79bd8e34785a6 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -11,6 +11,7 @@ current master branch "cascading gradient"
        - The check command now also checks the attribute table for
          inconsistencies.
        - New -v flag for the version command (print verbose version string)
+       - New option --priority for para_server and para_audiod.
 
 
 --------------------------------------
index 5b2e9fba0a2b7b50fe25b35e166f66c92973858a..d3e694548a3dbfaf08e40eb5cd8ba01bc10af7cf 100644 (file)
--- a/aac_afh.c
+++ b/aac_afh.c
@@ -46,23 +46,13 @@ static int aac_find_stsz(unsigned char *buf, size_t buflen, off_t *skip)
 
 static int atom_cmp(const unsigned char *buf1, const char *buf2)
 {
-       const unsigned char *b2 = (unsigned char *)buf2;
-
-       if (buf1[0] != b2[0])
-               return 1;
-       if (buf1[1] != b2[1])
-               return 1;
-       if (buf1[2] != b2[2])
-               return 1;
-       if (buf1[3] != b2[3])
-               return 1;
-       return 0;
+       return memcmp(buf1, buf2, 4)? 1 : 0;
 }
 
 static int read_atom_header(unsigned char *buf, uint64_t *subsize, unsigned char type[5])
 {
        int i;
-       uint64_t size = (buf[0] << 24) + (buf[1] << 16) + (buf[2] << 8) + buf[3];
+       uint64_t size = aac_read_int32(buf);
 
        memcpy(type, buf + 4, 4);
        type[4] = '\0';
@@ -174,7 +164,7 @@ static ssize_t aac_compute_chunk_table(struct afh_info *afhi,
        if (ret < 0)
                return ret;
        afhi->chunks_total = ret;
-       PARA_DEBUG_LOG("sz table has %lu entries\n", afhi->chunks_total);
+       PARA_DEBUG_LOG("sz table has %" PRIu32 " entries\n", afhi->chunks_total);
        afhi->chunk_table = para_malloc((afhi->chunks_total + 1) * sizeof(size_t));
        for (i = 1; i <= afhi->chunks_total; i++) {
                if (skip + 4 > numbytes)
@@ -189,7 +179,7 @@ static ssize_t aac_compute_chunk_table(struct afh_info *afhi,
 }
 
 static int aac_set_chunk_tv(struct afh_info *afhi,
-               mp4AudioSpecificConfig *mp4ASC, long unsigned *seconds)
+               mp4AudioSpecificConfig *mp4ASC, uint32_t *seconds)
 {
        float tmp = mp4ASC->sbr_present_flag == 1? 2047 : 1023;
        struct timeval total;
@@ -200,7 +190,7 @@ static int aac_set_chunk_tv(struct afh_info *afhi,
        ms = 1000.0 * afhi->chunks_total * tmp / mp4ASC->samplingFrequency;
        ms2tv(ms, &total);
        tv_divide(afhi->chunks_total, &total, &afhi->chunk_tv);
-       PARA_INFO_LOG("%luHz, %lus (%lu x %lums)\n",
+       PARA_INFO_LOG("%luHz, %lus (%" PRIu32 " x %lums)\n",
                mp4ASC->samplingFrequency, ms / 1000,
                afhi->chunks_total, tv2ms(&afhi->chunk_tv));
        if (ms < 1000)
diff --git a/afh.h b/afh.h
index 62e38c02af85a946c74533115b8f826be337781a..7a30947a637e43fbeccc9788b30c21f917a427df 100644 (file)
--- a/afh.h
+++ b/afh.h
@@ -28,9 +28,9 @@ struct taginfo {
 /** Audio format dependent information. */
 struct afh_info {
        /** The number of chunks this audio file contains. */
-       long unsigned chunks_total;
+       uint32_t chunks_total;
        /** The length of the audio file in seconds. */
-       long unsigned seconds_total;
+       uint32_t seconds_total;
        /** Audio handler specific info about the file. */
        char *techinfo;
        /** Id3 tags, vorbis comments, aac tags. */
index b1f8b25dd5726bbf887f0f4bca481f59937371fc..063ae8f0b104ccab15e9f10f637ec34e7783e785 100644 (file)
@@ -367,9 +367,9 @@ unsigned afh_get_afhi_txt(int audio_format_num, struct afh_info *afhi, char **re
                "%s: %s\n" /* format */
                "%s: %dHz\n" /* frequency */
                "%s: %d\n" /* channels */
-               "%s: %lu\n" /* seconds total */
+               "%s: %" PRIu32 "\n" /* seconds total */
                "%s: %lu: %lu\n" /* chunk time */
-               "%s: %lu\n" /* num chunks */
+               "%s: %" PRIu32 "\n" /* num chunks */
                "%s: %s\n" /* techinfo */
                "%s: %s\n" /* artist */
                "%s: %s\n" /* title */
index ff794852239a093903d513581d7fbed2a4c93eff..164634634fedbaaf5441ebdec79dcff51e24d641 100644 (file)
@@ -40,11 +40,11 @@ static int afh_execute(struct btr_node *btrn, const char *cmd, char **result)
 
        *result = NULL;
        if (!strcmp(cmd, "seconds_total")) {
-               *result = make_message("%lu", pard->afhi.seconds_total);
+               *result = make_message("%" PRIu32, pard->afhi.seconds_total);
                return 1;
        }
        if (!strcmp(cmd, "chunks_total")) {
-               *result = make_message("%lu", pard->afhi.chunks_total);
+               *result = make_message("%" PRIu32, pard->afhi.chunks_total);
                return 1;
        }
        if (!strcmp(cmd, "afhi")) {
diff --git a/afs.c b/afs.c
index bd705050d328a23dda1b9610c3c5dd5d9dcb483d..d5afc6d9eb12eb731fecfdb8209bcd150e0e01cd 100644 (file)
--- a/afs.c
+++ b/afs.c
@@ -97,10 +97,11 @@ static char *current_mop; /* mode or playlist specifier. NULL means dummy mood *
 /**
  * A random number used to "authenticate" the connection.
  *
- * para_server picks this number by random before forking the afs process.  The
- * command handlers write this number together with the id of the shared memory
- * area containing the query. This way, a malicious local user has to know this
- * number to be able to cause the afs process to crash by sending fake queries.
+ * para_server picks this number by random before it forks the afs process. The
+ * command handlers know this number as well and write it to the afs socket,
+ * together with the id of the shared memory area which contains the payload of
+ * the afs command. A local process has to know this number to abuse the afs
+ * service provided by the local socket.
  */
 extern uint32_t afs_socket_cookie;
 
@@ -693,7 +694,7 @@ static int make_database_dir(void)
 
        get_database_dir();
        ret = para_mkdir(database_dir, 0777);
-       if (ret >= 0 || is_errno(-ret, EEXIST))
+       if (ret >= 0 || ret == -ERRNO_TO_PARA_ERROR(EEXIST))
                return 1;
        return ret;
 }
diff --git a/afs.h b/afs.h
index e77cdf020d2c2b7716dd03c9050cdc6c42b4c3f5..25ff421d8b86d0f5708d4b4f3749f310f9c4a877 100644 (file)
--- a/afs.h
+++ b/afs.h
@@ -6,8 +6,6 @@
 
 /** \file afs.h Exported symbols of the audio file selector. */
 
-#include <regex.h>
-
 /** Audio file selector data stored in the audio file table. */
 struct afs_info {
        /** Seconds since the epoch. */
diff --git a/aft.c b/aft.c
index 8a8e5282576dec0f3319bb98685bd0e1df9767c5..f5830dacd0ce98836380bd89dcc5a28cc29cbd45 100644 (file)
--- a/aft.c
+++ b/aft.c
@@ -676,21 +676,27 @@ int load_afd(int shmid, struct audio_file_data *afd)
 static int get_local_time(uint64_t *seconds, char *buf, size_t size,
        time_t current_time, enum ls_listing_mode lm)
 {
-       struct tm t;
+       struct tm *tm;
+       /*
+        * Omit year but show time if the given value is closer to the current
+        * time than this many seconds.
+        */
+       const time_t m = 6 * 30 * 24 * 3600; /* six months */
 
-       if (!localtime_r((time_t *)seconds, &t))
+       tm = localtime((time_t *)seconds);
+       if (!tm)
                return -E_LOCALTIME;
        if (lm == LS_MODE_MBOX) {
-               if (!strftime(buf, size, "%c", &t))
+               if (!strftime(buf, size, "%c", tm))
                        return -E_STRFTIME;
                return 1;
        }
-       if (*seconds + 6 * 30 * 24 * 3600 > current_time) {
-               if (!strftime(buf, size, "%b %e %k:%M", &t))
+       if (*seconds > current_time - m && *seconds < current_time + m) {
+               if (!strftime(buf, size, "%b %e %k:%M", tm))
                        return -E_STRFTIME;
                return 1;
        }
-       if (!strftime(buf, size, "%b %e  %Y", &t))
+       if (!strftime(buf, size, "%b %e %Y", tm))
                return -E_STRFTIME;
        return 1;
 }
@@ -915,12 +921,14 @@ static int print_list_item(struct ls_data *d, struct ls_options *opts,
        WRITE_STATUS_ITEM(b, SI_FREQUENCY, "%dHz\n", afhi->frequency);
        WRITE_STATUS_ITEM(b, SI_CHANNELS, "%d\n", afhi->channels);
        WRITE_STATUS_ITEM(b, SI_DURATION, "%s\n", duration_buf);
-       WRITE_STATUS_ITEM(b, SI_SECONDS_TOTAL, "%lu\n", afhi->seconds_total);
+       WRITE_STATUS_ITEM(b, SI_SECONDS_TOTAL, "%" PRIu32 "\n",
+               afhi->seconds_total);
        WRITE_STATUS_ITEM(b, SI_LAST_PLAYED, "%s\n", last_played_time);
        WRITE_STATUS_ITEM(b, SI_NUM_PLAYED, "%d\n", afsi->num_played);
        WRITE_STATUS_ITEM(b, SI_AMPLIFICATION, "%u\n", afsi->amp);
        WRITE_STATUS_ITEM(b, SI_CHUNK_TIME, "%lu\n", tv2ms(&afhi->chunk_tv));
-       WRITE_STATUS_ITEM(b, SI_NUM_CHUNKS, "%lu\n", afhi->chunks_total);
+       WRITE_STATUS_ITEM(b, SI_NUM_CHUNKS, "%" PRIu32 "\n",
+               afhi->chunks_total);
        WRITE_STATUS_ITEM(b, SI_TECHINFO, "%s\n", afhi->techinfo);
        WRITE_STATUS_ITEM(b, SI_ARTIST, "%s\n", afhi->tags.artist);
        WRITE_STATUS_ITEM(b, SI_TITLE, "%s\n", afhi->tags.title);
@@ -1737,6 +1745,8 @@ static int com_add_callback(struct afs_callback_arg *aca)
        objs[AFTCOL_AFSI].size = AFSI_SIZE;
        save_afsi(&default_afsi, &objs[AFTCOL_AFSI]);
        ret = osl(osl_add_and_get_row(audio_file_table, objs, &aft_row));
+       if (ret < 0)
+               goto out;
        ret = afs_event(AUDIO_FILE_ADD, &aca->pbout, aft_row);
 out:
        if (ret < 0)
index accf0244f957809b9c55b7e56b61127492264d62..798142f39a348ec6f0ac74e689332d18a1318444 100644 (file)
--- a/audiod.c
+++ b/audiod.c
@@ -525,11 +525,11 @@ static void close_filters(struct slot_info *s)
                return;
        for (i = a->num_filters - 1; i >= 0; i--) {
                struct filter_node *fn = s->fns + i;
-               struct filter *f;
+               const struct filter *f;
 
                if (!fn)
                        continue;
-               f = filters + fn->filter_num;
+               f = filter_get(fn->filter_num);
                if (f->close)
                        f->close(fn);
                btr_remove_node(&fn->btrn);
@@ -588,7 +588,7 @@ static void open_filters(struct slot_info *s)
        parent = s->receiver_node->btrn;
        for (i = 0; i < nf; i++) {
                char buf[20];
-               struct filter *f = filters + a->filter_nums[i];
+               const struct filter *f = filter_get(a->filter_nums[i]);
                fn = s->fns + i;
                fn->filter_num = a->filter_nums[i];
                fn->conf = a->filter_conf[i];
@@ -858,7 +858,7 @@ static int add_filter(int format, char *cmdline)
        a->filter_conf[nf] = cfg;
        a->num_filters++;
        PARA_INFO_LOG("%s filter %d: %s\n", audio_formats[format], nf,
-               filters[filter_num].name);
+               filter_get(filter_num)->name);
        return filter_num;
 }
 
@@ -993,20 +993,20 @@ static int init_default_filters(void)
                }
                /* add "dec" to audio format name */
                tmp = make_message("%sdec", audio_formats[i]);
-               for (j = 0; filters[j].name; j++)
-                       if (!strcmp(tmp, filters[j].name))
+               for (j = 0; filter_get(j); j++)
+                       if (!strcmp(tmp, filter_get(j)->name))
                                break;
                free(tmp);
                ret = -E_UNSUPPORTED_FILTER;
-               if (!filters[j].name)
+               if (!filter_get(j))
                        goto out;
-               tmp = para_strdup(filters[j].name);
+               tmp = para_strdup(filter_get(j)->name);
                ret = add_filter(i, tmp);
                free(tmp);
                if (ret < 0)
                        goto out;
                PARA_INFO_LOG("%s -> default filter: %s\n", audio_formats[i],
-                       filters[j].name);
+                       filter_get(j)->name);
        }
 out:
        return ret;
@@ -1474,6 +1474,7 @@ int main(int argc, char *argv[])
        writer_init();
        if (conf.help_given || conf.detailed_help_given)
                print_help_and_die();
+       daemon_set_priority(conf.priority_arg);
        daemon_drop_privileges_or_die(conf.user_arg, conf.group_arg);
        parse_config_or_die();
        daemon_init_colors_or_die(conf.color_arg, color_arg_auto, color_arg_no,
index b47364c9bd7b91c09d2e0c28fedc69efd3e5c6d0..cd1ccc619ce06710d9fad42652d6868942fc17d8 100644 (file)
@@ -403,7 +403,7 @@ static int client_post_select(struct sched *s, void *context)
                                        btr_consume(ct->btrn[1], sz);
                        }
                }
-               /* fall though */
+               /* fall through */
        case CL_EXECUTING:
                if (ct->btrn[0]) {
                        ret = btr_node_status(ct->btrn[0], 0, BTR_NT_ROOT);
index e8f6948437aac8c0f03b538381afc5ea20b55fe4..bde1458776856d26be371da2e309fb21354c5078 100644 (file)
--- a/command.c
+++ b/command.c
@@ -75,20 +75,14 @@ static void dummy(__a_unused int s)
 {
 }
 
-static void mmd_dup(struct misc_meta_data *new_mmd)
-{
-       mutex_lock(mmd_mutex);
-       *new_mmd = *mmd;
-       mutex_unlock(mmd_mutex);
-}
-
 /*
- * Compute human readable string containing vss status for given integer value.
+ * Compute human readable vss status text.
  *
- * We don't want to use vss_playing() and friends here because we take a
- * snapshot of the mmd struct and use the copy for computing the state of the
- * vss. If the real data were used, we would take the mmd lock for a rather
- * long time or risk to get an inconsistent view.
+ * We can't call vss_playing() and friends here because those functions read
+ * the flags from the primary mmd structure, so calling them from command
+ * handler context would require to take the mmd lock. At the time the function
+ * is called we already took a copy of the mmd structure and want to use the
+ * flags value of the copy for computing the vss status text.
  */
 static char *vss_status_tohuman(unsigned int flags)
 {
@@ -532,7 +526,13 @@ static int com_stat(struct command_context *cc)
        if (i != cc->argc)
                return -E_COMMAND_SYNTAX;
        for (;;) {
-               mmd_dup(nmmd);
+               /*
+                * Copy the mmd structure to minimize the time we hold the mmd
+                * lock.
+                */
+               mutex_lock(mmd_mutex);
+               *nmmd = *mmd;
+               mutex_unlock(mmd_mutex);
                ret = get_status(nmmd, parser_friendly, &s);
                ret = send_sb(&cc->scc, s, ret, SBD_OUTPUT, false);
                if (ret < 0)
index 2b2f2966b980bb6169c9501ce77e1ccaf830b0aa..5960b0871ec7fc720bef13a90d9af5a58dd75e10 100644 (file)
@@ -65,20 +65,6 @@ AC_DEFUN([LIB_SUBST_FLAGS], [
        AC_SUBST($1_ldflags)
 ])
 
-AC_PATH_PROG(UNAMEPATH, uname, no)
-if test "$UNAMEPATH" = "no"; then
-       AC_MSG_ERROR(unable to determine system type)
-fi
-AC_MSG_CHECKING(os type)
-OSTYPE="`$UNAMEPATH -s`"
-AC_MSG_RESULT("$OSTYPE")
-
-if test "$OSTYPE" = "SunOS"; then
-       # needed on SunOS for socket magic
-       arch_cppflags="-D_XOPEN_SOURCE=500 -D__EXTENSIONS__"
-       AC_SUBST(arch_cppflags)
-fi
-
 AC_C_BIGENDIAN()
 
 AC_PATH_PROG([GENGETOPT], [gengetopt])
index 94c4a8cba6b9aae8646491f3eeddfff016914c7b..478b0f47acc94d3098cc17576599032f007b43ca 100644 (file)
--- a/daemon.c
+++ b/daemon.c
@@ -11,6 +11,7 @@
 #include <sys/types.h> /* getgrnam() */
 #include <grp.h>
 #include <signal.h>
+#include <sys/resource.h>
 
 #include "para.h"
 #include "daemon.h"
@@ -260,6 +261,21 @@ void daemon_log_welcome(const char *name)
        PARA_INFO_LOG("welcome to para_%s-" PACKAGE_VERSION " \n", name);
 }
 
+/**
+ * Renice the calling process.
+ *
+ * \param prio The priority value to set.
+ *
+ * Errors are not considered fatal, but a warning message is logged if the
+ * underlying call to setpriority(2) fails.
+ */
+void daemon_set_priority(int prio)
+{
+       if (setpriority(PRIO_PROCESS, 0, prio) < 0)
+               PARA_WARNING_LOG("could not set priority to %d: %s\n", prio,
+                       strerror(errno));
+}
+
 /**
  * Give up superuser privileges.
  *
index ca3da140b812b8f5728d426e16bfdd8c40979c8f..621420a4340c75fc3eddbe37652c066c0772b8eb 100644 (file)
--- a/daemon.h
+++ b/daemon.h
@@ -5,6 +5,7 @@ void daemonize(bool parent_waits);
 void daemon_open_log_or_die(void);
 void daemon_close_log(void);
 void daemon_log_welcome(const char *whoami);
+void daemon_set_priority(int prio);
 void daemon_drop_privileges_or_die(const char *username, const char *groupname);
 void daemon_set_start_time(void);
 time_t daemon_get_uptime(const struct timeval *current_time);
diff --git a/error.h b/error.h
index 5d5666c63285835691ca65e95411e7dfc40eb99e..75532ea2518a93aa7e0cbcca4dec18cb0d3a5bd8 100644 (file)
--- a/error.h
+++ b/error.h
@@ -396,6 +396,7 @@ extern const char **para_errlist[];
        PARA_ERROR(SIZE_PREFIX, "bad size prefix"), \
        PARA_ERROR(REGEX, "regular expression error"), \
        PARA_ERROR(ARG_NOT_FOUND, "argument not found in arg vector"), \
+       PARA_ERROR(BAD_LL, "invalid loglevel"), \
 
 
 #define EXEC_ERRORS \
@@ -579,20 +580,8 @@ extern const char **para_errlist[];
 /** Set the osl error bit for the given number. */
 #define OSL_ERRNO_TO_PARA_ERROR(num) ((num) | (1 << OSL_ERROR_BIT))
 
-/** Check whether a given number is a system error number.
- *
- * \param num The value to be checked.
- * \param _errno The system error number.
- *
- * \return True if \a num is paraslash's representation of the system
- * error identified by \a _errno.
- */
-_static_inline_ bool is_errno(int num, int _errno)
-{
-       assert(num > 0 && _errno > 0);
-       return ERRNO_TO_PARA_ERROR(_errno) == num;
-}
 
+static const char *weak_osl_strerror(int) __attribute__ ((weakref("osl_strerror")));
 /**
  * Paraslash's version of strerror(3).
  *
@@ -603,12 +592,12 @@ _static_inline_ bool is_errno(int num, int _errno)
 _static_inline_ const char *para_strerror(int num)
 {
        assert(num > 0);
-#ifdef _OSL_H
-       if (IS_OSL_ERROR(num))
-               return osl_strerror(num & ((1 << OSL_ERROR_BIT) - 1));
-#endif
+       if (IS_OSL_ERROR(num)) {
+               assert(weak_osl_strerror);
+               return weak_osl_strerror(num & ~(1U << OSL_ERROR_BIT));
+       }
        if (IS_SYSTEM_ERROR(num))
-               return strerror(num & ((1 << SYSTEM_ERROR_BIT) - 1));
+               return strerror(num & ~(1U << SYSTEM_ERROR_BIT));
        return para_errlist[ERRNUM_TO_SS(num)][ERRNUM_TO_INDEX(num)];
 }
 
index f9ba17ad117ebe0da4a53a80a57dd5b21d49c5f8..1ba12689b45d7b41d3e2a8b1a8c06464114211a6 100644 (file)
--- a/filter.c
+++ b/filter.c
@@ -106,7 +106,7 @@ int main(int argc, char *argv[])
 {
        static struct sched s;
        int i, ret;
-       struct filter *f;
+       const struct filter *f;
        struct btr_node *parent;
        struct filter_node **fns;
 
@@ -133,7 +133,7 @@ int main(int argc, char *argv[])
                        goto out_cleanup;
                }
                fn->filter_num = ret;
-               f = filters + fn->filter_num;
+               f = filter_get(fn->filter_num);
                PARA_DEBUG_LOG("filter #%d: %s\n", i, f->name);
                fn->btrn = btr_new_node(&(struct btr_node_description)
                        EMBRACE(.name = f->name, .parent = parent,
@@ -159,7 +159,7 @@ out_cleanup:
        for (i--; i >= 0; i--) {
                struct filter_node *fn = fns[i];
 
-               f = filters + fn->filter_num;
+               f = filter_get(fn->filter_num);
                if (f->close)
                        f->close(fn);
                btr_remove_node(&fn->btrn);
index 135a6887405e496ef7c44154886d449c1e3e8156..31eedcc044d5c1a022b8a6bb6bdd37be1c0eb116 100644 (file)
--- a/filter.h
+++ b/filter.h
@@ -96,10 +96,12 @@ struct filter {
        /**
         * Set scheduler timeout and add file descriptors to fd sets.
         *
-        * This function is used to control the timeout value for select. It
-        * only allowed to decrease the current value. The second purpose of
-        * this function is to set file descriptors to be watched by the
-        * subsequent select call to the two fd sets.
+        * This function controls the timeout value for the next call to
+        * select(2). It may decrease the current timeout but shall never
+        * increase it. The second purpose of this function is to add file
+        * descriptors to the two fd sets of the sched structure. The
+        * descriptors in these sets will be watched by the subsequent
+        * select(2) call.
         */
        void (*pre_select)(struct sched *s, void *context);
        /**
@@ -138,8 +140,5 @@ static inline void write_int16_host_endian(char *buf, int val)
 
 DECLARE_FILTER_INITS
 
-/** Iterate over the array of supported filters. */
-#define FOR_EACH_SUPPORTED_FILTER(j)  for (j = 0; j < NUM_SUPPORTED_FILTERS; j++)
-
 /** The filter array, one structure for each supported filter. */
-extern struct filter filters[NUM_SUPPORTED_FILTERS];
+const struct filter *filter_get(int filter_num);
index 009ac936d55a7e398f623e6c374a4df68e5e06f4..099d056ef1514e2f606adf30d779308b58bead95 100644 (file)
 #include "error.h"
 #include "string.h"
 
+/** Iterate over the array of supported filters. */
+#define FOR_EACH_SUPPORTED_FILTER(j)  for (j = 0; j < NUM_SUPPORTED_FILTERS; j++)
+
 /** The array of supported filters. */
-struct filter filters[NUM_SUPPORTED_FILTERS] = {FILTER_ARRAY};
+static struct filter filters[NUM_SUPPORTED_FILTERS] = {FILTER_ARRAY};
+
+const struct filter *filter_get(int filter_num)
+{
+       assert(filter_num >= 0);
+       assert(filter_num < NUM_SUPPORTED_FILTERS);
+       return filters + filter_num;
+}
 
 /**
  * Call the init function of each supported filter.
@@ -31,7 +41,7 @@ void filter_init(void)
        int i;
 
        FOR_EACH_SUPPORTED_FILTER(i)
-               filters[i].init(filters + i);
+               filter_get(i)->init((struct filter *)filter_get(i));
 }
 
 /*
@@ -40,7 +50,7 @@ void filter_init(void)
  */
 static int parse_filter_args(int filter_num, char *options, void **conf)
 {
-       struct filter *f = &filters[filter_num];
+       const struct filter *f = filter_get(filter_num);
        int ret, argc;
        char **argv;
 
@@ -80,7 +90,7 @@ int check_filter_arg(char *fa, void **conf)
        *conf = NULL;
 //     PARA_DEBUG_LOG("arg: %s\n", fa);
        FOR_EACH_SUPPORTED_FILTER(j) {
-               const char *name = filters[j].name;
+               const char *name = filter_get(j)->name;
                size_t len = strlen(name);
                char c;
                if (strlen(fa) < len)
@@ -90,7 +100,7 @@ int check_filter_arg(char *fa, void **conf)
                c = fa[len];
                if (c && c != ' ')
                        continue;
-               if (c && !filters[j].parse_config)
+               if (c && !filter_get(j)->parse_config)
                        return -E_BAD_FILTER_OPTIONS;
                return parse_filter_args(j, c? fa + len + 1 :
                        fa + strlen(fa), conf);
@@ -113,12 +123,12 @@ void print_filter_helps(unsigned flags)
                        printf_or_die("\n                  ");
                        num = 0;
                }
-               num += printf_or_die("%s%s", i? " " : "", filters[i].name);
+               num += printf_or_die("%s%s", i? " " : "", filter_get(i)->name);
        }
        printf_or_die("\n");
 
        FOR_EACH_SUPPORTED_FILTER(i) {
-               struct filter *f = filters + i;
+               struct filter *f = (struct filter *)filter_get(i);
 
                if (!f->help.short_help)
                        continue;
index 08c3152121797a39218bced32d4944635acc212a..28a0a9ea09ef7204256beaf254f5d0e200653966 100644 (file)
@@ -22,19 +22,19 @@ required
 
 option "begin-chunk" b
 #~~~~~~~~~~~~~~~~~~~~~
-"skip a number of chunks"
+"skip the beginning of the file"
 int typestr = "chunk_num"
 default = "0"
 optional
 details = "
        The chunk_num argument must be between -num_chunks and
-       num_chunks - 1 inclusively where num_chunks is the total number
-       of chunks which is printed when using the --info option. If
-       chunk_num is negative, the given number of chunks are counted
-       backwards from the end of the file. For example --begin-chunk
-       -100 instructs para_afh to start output at chunk num_chunks
-       - 100. This is mainly useful for cutting off the end of an
-       audio file.
+       num_chunks - 1, inclusively, where num_chunks is the total
+       number of chunks of the audio file given by the argument to
+       --filename. If chunk_num is negative, the given number of
+       chunks are counted backwards from the end of the file. For
+       example --begin-chunk -100 instructs the afh receiver to
+       start output at chunk num_chunks - 100. This is useful for
+       selecting the last part of an audio file.
 "
 
 option "end-chunk" e
index 732f80873cdf39529e61f158a4d6cc40c2ae0735..75c045817898e8b840dc4734cd547ad282e67580 100644 (file)
@@ -20,6 +20,7 @@ include(log_timing.m4)
 include(daemon.m4)
 include(user.m4)
 include(group.m4)
+include(priority.m4)
 
 <qu>
 ########################
diff --git a/m4/gengetopt/priority.m4 b/m4/gengetopt/priority.m4
new file mode 100644 (file)
index 0000000..0b37dc0
--- /dev/null
@@ -0,0 +1,16 @@
+option "priority" -
+#~~~~~~~~~~~~~~~~~~
+"adjust scheduling priority"
+int typestr = "prio"
+default = "0"
+optional
+details = "
+       The priority (also known as nice value) is a value in the range -20
+       to 19. Lower priorities cause more favorable scheduling. Since only
+       privileged processes may request a negative priority, specifying
+       a negative value works only if the daemon is started with root
+       privileges.
+
+       Failure to set the given priority value is not considered an error
+       but a log message is printed in this case.
+"
index 916e88563ea32af2fc75d94c19a74f5c03ea0b64..6aca7bac7f41ddb9a37d4ec96e329a210e275f1f 100644 (file)
@@ -18,6 +18,7 @@ include(color.m4)
 include(daemon.m4)
 include(user.m4)
 include(group.m4)
+include(priority.m4)
 
 <qu>
 option "port" p
index 484172abe6e28345073f339623f5219c390b58ce..73e744ec44088c4d8c92c1e19c1e6bed8b5076a0 100644 (file)
--- a/mp3_afh.c
+++ b/mp3_afh.c
@@ -656,7 +656,7 @@ static int mp3_read_info(unsigned char *map, size_t numbytes, int fd,
        afhi->channels = header_channels(&header);
        afhi->seconds_total = (tv2ms(&total_time) + 500) / 1000;
        tv_divide(afhi->chunks_total, &total_time, &afhi->chunk_tv);
-       PARA_DEBUG_LOG("%lu chunks, each %lums\n", afhi->chunks_total,
+       PARA_DEBUG_LOG("%" PRIu32 "chunks, each %lums\n", afhi->chunks_total,
                tv2ms(&afhi->chunk_tv));
        ret = mp3_get_id3(map, numbytes, fd, &afhi->tags);
        afhi->techinfo = make_message("%cbr, %s, %s tags", vbr? 'v' : 'c',
index b8b0006d5ac80ed666620690267aee9470f67747..e49b803b4e7a0e6492161d7be5c2b2fa21a16a09 100644 (file)
@@ -159,7 +159,7 @@ int ogg_get_file_info(char *map, size_t numbytes, struct afh_info *afhi,
        afhi->seconds_total = num_frames / afhi->frequency;
        /* use roughly one page per chunk */
        frames_per_chunk = num_frames / i;
-       PARA_INFO_LOG("%lu seconds, %d frames/chunk\n",
+       PARA_INFO_LOG("%" PRIu32 "seconds, %d frames/chunk\n",
                afhi->seconds_total, frames_per_chunk);
        ct_size = 250;
        afhi->chunk_table = para_malloc(ct_size * sizeof(uint32_t));
diff --git a/para.h b/para.h
index e5b18e4ca032bbf7a2a1976cafd9fbdb7f0aef04..f08d43a8e96cbaa607518615acdb22703a1cf292 100644 (file)
--- a/para.h
+++ b/para.h
@@ -206,7 +206,7 @@ _static_inline_ bool iov_valid(const struct iovec *iov)
  *
  *     2. The wav header (para_write only).
  *
- *     3. The --format option of para_write.
+ *     3. The --sample-format option of para_write.
  */
 #define SAMPLE_FORMATS \
        SAMPLE_FORMAT(SF_S8, "8 bit signed"), \
diff --git a/play.c b/play.c
index 7593a69b25123d6983d39de373c3399a4ec78d51..55c9ec1bbb635946fe8ec92eadb52fa0accc8bf6 100644 (file)
--- a/play.c
+++ b/play.c
@@ -184,10 +184,10 @@ static void parse_config_or_die(int argc, char *argv[])
                loglevel = get_loglevel_by_name(conf.loglevel_arg);
        }
        for (i = 0; i < conf.key_map_given; i++) {
-               char *s = strchr(conf.key_map_arg[i] + 1, ':');
-               if (s)
+               char *kma = conf.key_map_arg[i];
+               if (*kma && strchr(kma + 1, ':'))
                        continue;
-               PARA_EMERG_LOG("invalid key map arg: %s\n", conf.key_map_arg[i]);
+               PARA_EMERG_LOG("invalid key map arg: %s\n", kma);
                goto err;
        }
        free(config_file);
@@ -263,7 +263,7 @@ static int get_playback_error(struct play_task *pt)
 static int eof_cleanup(struct play_task *pt)
 {
        struct writer *w = writers + DEFAULT_WRITER;
-       struct filter *decoder = filters + pt->fn.filter_num;
+       const struct filter *decoder = filter_get(pt->fn.filter_num);
        int ret;
 
        ret = get_playback_error(pt);
@@ -368,7 +368,7 @@ static int load_file(struct play_task *pt)
        const char *af;
        char *tmp, buf[20];
        int ret;
-       struct filter *decoder;
+       const struct filter *decoder;
 
        btr_remove_node(&pt->rn.btrn);
        if (!pt->rn.receiver || pt->next_file != pt->current_file) {
@@ -393,7 +393,7 @@ static int load_file(struct play_task *pt)
        if (ret < 0)
                goto fail;
        pt->fn.filter_num = ret;
-       decoder = filters + ret;
+       decoder = filter_get(ret);
        pt->fn.btrn = btr_new_node(&(struct btr_node_description)
                EMBRACE(.name = decoder->name, .parent = pt->rn.btrn,
                        .handler = decoder->execute, .context = &pt->fn));
@@ -1031,7 +1031,7 @@ static void sigint_handler(int sig)
  * stderr. Once the i9e subsystem has been initialized, we switch to the i9e
  * log facility.
  */
-static void session_open(__a_unused struct play_task *pt)
+static void session_open(struct play_task *pt)
 {
        int ret;
        char *history_file;
index aa2823c4f2fbce62195832a7ffd6aa2b3a101344..59630dfcc5f5f6fc5cfa973fd25c4476366b6b92 100644 (file)
@@ -55,10 +55,10 @@ static void *parse_receiver_args(int receiver_num, char *options)
  * \param \ra string of the form receiver_name:options
  * \param receiver_num contains the number of the receiver upon success
  *
- * This function checks whether \a ra starts with the name of a supported
- * paraslash receiver, optionally followed by a colon and any options for that
- * receiver. If a valid receiver name was found the remaining part of \a ra is
- * passed to the receiver's config parser.
+ * This function checks whether \a ra starts with the name of a receiver,
+ * optionally followed by options for that receiver. If a valid receiver name
+ * was found the remaining part of \a ra is passed to the receiver's config
+ * parser.
  *
  * \return On success, a pointer to the receiver-specific gengetopt args info
  * struct is returned and \a receiver_num contains the number of the receiver.
index 7cb6e5200fa696471e7baaf5a4ee121cdef47755..71a9ec505f6d096a1dc589a9cdf6c1f484e5090d 100644 (file)
--- a/server.c
+++ b/server.c
@@ -463,6 +463,7 @@ static void server_init(int argc, char **argv)
        version_handle_flag("server", conf.version_given);
        if (conf.help_given || conf.detailed_help_given)
                print_help_and_die();
+       daemon_set_priority(conf.priority_arg);
        daemon_drop_privileges_or_die(conf.user_arg, conf.group_arg);
        /* parse config file, open log and set defaults */
        parse_config_or_die(0);
index c35285153fdadf031fafb544aea4affdf066a86d..c820bdca3fd1ca37695354aa03024b4d384da765 100644 (file)
--- a/string.c
+++ b/string.c
@@ -633,7 +633,7 @@ int get_loglevel_by_name(const char *txt)
                return LL_CRIT;
        if (loglevel_equal(txt, "emerg"))
                return LL_EMERG;
-       return -1;
+       return -E_BAD_LL;
 }
 
 static int get_next_word(const char *buf, const char *delim, char **word)
index 6ef9ac84862be90980474f699911421140fc6618..15bb6859b1c2e668245bf0663bc57d7593710f83 100644 (file)
@@ -1,4 +1,4 @@
-RM ?= rm -f
+RM = rm -f
 
 results_dir := $(test_dir)/test-results
 trash_dir := $(test_dir)/trashes
index a14a04e9d05bbf33034b8630e05141aa9632a33d..76128512bca28b7fba427cdb4b36b446629472cd 100755 (executable)
@@ -45,7 +45,7 @@ bad[$i]='.'
 let i++
 commands[$i]="ls_ogg"
 required_objects[$i]='ogg_afh'
-cmdline[$i]="ls -lv ${oggs_base[@]}"
+cmdline[$i]="ls -l=v ${oggs_base[@]}"
 good[$i]='^basename:'
 
 let i++
index 7a627aad34784eab0a9fd15de5ff2883b48235fd..fa32d4112e0ee80592b04c40214ffc7a868c9d89 100755 (executable)
@@ -32,8 +32,12 @@ test_require_objects "audiod"
 if [[ -n "$result" ]]; then
        test_skip 'para_audiod' "missing object(s): $result"
 else
-       test_expect_success 'para_audiod: recv/filter/writer options' \
-               "grep_man '$regex' audiod"
+       test_expect_success 'para_audiod: receivers' \
+               "grep_man 'Options for the http receiver' audiod"
+       test_expect_success 'para_audiod: filters' \
+               "grep_man 'Options for the compress filter' audiod"
+       test_expect_success 'para_audiod: writers' \
+               "grep_man 'Options for the file writer' audiod"
 fi
 
 # check various command lists
@@ -60,5 +64,4 @@ fi
 # para_play is always built
 regex='LIST OF COMMANDS.\{100,\}'
 test_expect_success 'para_play: play commands' "grep_man '$regex' play"
-regex="$rfw_regex"
 test_done
index 3379f98d1dcd2f6b205492f13f4a8bd3e2807ac0..faae208c2d6d9142760d93d2d7033b2b53e9e95f 100644 (file)
@@ -156,11 +156,6 @@ err:
        return -ERRNO_TO_PARA_ERROR(errno);
 }
 
-static void udp_init_session(struct sender_client *sc)
-{
-       PARA_NOTICE_LOG("sending to udp %s\n", sc->name);
-}
-
 static void udp_shutdown_targets(void)
 {
        struct sender_client *sc, *tmp;
@@ -239,7 +234,7 @@ static int udp_init_fec(struct sender_client *sc)
 {
        int mps;
 
-       udp_init_session(sc);
+       PARA_NOTICE_LOG("sending to udp %s\n", sc->name);
        mps = generic_max_transport_msg_size(sc->fd) - sizeof(struct udphdr);
        PARA_INFO_LOG("current MPS = %d bytes\n", mps);
        return mps;
index 0963306e226bf3bdbd7e03ba591a8cfc970c2946..d63b07e8cbb69067439db6bca4875f9867908831 100644 (file)
@@ -2010,21 +2010,19 @@ Doxygen
 ~~~~~~~
 
 Doxygen is a documentation system for various programming
-languages. The paraslash project uses Doxygen for generating the API
-reference on the web pages, but good source code documentation is
-also beneficial to people trying to understand the code structure
-and the interactions between the various source files.
+languages. The API reference on the paraslash web page is generated
+by doxygen.
 
 It is more illustrative to look at the source code for examples than
-to describe the conventions for documenting the source in this manual,
-so we only describe which parts of the code need doxygen comments,
-but leave out details on documentation conventions.
+to describe the conventions in this manual, so we only describe which
+parts of the code need doxygen comments, but leave out details on
+documentation conventions.
 
 As a rule, only the public part of the C source is documented with
 Doxygen. This includes structures, defines and enumerations in header
 files as well as public (non-static) C functions.  These should be
-documented completely. For example each parameter and the return
-value of a public function should get a descriptive comment.
+documented completely. For example, each parameter and the return
+value of a public function should get a descriptive doxygen comment.
 
 No doxygen comments are necessary for static functions and for
 structures and enumerations in C files (which are used only within