Merge branch 'refs/heads/t/openssl-1.1'
authorAndre Noll <maan@tuebingen.mpg.de>
Tue, 27 Dec 2016 15:29:29 +0000 (16:29 +0100)
committerAndre Noll <maan@tuebingen.mpg.de>
Tue, 27 Dec 2016 15:31:07 +0000 (16:31 +0100)
In openssl-1.1 several structures have been made opaque, breaking both
the stream cipher and the public key functions in crypt.c. This series
deals with these issues, trying to minimize the ifdeffery.

* refs/heads/t/openssl-1.1 (cooking for three months):
  openssl: RSA fixes for openssl-1.1.
  openssl: Use EVP API for AES.

28 files changed:
NEWS.md
aac.h
aac_afh.c
aac_common.c
aacdec_filter.c
afh.h
afs.c
afs.cmd
aft.c
base64.c [new file with mode: 0644]
base64.h [new file with mode: 0644]
client.c
client_common.c
command.c
configure.ac
crypt.c
crypt_backend.h
crypt_common.c
daemon.c
daemon.h
error.h
gcrypt.c
play.c
portable_io.h
server.c
t/test-lib.sh
web/documentation.in.html
web/download.in.html

diff --git a/NEWS.md b/NEWS.md
index 71eb6cb..cad0169 100644 (file)
--- a/NEWS.md
+++ b/NEWS.md
@@ -1,6 +1,20 @@
 NEWS
 ====
 
+------------------------------------------
+0.5.7 (to be announced) "semantic density"
+------------------------------------------
+- Speedup of the base64 decoder.
+- One of the two source browsers has been removed from the web pages.
+  The doxygen API reference still contains an HTML version of each
+  source file.
+- Two race conditions in para_server have been fixed.
+- ls -p is now deprecated in favor of -F or -b. See the help text of
+  the ls command for details.
+- The openssl code has been adjusted to work also with openssl-1.1.
+
+Download: [tarball](./releases/paraslash-git.tar.bz2)
+
 ---------------------------------------
 0.5.6 (2016-07-10) "cascading gradient"
 ---------------------------------------
diff --git a/aac.h b/aac.h
index f31d723..eeed252 100644 (file)
--- a/aac.h
+++ b/aac.h
@@ -9,12 +9,6 @@
 #include <neaacdec.h>
 
 NeAACDecHandle aac_open(void);
-int aac_find_esds(unsigned char *buf, size_t buflen, size_t *skip,
+int aac_find_esds(char *buf, size_t buflen, size_t *skip,
                unsigned long *decoder_length);
-ssize_t aac_find_entry_point(unsigned char *buf, size_t buflen, size_t *skip);
-
-static inline unsigned aac_read_int32(unsigned char *buf)
-{
-       uint8_t *d = (uint8_t*)buf;
-       return (d[0] << 24) | (d[1] << 16) | (d[2] << 8) | d[3];
-}
+ssize_t aac_find_entry_point(char *buf, size_t buflen, size_t *skip);
index c49f30d..a30be96 100644 (file)
--- a/aac_afh.c
+++ b/aac_afh.c
 
 #include "para.h"
 #include "error.h"
+#include "portable_io.h"
 #include "afh.h"
 #include "string.h"
 #include "aac.h"
 #include "fd.h"
 
-static int aac_find_stsz(unsigned char *buf, size_t buflen, off_t *skip)
+static int aac_find_stsz(char *buf, size_t buflen, off_t *skip)
 {
        int i;
 
        for (i = 0; i + 16 < buflen; i++) {
-               unsigned char *p = buf + i;
+               char *p = buf + i;
                unsigned sample_count, sample_size;
 
                if (p[0] != 's' || p[1] != 't' || p[2] != 's' || p[3] != 'z')
                        continue;
                PARA_DEBUG_LOG("found stsz@%d\n", i);
                i += 8;
-               sample_size = aac_read_int32(buf + i);
+               sample_size = read_u32_be(buf + i);
                PARA_DEBUG_LOG("sample size: %d\n", sample_size);
                i += 4;
-               sample_count = aac_read_int32(buf + i);
+               sample_count = read_u32_be(buf + i);
                i += 4;
                PARA_DEBUG_LOG("sample count: %d\n", sample_count);
                *skip = i;
@@ -44,15 +45,14 @@ static int aac_find_stsz(unsigned char *buf, size_t buflen, off_t *skip)
        return -E_STSZ;
 }
 
-static int atom_cmp(const unsigned char *buf1, const char *buf2)
+static int atom_cmp(const char *buf1, const char *buf2)
 {
        return memcmp(buf1, buf2, 4)? 1 : 0;
 }
 
-static int read_atom_header(unsigned char *buf, uint64_t *subsize, unsigned char type[5])
+static int read_atom_header(char *buf, uint64_t *subsize, char type[5])
 {
-       int i;
-       uint64_t size = aac_read_int32(buf);
+       uint64_t size = read_u32_be(buf);
 
        memcpy(type, buf + 4, 4);
        type[4] = '\0';
@@ -64,13 +64,12 @@ static int read_atom_header(unsigned char *buf, uint64_t *subsize, unsigned char
        }
        buf += 4;
        size = 0;
-       for (i = 0; i < 8; i++)
-               size |= ((uint64_t)buf[i]) << ((7 - i) * 8);
+       size = read_u64_be(buf);
        *subsize = size;
        return 16;
 }
 
-static char *get_tag(unsigned char *p, int size)
+static char *get_tag(char *p, int size)
 {
        char *buf;
 
@@ -83,12 +82,12 @@ static char *get_tag(unsigned char *p, int size)
        return buf;
 }
 
-static void read_tags(unsigned char *buf, size_t buflen, struct afh_info *afhi)
+static void read_tags(char *buf, size_t buflen, struct afh_info *afhi)
 {
-       unsigned char *p = buf;
+       char *p = buf;
 
        while (p + 32 < buf + buflen) {
-               unsigned char *q, type1[5], type2[5];
+               char *q, type1[5], type2[5];
                uint64_t size1, size2;
                int ret, ret2;
 
@@ -117,9 +116,9 @@ static void read_tags(unsigned char *buf, size_t buflen, struct afh_info *afhi)
        }
 }
 
-static void read_meta(unsigned char *buf, size_t buflen, struct afh_info *afhi)
+static void read_meta(char *buf, size_t buflen, struct afh_info *afhi)
 {
-       unsigned char *p = buf;
+       char *p = buf;
 
        while (p + 4 < buf + buflen) {
 
@@ -132,15 +131,14 @@ static void read_meta(unsigned char *buf, size_t buflen, struct afh_info *afhi)
        }
 }
 
-static void aac_get_taginfo(unsigned char *buf, size_t buflen,
-               struct afh_info *afhi)
+static void aac_get_taginfo(char *buf, size_t buflen, struct afh_info *afhi)
 {
        int i;
        uint64_t subsize;
-       unsigned char type[5];
+       char type[5];
 
        for (i = 0; i + 24 < buflen; i++) {
-               unsigned char *p = buf + i;
+               char *p = buf + i;
                if (p[0] != 'm' || p[1] != 'e' || p[2] != 't' || p[3] != 'a')
                        continue;
                PARA_INFO_LOG("found metadata at offset %d\n", i);
@@ -154,7 +152,7 @@ static void aac_get_taginfo(unsigned char *buf, size_t buflen,
 }
 
 static ssize_t aac_compute_chunk_table(struct afh_info *afhi,
-               unsigned char *map, size_t numbytes)
+               char *map, size_t numbytes)
 {
        int ret, i;
        size_t sum = 0;
@@ -169,7 +167,7 @@ static ssize_t aac_compute_chunk_table(struct afh_info *afhi,
        for (i = 1; i <= afhi->chunks_total; i++) {
                if (skip + 4 > numbytes)
                        break;
-               sum += aac_read_int32(map + skip);
+               sum += read_u32_be(map + skip);
                afhi->chunk_table[i] = sum;
                skip += 4;
 //             if (i < 10 || i + 10 > afhi->chunks_total)
@@ -212,32 +210,33 @@ static int aac_get_file_info(char *map, size_t numbytes, __a_unused int fd,
        unsigned char channels = 0;
        mp4AudioSpecificConfig mp4ASC;
        NeAACDecHandle handle = NULL;
-       unsigned char *umap = (unsigned char *) map;
 
-       ret = aac_find_esds(umap, numbytes, &skip, &decoder_len);
+       ret = aac_find_esds(map, numbytes, &skip, &decoder_len);
        if (ret < 0)
                goto out;
-       aac_get_taginfo(umap, numbytes, afhi);
+       aac_get_taginfo(map, numbytes, afhi);
        handle = aac_open();
        ret = -E_AAC_AFH_INIT;
-       if (NeAACDecInit(handle, umap + skip, decoder_len, &rate, &channels))
+       if (NeAACDecInit(handle, (unsigned char *)map + skip, decoder_len,
+                       &rate, &channels))
                goto out;
        if (!channels)
                goto out;
        PARA_DEBUG_LOG("rate: %lu, channels: %d\n", rate, channels);
        ret = -E_MP4ASC;
-       if (NeAACDecAudioSpecificConfig(umap + skip, numbytes - skip, &mp4ASC))
+       if (NeAACDecAudioSpecificConfig((unsigned char *)map + skip,
+                       numbytes - skip, &mp4ASC))
                goto out;
        if (!mp4ASC.samplingFrequency)
                goto out;
-       ret = aac_compute_chunk_table(afhi, umap, numbytes);
+       ret = aac_compute_chunk_table(afhi, map, numbytes);
        if (ret < 0)
                goto out;
        skip = ret;
        ret = aac_set_chunk_tv(afhi, &mp4ASC, &afhi->seconds_total);
        if (ret < 0)
                goto out;
-       ret = aac_find_entry_point(umap + skip, numbytes - skip, &skip);
+       ret = aac_find_entry_point(map + skip, numbytes - skip, &skip);
        if (ret < 0)
                goto out;
        afhi->chunk_table[0] = ret;
index fe9b729..70a9d77 100644 (file)
@@ -13,6 +13,7 @@
 #include "para.h"
 #include "aac.h"
 #include "error.h"
+#include "portable_io.h"
 
 /**
  * Get a new libfaad decoder handle.
@@ -31,7 +32,7 @@ NeAACDecHandle aac_open(void)
        return h;
 }
 
-static unsigned long aac_read_decoder_length(unsigned char *buf, int *description_len)
+static unsigned long aac_read_decoder_length(char *buf, int *description_len)
 {
        uint8_t b;
        uint8_t numBytes = 0;
@@ -59,13 +60,13 @@ static unsigned long aac_read_decoder_length(unsigned char *buf, int *descriptio
  *
  * \return positive on success, negative on errors
  */
-int aac_find_esds(unsigned char *buf, size_t buflen, size_t *skip,
+int aac_find_esds(char *buf, size_t buflen, size_t *skip,
                unsigned long *decoder_length)
 {
        size_t i;
 
        for (i = 0; i + 4 < buflen; i++) {
-               unsigned char *p = buf + i;
+               char *p = buf + i;
                int description_len;
 
                if (p[0] != 'e' || p[1] != 's' || p[2] != 'd' || p[3] != 's')
@@ -108,19 +109,19 @@ int aac_find_esds(unsigned char *buf, size_t buflen, size_t *skip,
  * \return the position of the first entry in the table on success,
  * -E_STCO on errors.
  */
-ssize_t aac_find_entry_point(unsigned char *buf, size_t buflen, size_t *skip)
+ssize_t aac_find_entry_point(char *buf, size_t buflen, size_t *skip)
 {
        ssize_t ret;
        size_t i;
 
        for (i = 0; i + 20 < buflen; i++) {
-               unsigned char *p = buf + i;
+               char *p = buf + i;
 
                if (p[0] != 's' || p[1] != 't' || p[2] != 'c' || p[3] != 'o')
                        continue;
                PARA_INFO_LOG("found stco@%zu\n", i);
                i += 12;
-               ret = aac_read_int32(buf + i); /* first offset */
+               ret = read_u32_be(buf + i); /* first offset */
                i += 4;
                PARA_INFO_LOG("entry point: %zd\n", ret);
                *skip = i;
index ac8148e..9791175 100644 (file)
@@ -86,7 +86,7 @@ static int aacdec_post_select(__a_unused struct sched *s, void *context)
        struct btr_node *btrn = fn->btrn;
        struct private_aacdec_data *padd = fn->private_data;
        int i, ret;
-       unsigned char *p, *inbuf, *outbuffer;
+       char *p, *inbuf, *outbuffer;
        char *btr_buf;
        size_t len, skip, consumed, loaded;
 
@@ -97,7 +97,7 @@ next_buffer:
        if (ret == 0)
                return 0;
        btr_merge(btrn, fn->min_iqs);
-       len = btr_next_buffer(btrn, (char **)&inbuf);
+       len = btr_next_buffer(btrn, &inbuf);
        len = PARA_MIN(len, (size_t)8192);
        consumed = 0;
        if (!padd->initialized) {
@@ -106,7 +106,7 @@ next_buffer:
                ret = aac_find_esds(inbuf, len, &skip, &padd->decoder_length);
                if (ret < 0) {
                        PARA_INFO_LOG("%s\n", para_strerror(-ret));
-                       ret = NeAACDecInit(padd->handle, inbuf,
+                       ret = NeAACDecInit(padd->handle, (unsigned char *)inbuf,
                                len, &rate, &channels);
                        PARA_INFO_LOG("decoder init: %d\n", ret);
                        if (ret < 0) {
@@ -120,7 +120,7 @@ next_buffer:
                        consumed += skip;
                        p = inbuf + consumed;
                        ret = -E_AACDEC_INIT;
-                       if (NeAACDecInit2(padd->handle, p,
+                       if (NeAACDecInit2(padd->handle, (unsigned char *)p,
                                        padd->decoder_length, &rate,
                                        &channels) != 0)
                                goto out;
@@ -158,8 +158,8 @@ next_buffer:
        p = inbuf + consumed;
        //PARA_CRIT_LOG("consumed: %zu (%zu + %zu), have: %zu\n", padd->consumed_total + consumed,
        //      padd->consumed_total, consumed, len - consumed);
-       outbuffer = NeAACDecDecode(padd->handle, &padd->frame_info, p,
-               len - consumed);
+       outbuffer = NeAACDecDecode(padd->handle, &padd->frame_info,
+               (unsigned char *)p, len - consumed);
        if (padd->frame_info.error) {
                int err = padd->frame_info.error;
                ret = -E_AAC_DECODE;
diff --git a/afh.h b/afh.h
index dad6735..a6f9c50 100644 (file)
--- a/afh.h
+++ b/afh.h
@@ -36,9 +36,9 @@ struct afh_info {
        /** Id3 tags, vorbis comments, aac tags. */
        struct taginfo tags;
        /**
-        * The table that specifies the offset of the individual pieces in
-        * the current audio file.
-        */
+        * The table that specifies the offset of the individual pieces in
+        * the current audio file.
+        */
        uint32_t *chunk_table;
        /** Period of time between sending data chunks. */
        struct timeval chunk_tv;
@@ -48,7 +48,7 @@ struct afh_info {
         * which means that this audio format does not need any special header
         * treatment. The audio format handler does not need to set this to
         * zero in this case.
-        */
+        */
        uint32_t header_len;
        /** The number of channels. */
        uint8_t channels;
diff --git a/afs.c b/afs.c
index 0accc45..071f657 100644 (file)
--- a/afs.c
+++ b/afs.c
@@ -1024,6 +1024,13 @@ __noreturn void afs_init(uint32_t cookie, int socket_fd)
        register_command_task(cookie, &s);
        s.default_timeout.tv_sec = 0;
        s.default_timeout.tv_usec = 999 * 1000;
+       ret = write(socket_fd, "\0", 1);
+       if (ret != 1) {
+               if (ret == 0)
+                       errno = EINVAL;
+               ret = -ERRNO_TO_PARA_ERROR(errno);
+               goto out_close;
+       }
        ret = schedule(&s);
        sched_shutdown(&s);
 out_close:
diff --git a/afs.cmd b/afs.cmd
index 584ba80..76b5f4d 100644 (file)
--- a/afs.cmd
+++ b/afs.cmd
@@ -51,8 +51,13 @@ H:    p: parser-friendly mode
 H:    m: mbox listing mode
 H:    c: chunk-table listing mode
 H:
-H: -p  List full paths. If this option is not specified, only the basename
+H: -F  List full paths. If this option is not specified, only the basename
 H:     of each file is printed.
+H: -p  Synonym for -F. Deprecated.
+H:
+H: -b  Print only the basename of each matching file. This is the default, so
+H:     the option is currently a no-op. It is recommended to specify this option,
+H:     though, as the default might change in a future release.
 H:
 H: -a  List only files that are admissible with respect to the current mood or
 H:     playlist.
@@ -61,7 +66,8 @@ H: -r Reverse sort order.
 H:
 H: -d  Print dates as seconds after the epoch.
 H:
-H: -s=order    Change sort order. Defaults to alphabetical path sort if not given.
+H: -s=order
+H:     Change sort order. Defaults to alphabetical path sort if not given.
 H:
 H:   Possible values for order:
 H:   p: by path
diff --git a/aft.c b/aft.c
index f14440e..df29524 100644 (file)
--- a/aft.c
+++ b/aft.c
@@ -1410,10 +1410,14 @@ int com_ls(struct command_context *cc)
                                return -E_AFT_SYNTAX;
                        }
                }
-               if (!strcmp(arg, "-p")) {
+               if (!strcmp(arg, "-p") || !strcmp(arg, "-F")) {
                        flags |= LS_FLAG_FULL_PATH;
                        continue;
                }
+               if (!strcmp(arg, "-b")) {
+                       flags &= ~LS_FLAG_FULL_PATH;
+                       continue;
+               }
                if (!strcmp(arg, "-a")) {
                        flags |= LS_FLAG_ADMISSIBLE_ONLY;
                        continue;
diff --git a/base64.c b/base64.c
new file mode 100644 (file)
index 0000000..7b8fe29
--- /dev/null
+++ b/base64.c
@@ -0,0 +1,205 @@
+/*
+ * The code in this file was taken from openssh-5.2p1, Copyright (c) 1996 by
+ * Internet Software Consortium.  Portions Copyright (c) 1995 by International
+ * Business Machines, Inc.
+ */
+
+/** \file base64.c Uudecode and base64decode implementation. */
+
+#include <regex.h>
+
+#include "para.h"
+#include "error.h"
+#include "base64.h"
+#include "string.h"
+
+static const char Base64[] =
+       "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+static const unsigned char base64_tab[256] = {
+       255, 255, 255, 255, 255, 255, 255, 255, /* 00-07 */
+       255, 255, 255, 255, 255, 255, 255, 255, /* 08-0f */
+       255, 255, 255, 255, 255, 255, 255, 255, /* 10-17 */
+       255, 255, 255, 255, 255, 255, 255, 255, /* 18-1f */
+       255, 255, 255, 255, 255, 255, 255, 255, /* 20-2f */
+       255, 255, 255,  62, 255, 255, 255,  63, /* 28-2f */
+       52 ,  53,  54,  55,  56,  57,  58,  59, /* 30-37 */
+       60 ,  61, 255, 255, 255, 255, 255, 255, /* 38-3f */
+       255,   0,   1,   2,   3,   4,   5,   6, /* 40-47 */
+       7  ,   8,   9,  10,  11,  12,  13,  14, /* 48-4f */
+       15 ,  16,  17,  18,  19,  20,  21,  22, /* 50-57 */
+       23 ,  24,  25, 255, 255, 255, 255, 255, /* 58-5f */
+       255,  26,  27,  28,  29,  30,  31,  32, /* 60-6f */
+       33 ,  34,  35,  36,  37,  38,  39,  40, /* 68-6f */
+       41 ,  42,  43,  44,  45,  46,  47,  48, /* 70-77 */
+       49 ,  50,  51, 255, 255, 255, 255, 255, /* 78-7f */
+       255, 255, 255, 255, 255, 255, 255, 255, /* 80-87 */
+       255, 255, 255, 255, 255, 255, 255, 255, /* 88-8f */
+       255, 255, 255, 255, 255, 255, 255, 255, /* 90-97 */
+       255, 255, 255, 255, 255, 255, 255, 255, /* 98-9f */
+       255, 255, 255, 255, 255, 255, 255, 255, /* a0-a7 */
+       255, 255, 255, 255, 255, 255, 255, 255, /* a8-af */
+       255, 255, 255, 255, 255, 255, 255, 255, /* b0-b7 */
+       255, 255, 255, 255, 255, 255, 255, 255, /* b8-bf */
+       255, 255, 255, 255, 255, 255, 255, 255, /* c0-c7 */
+       255, 255, 255, 255, 255, 255, 255, 255, /* c8-cf */
+       255, 255, 255, 255, 255, 255, 255, 255, /* d0-d7 */
+       255, 255, 255, 255, 255, 255, 255, 255, /* d8-df */
+       255, 255, 255, 255, 255, 255, 255, 255, /* e0-e7 */
+       255, 255, 255, 255, 255, 255, 255, 255, /* e8-ef */
+       255, 255, 255, 255, 255, 255, 255, 255, /* f0-f7 */
+       255, 255, 255, 255, 255, 255, 255, 255, /* f8-ff */
+};
+
+/** Maximal possible size of the decoded data. */
+#define BASE64_MAX_DECODED_SIZE(_encoded_size) ((_encoded_size) / 4 * 3)
+
+#define PAD64 '='
+/**
+ * base64-decode a buffer.
+ *
+ * \param src The buffer to decode.
+ * \param encoded_size The special value -1 means: look for terminating zero byte.
+ * \param result Points to dynamically allocated target buffer on success.
+ * \param decoded_size Number of bytes written to \a result.
+ *
+ * Skips all whitespace anywhere. Converts characters, four at a time, starting
+ * at (or after) src from base - 64 numbers into three 8 bit bytes in the
+ * target area.
+ *
+ * It is OK to pass a \p NULL pointer as \a decoded_size. The result is
+ * terminated with a zero byte.
+ *
+ * \return Standard. The contents of result \a and \a decoded_size are
+ * undefined on failure.
+ */
+int base64_decode(char const *src, size_t encoded_size, char **result,
+               size_t *decoded_size)
+{
+       size_t i, j, state; /* source/target indices */
+       const char *end = src + encoded_size, *p;
+       unsigned char *target, uch;
+
+       if (encoded_size == (size_t)-1)
+               encoded_size = strlen(src);
+       target = para_malloc(BASE64_MAX_DECODED_SIZE(encoded_size) + 1);
+
+       for (
+               i = 0, j = 0, state = 0;
+               i < encoded_size && (uch = src[i]) != '\0';
+               i++
+       ) {
+               if (para_isspace(uch)) /* Skip whitespace anywhere. */
+                       continue;
+               if (uch == PAD64)
+                       break;
+               if (base64_tab[uch] == 255) /* A non-base64 character. */
+                       goto fail;
+               uch = base64_tab[uch];
+               switch (state) {
+               case 0:
+                       target[j] = uch << 2;
+                       break;
+               case 1:
+                       target[j] |= uch >> 4;
+                       j++;
+                       target[j] = (uch & 0x0f) << 4;
+                       break;
+               case 2:
+                       target[j] |= uch >> 2;
+                       j++;
+                       target[j] = (uch & 0x03) << 6;
+                       break;
+               case 3:
+                       target[j] |= uch;
+                       j++;
+                       break;
+               }
+               state = (state + 1) % 4;
+       }
+       p = (i < encoded_size)? src + i : NULL;
+       /*
+        * We are done decoding Base-64 chars.  Let's see if we ended
+        * on a byte boundary, and/or with erroneous trailing characters.
+        */
+       if (p && *p == PAD64) { /* We got a pad char. Skip it, get next. */
+               p++;
+               switch (state) {
+               case 0: /* Invalid = in first position */
+               case 1: /* Invalid = in second position */
+                       goto fail;
+
+               case 2: /* Valid, means one byte of info */
+                       /* Skip any number of spaces. */
+                       for (; p < end && *p != '\0'; p++)
+                               if (!para_isspace(*p))
+                                       break;
+                       /* Make sure there is another trailing = sign. */
+                       if (*p != PAD64)
+                               goto fail;
+                       /* Fall through to "single trailing =" case. */
+                       p++;
+
+               case 3: /* Valid, means two bytes of info */
+                       /*
+                        * We know this char is an =.  Is there anything but
+                        * whitespace after it?
+                        */
+                       for (; p < end && *p != '\0'; p++)
+                               if (!para_isspace(*p))
+                                       goto fail;
+                       /*
+                        * Now make sure for cases 2 and 3 that the "extra"
+                        * bits that slopped past the last full byte were
+                        * zeros.  If we don't check them, they become a
+                        * subliminal channel.
+                        */
+                       if (target[j] != 0)
+                               goto fail;
+               }
+       } else {
+               /*
+                * We ended by seeing the end of the string.  Make sure we
+                * have no partial bytes lying around.
+                */
+               if (state != 0)
+                       goto fail;
+       }
+       /* success */
+       target[j] = '\0'; /* just to be sure */
+       if (decoded_size)
+               *decoded_size = j;
+       *result = (char *)target;
+       return 1;
+fail:
+       free(target);
+       return -E_BASE64;
+}
+
+/**
+ * Decode a buffer using the uuencode Base64 algorithm.
+ *
+ * \param src The buffer to decode.
+ * \param encoded_size Number of input bytes in the source buffer.
+ * \param result Contains the decoded data on success.
+ * \param decoded_size Number of output bytes on success.
+ *
+ * This is just a simple wrapper for \ref base64_decode() which strips
+ * whitespace.
+ *
+ * \return The return value of the underlying call to \ref base64_decode().
+ *
+ * \sa uuencode(1), uudecode(1).
+ */
+int uudecode(char const *src, size_t encoded_size, char **result,
+               size_t *decoded_size)
+{
+       const char *end = src + encoded_size, *p;
+
+       /* skip whitespace and data */
+       for (p = src; p < end && (*p == ' ' || *p == '\t'); p++)
+               ;
+       for (; p < end && *p != '\0' && *p != ' ' && *p != '\t'; p++)
+               ;
+       /* and remove trailing whitespace because base64_decode needs this */
+       return base64_decode(src, p - src, result, decoded_size);
+}
diff --git a/base64.h b/base64.h
new file mode 100644 (file)
index 0000000..4bfaa99
--- /dev/null
+++ b/base64.h
@@ -0,0 +1,4 @@
+int uudecode(char const *src, size_t encoded_size, char **result,
+               size_t *decoded_size);
+int base64_decode(char const *src, size_t encoded_size, char **result,
+               size_t *decoded_size);
index 31cfff0..64b1553 100644 (file)
--- a/client.c
+++ b/client.c
@@ -278,7 +278,7 @@ static void ls_completer(struct i9e_completion_info *ci,
        char *opts[] = {
                "--", "-l", "-l=s", "-l=l", "-l=v", "-l=p", "-l=m", "-l=c",
                "-p", "-a", "-r", "-d", "-s=p", "-s=l", "-s=s", "-s=n", "-s=f",
-               "-s=c", "-s=i", "-s=y", "-s=b", "-s=d", "-s=a", NULL
+               "-s=c", "-s=i", "-s=y", "-s=b", "-s=d", "-s=a", "-F", "-b", NULL
        };
        if (ci->word[0] == '-')
                i9e_complete_option(opts, ci, cr);
index cd1ccc6..eea7510 100644 (file)
@@ -292,11 +292,6 @@ static int client_post_select(struct sched *s, void *context)
                if (ret < 0 || n == 0)
                        goto out;
                ct->features = parse_features(buf);
-               if (!has_feature("sideband", ct)) {
-                       PARA_ERROR_LOG("server has no sideband support\n");
-                       ret = -E_INCOMPAT_FEAT;
-                       goto out;
-               }
                ct->status = CL_RECEIVED_WELCOME;
                return 0;
        case CL_RECEIVED_WELCOME: /* send auth command */
index 93de2d2..0eb4efc 100644 (file)
--- a/command.c
+++ b/command.c
@@ -807,7 +807,6 @@ static void reset_signals(void)
 }
 
 struct connection_features {
-       bool sideband_requested;
        bool aes_ctr128_requested;
 };
 
@@ -835,8 +834,8 @@ static int parse_auth_request(char *buf, int len, struct user **u,
                create_argv(p, ",", &features);
                for (i = 0; features[i]; i++) {
                        if (strcmp(features[i], "sideband") == 0)
-                               cf->sideband_requested = true;
-                       else if (strcmp(features[i], "aes_ctr128") == 0)
+                               continue;
+                       if (strcmp(features[i], "aes_ctr128") == 0)
                                cf->aes_ctr128_requested = true;
                        else {
                                ret = -E_BAD_FEATURE;
@@ -949,11 +948,6 @@ __noreturn void handle_connect(int fd, const char *peername)
        ret = parse_auth_request(buf, ret, &cc->u, &cf);
        if (ret < 0)
                goto net_err;
-       if (!cf.sideband_requested) { /* sideband is mandatory */
-               PARA_ERROR_LOG("client did not request sideband\n");
-               ret = -E_BAD_FEATURE;
-               goto net_err;
-       }
        if (cc->u) {
                get_random_bytes_or_die(rand_buf, sizeof(rand_buf));
                ret = pub_encrypt(cc->u->pubkey, rand_buf, sizeof(rand_buf),
index e502e0a..74f3fd9 100644 (file)
@@ -422,6 +422,7 @@ if test -n "$CRYPTOLIB" && test $HAVE_OSL = yes; then
                close_on_fork
                mm
                crypt_common
+               base64
                ipc
                dccp_send
                fd
@@ -484,6 +485,7 @@ if test -n "$CRYPTOLIB"; then
                client_common
                buffer_tree
                crypt_common
+               base64
                version
                ggo
        "
@@ -527,6 +529,7 @@ if test -n "$CRYPTOLIB"; then
                stat
                net
                crypt_common
+               base64
                sideband
                time
                grab_client
diff --git a/crypt.c b/crypt.c
index e819e8b..8116fb6 100644 (file)
--- a/crypt.c
+++ b/crypt.c
@@ -23,6 +23,7 @@
 #include "crypt.h"
 #include "fd.h"
 #include "crypt_backend.h"
+#include "base64.h"
 
 struct asymmetric_key {
        RSA *rsa;
@@ -165,7 +166,7 @@ int get_asymmetric_key(const char *key_file, int private,
        struct asymmetric_key *key = NULL;
        void *map = NULL;
        unsigned char *blob = NULL;
-       size_t map_size, blob_size, decoded_size;
+       size_t map_size, encoded_size, decoded_size;
        int ret, ret2;
        char *cp;
 
@@ -187,16 +188,11 @@ int get_asymmetric_key(const char *key_file, int private,
                goto out;
        }
        cp = map + ret;
+       encoded_size = map_size - ret;
        PARA_INFO_LOG("decoding public rsa-ssh key %s\n", key_file);
-       ret = -ERRNO_TO_PARA_ERROR(EOVERFLOW);
-       if (map_size > INT_MAX / 4)
-               goto out_unmap;
-       blob_size = 2 * map_size;
-       blob = para_malloc(blob_size);
-       ret = uudecode(cp, blob, blob_size);
+       ret = uudecode(cp, encoded_size, (char **)&blob, &decoded_size);
        if (ret < 0)
                goto out_unmap;
-       decoded_size = ret;
        ret = check_ssh_key_header(blob, decoded_size);
        if (ret < 0)
                goto out_unmap;
index 06c86d7..f9a69d9 100644 (file)
@@ -13,7 +13,5 @@
 
 size_t is_ssh_rsa_key(char *data, size_t size);
 uint32_t read_ssh_u32(const void *vp);
-int uudecode(const char *src, unsigned char *target, size_t targsize);
 int check_ssh_key_header(const unsigned char *blob, int blen);
 int check_key_file(const char *file, bool private_key);
-int base64_decode(char const *src, unsigned char *target, size_t targsize);
index 022692a..b39ee5e 100644 (file)
@@ -45,166 +45,6 @@ size_t is_ssh_rsa_key(char *data, size_t size)
        return cp - data;
 }
 
-/*
- * This base64/uudecode stuff below is taken from openssh-5.2p1, Copyright (c)
- * 1996 by Internet Software Consortium.  Portions Copyright (c) 1995 by
- * International Business Machines, Inc.
- */
-
-static const char Base64[] =
-       "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
-static const char Pad64 = '=';
-
-/**
- * base64-decode a buffer.
- *
- * \param src The buffer to decode.
- * \param target Result is stored here.
- * \param targsize Number of bytes of \a target.
- *
- * Skips all whitespace anywhere. Converts characters, four at a time, starting
- * at (or after) src from base - 64 numbers into three 8 bit bytes in the
- * target area.
- *
- * \return The number of data bytes stored at the target, -E_BASE64 on errors.
- */
-int base64_decode(char const *src, unsigned char *target, size_t targsize)
-{
-       unsigned int tarindex, state;
-       int ch;
-       char *pos;
-
-       state = 0;
-       tarindex = 0;
-
-       while ((ch = *src++) != '\0') {
-               if (para_isspace(ch)) /* Skip whitespace anywhere. */
-                       continue;
-
-               if (ch == Pad64)
-                       break;
-
-               pos = strchr(Base64, ch);
-               if (pos == NULL) /* A non-base64 character. */
-                       return -E_BASE64;
-
-               switch (state) {
-               case 0:
-                       if (tarindex >= targsize)
-                               return -E_BASE64;
-                       target[tarindex] = (pos - Base64) << 2;
-                       state = 1;
-                       break;
-               case 1:
-                       if (tarindex + 1 >= targsize)
-                               return -E_BASE64;
-                       target[tarindex] |= (pos - Base64) >> 4;
-                       target[tarindex + 1] = ((pos - Base64) & 0x0f) << 4;
-                       tarindex++;
-                       state = 2;
-                       break;
-               case 2:
-                       if (tarindex + 1 >= targsize)
-                               return -E_BASE64;
-                       target[tarindex] |= (pos - Base64) >> 2;
-                       target[tarindex + 1] = ((pos - Base64) & 0x03) << 6;
-                       tarindex++;
-                       state = 3;
-                       break;
-               case 3:
-                       if (tarindex >= targsize)
-                               return -E_BASE64;
-                       target[tarindex] |= pos - Base64;
-                       tarindex++;
-                       state = 0;
-                       break;
-               }
-       }
-
-       /*
-        * We are done decoding Base-64 chars.  Let's see if we ended
-        * on a byte boundary, and/or with erroneous trailing characters.
-        */
-
-       if (ch == Pad64) {              /* We got a pad char. */
-               ch = *src++;            /* Skip it, get next. */
-               switch (state) {
-               case 0:         /* Invalid = in first position */
-               case 1:         /* Invalid = in second position */
-                       return -E_BASE64;
-
-               case 2:         /* Valid, means one byte of info */
-                       /* Skip any number of spaces. */
-                       for (; ch != '\0'; ch = *src++)
-                               if (!isspace(ch))
-                                       break;
-                       /* Make sure there is another trailing = sign. */
-                       if (ch != Pad64)
-                               return -E_BASE64;
-                       ch = *src++;            /* Skip the = */
-                       /* Fall through to "single trailing =" case. */
-                       /* FALLTHROUGH */
-
-               case 3:         /* Valid, means two bytes of info */
-                       /*
-                        * We know this char is an =.  Is there anything but
-                        * whitespace after it?
-                        */
-                       for (; ch != '\0'; ch = *src++)
-                               if (!isspace(ch))
-                                       return -E_BASE64;
-
-                       /*
-                        * Now make sure for cases 2 and 3 that the "extra"
-                        * bits that slopped past the last full byte were
-                        * zeros.  If we don't check them, they become a
-                        * subliminal channel.
-                        */
-                       if (target[tarindex] != 0)
-                               return -E_BASE64;
-               }
-       } else {
-               /*
-                * We ended by seeing the end of the string.  Make sure we
-                * have no partial bytes lying around.
-                */
-               if (state != 0)
-                       return -E_BASE64;
-       }
-
-       return tarindex;
-}
-
-/**
- * uudecode a buffer.
- *
- * \param src The buffer to decode.
- * \param target Result buffer.
- * \param targsize The length of \a target in bytes.
- *
- * This is just a simple wrapper for base64_decode() which strips whitespace.
- *
- * \return The return value of the underlying call to base64_decode().
- */
-int uudecode(const char *src, unsigned char *target, size_t targsize)
-{
-       int len;
-       char *encoded, *p;
-
-       /* copy the 'readonly' source */
-       encoded = para_strdup(src);
-       /* skip whitespace and data */
-       for (p = encoded; *p == ' ' || *p == '\t'; p++)
-               ;
-       for (; *p != '\0' && *p != ' ' && *p != '\t'; p++)
-               ;
-       /* and remove trailing whitespace because base64_decode needs this */
-       *p = '\0';
-       len = base64_decode(encoded, target, targsize);
-       free(encoded);
-       return len;
-}
-
 /**
  * Read a 4-byte number from a buffer in big-endian format.
  *
index 7c625bb..20cdc6a 100644 (file)
--- a/daemon.c
+++ b/daemon.c
@@ -155,10 +155,6 @@ static bool daemon_test_flag(unsigned flag)
        return me->flags & flag;
 }
 
-static void dummy_sighandler(__a_unused int s)
-{
-}
-
 /**
  * Do the usual stuff to become a daemon.
  *
@@ -166,30 +162,42 @@ static void dummy_sighandler(__a_unused int s)
  *
  * Fork, become session leader, cd to /, and dup fd 0, 1, 2 to /dev/null. If \a
  * parent_waits is false, the parent process terminates immediately.
- * Otherwise, it calls pause() to sleep until it receives \p SIGTERM or \p
- * SIGCHLD and exits successfully thereafter. This behaviour is useful if the
- * daemon process should not detach from the console until the child process
- * has completed its setup.
+ * Otherwise, a pipe is created prior to the fork() and the parent tries to
+ * read a single byte from the reading end of the pipe. The child is supposed
+ * to write to the writing end of the pipe after it completed its setup
+ * procedure successfully. This behaviour is useful to let the parent process
+ * die with an error if the child process aborts early, since in this case the
+ * read() will return non-positive.
+ *
+ * \return This function either succeeds or calls exit(3). If parent_waits is
+ * true, the return value is the file descriptor of the writing end of the
+ * pipe. Otherwise the function returns zero.
  *
  * \sa fork(2), setsid(2), dup(2), pause(2).
  */
-void daemonize(bool parent_waits)
+int daemonize(bool parent_waits)
 {
        pid_t pid;
-       int null;
+       int null, pipe_fd[2];
 
-       PARA_INFO_LOG("daemonizing\n");
+       if (parent_waits && pipe(pipe_fd) < 0)
+               goto err;
+       PARA_INFO_LOG("subsequent log messages go to %s\n", me->logfile_name?
+                me->logfile_name : "/dev/null");
        pid = fork();
        if (pid < 0)
                goto err;
-       if (pid) {
+       if (pid) { /* parent exits */
                if (parent_waits) {
-                       signal(SIGTERM, dummy_sighandler);
-                       signal(SIGCHLD, dummy_sighandler);
-                       pause();
+                       char c;
+                       close(pipe_fd[1]);
+                       exit(read(pipe_fd[0], &c, 1) <= 0?
+                               EXIT_FAILURE : EXIT_SUCCESS);
                }
-               exit(EXIT_SUCCESS); /* parent exits */
+               exit(EXIT_SUCCESS);
        }
+       if (parent_waits)
+               close(pipe_fd[0]);
        /* become session leader */
        if (setsid() < 0)
                goto err;
@@ -205,7 +213,7 @@ void daemonize(bool parent_waits)
        if (dup2(null, STDERR_FILENO) < 0)
                goto err;
        close(null);
-       return;
+       return parent_waits? pipe_fd[1] : 0;
 err:
        PARA_EMERG_LOG("fatal: %s\n", strerror(errno));
        exit(EXIT_FAILURE);
index c715360..989678d 100644 (file)
--- a/daemon.h
+++ b/daemon.h
@@ -1,7 +1,7 @@
 /** \file daemon.h exported symbols from daemon.c */
 
 
-void daemonize(bool parent_waits);
+int daemonize(bool parent_waits);
 void daemon_open_log_or_die(void);
 void daemon_close_log(void);
 void daemon_log_welcome(const char *whoami);
diff --git a/error.h b/error.h
index 337160c..ff85c8d 100644 (file)
--- a/error.h
+++ b/error.h
@@ -306,7 +306,6 @@ extern const char **para_errlist[];
        PARA_ERROR(SERVER_EOF, "connection closed by para_server"), \
        PARA_ERROR(SERVER_CMD_SUCCESS, "command terminated successfully"), \
        PARA_ERROR(SERVER_CMD_FAILURE, "command failed"), \
-       PARA_ERROR(INCOMPAT_FEAT, "client/server incompatibility"), \
 
 
 #define NET_ERRORS \
@@ -440,9 +439,10 @@ extern const char **para_errlist[];
 
 #define CRYPT_COMMON_ERRORS \
        PARA_ERROR(SSH_KEY_HEADER, "ssh key header not found"), \
-       PARA_ERROR(BASE64, "failed to base64-decode ssh public key"), \
        PARA_ERROR(KEY_PERM, "unprotected private key"), \
 
+#define BASE64_ERRORS \
+       PARA_ERROR(BASE64, "base64 decode error"), \
 
 #define CRYPT_ERRORS \
        PARA_ERROR(PRIVATE_KEY, "can not read private key"), \
index 3c6c1ad..289748e 100644 (file)
--- a/gcrypt.c
+++ b/gcrypt.c
@@ -15,6 +15,7 @@
 #include "crypt.h"
 #include "crypt_backend.h"
 #include "fd.h"
+#include "base64.h"
 
 //#define GCRYPT_DEBUG 1
 
@@ -239,12 +240,11 @@ static int decode_key(const char *key_file, const char *header_str,
                key[j++] = begin[i];
        }
        key[j] = '\0';
-       blob_size = key_size * 2;
-       blob = para_malloc(blob_size);
-       ret = base64_decode(key, blob, blob_size);
+       ret = base64_decode(key, j, (char **)&blob, &blob_size);
        free(key);
        if (ret < 0)
                goto free_unmap;
+       ret = blob_size;
        goto unmap;
 free_unmap:
        free(blob);
@@ -606,13 +606,9 @@ static int get_ssh_public_key(unsigned char *data, int size, gcry_sexp_t *result
        gcry_mpi_t e = NULL, n = NULL;
 
        PARA_DEBUG_LOG("decoding %d byte public rsa-ssh key\n", size);
-       if (size > INT_MAX / 4)
-               return -ERRNO_TO_PARA_ERROR(EOVERFLOW);
-       blob = para_malloc(2 * size);
-       ret = uudecode((char *)data, blob, 2 * size);
+       ret = uudecode((char *)data, size, (char **)&blob, &decoded_size);
        if (ret < 0)
                goto free_blob;
-       decoded_size = ret;
        end = blob + decoded_size;
        dump_buffer("decoded key", blob, decoded_size);
        ret = check_ssh_key_header(blob, decoded_size);
diff --git a/play.c b/play.c
index d2539ee..108db59 100644 (file)
--- a/play.c
+++ b/play.c
@@ -328,8 +328,7 @@ static int open_new_file(struct play_task *pt)
        pt->rn.receiver = afh_recv;
        ret = afh_recv->open(&pt->rn);
        if (ret < 0) {
-               PARA_ERROR_LOG("could not open %s: %s\n", path,
-                       para_strerror(-ret));
+               PARA_ERROR_LOG("could not open %s\n", path);
                goto fail;
        }
        pt->audio_format_num = ret;
@@ -388,6 +387,7 @@ static int load_file(struct play_task *pt)
        /* set up decoding filter */
        af = audio_format_name(pt->audio_format_num);
        tmp = make_message("%sdec", af);
+       PARA_INFO_LOG("decoder: %s\n", tmp);
        ret = check_filter_arg(tmp, &pt->fn.conf);
        freep(&tmp);
        if (ret < 0)
@@ -399,6 +399,8 @@ static int load_file(struct play_task *pt)
                        .handler = decoder->execute, .context = &pt->fn));
        if (decoder->open)
                decoder->open(&pt->fn);
+       PARA_INFO_LOG("buffer tree:\n");
+       btr_log_tree(pt->rn.btrn, LL_INFO);
 
        /* setup default writer */
        pt->wn.conf = check_writer_arg_or_die(NULL, &pt->wn.writer_num);
@@ -453,6 +455,8 @@ again:
                pt->next_file = pt->current_file;
        ret = load_file(pt);
        if (ret < 0) {
+               PARA_ERROR_LOG("%s: marking file as invalid\n",
+                       para_strerror(-ret));
                pt->invalid[pt->next_file] = true;
                pt->rq = CRT_NONE;
                goto again;
index f1a3892..4e10c2e 100644 (file)
@@ -4,7 +4,7 @@
  * Licensed under the GPL v2. For licencing details see COPYING.
  */
 
-/** \file portable_io.h Inline functions for endian-independent binary IO. */
+/** \file portable_io.h Inline functions for binary IO. */
 
 static inline uint64_t read_portable(unsigned bits, const char *buf)
 {
@@ -18,6 +18,18 @@ static inline uint64_t read_portable(unsigned bits, const char *buf)
        return ret;
 }
 
+static inline uint64_t read_portable_be(unsigned bits, const char *buf)
+{
+       uint64_t ret = 0;
+       int i, num_bytes = bits / 8;
+
+       for (i = 0; i < num_bytes; i++) {
+               unsigned char c = buf[i];
+               ret += ((uint64_t)c << (8 * (num_bytes - i - 1)));
+       }
+       return ret;
+}
+
 static inline uint64_t read_u64(const char *buf)
 {
        return read_portable(64, buf);
@@ -38,13 +50,35 @@ static inline uint8_t read_u8(const char *buf)
        return read_portable(8, buf);
 }
 
+static inline uint64_t read_u64_be(const char *buf)
+{
+       return read_portable_be(64, buf);
+}
+
+static inline uint32_t read_u32_be(const char *buf)
+{
+       return read_portable_be(32, buf);
+}
+
+static inline uint16_t read_u16_be(const char *buf)
+{
+       return read_portable_be(16, buf);
+}
+
 static inline void write_portable(unsigned bits, char *buf, uint64_t val)
 {
        int i, num_bytes = bits / 8;
-//     fprintf(stderr, "val: %lu\n", val);
        for (i = 0; i < num_bytes; i++) {
                buf[i] = val & 0xff;
-//             fprintf(stderr, "buf[%d]=%x\n", i, buf[i]);
+               val = val >> 8;
+       }
+}
+
+static inline void write_portable_be(unsigned bits, char *buf, uint64_t val)
+{
+       int i, num_bytes = bits / 8;
+       for (i = 0; i < num_bytes; i++) {
+               buf[num_bytes - i - 1] = val & 0xff;
                val = val >> 8;
        }
 }
@@ -68,3 +102,18 @@ static inline void write_u8(char *buf, uint8_t val)
 {
        write_portable(8, buf, (uint64_t) val);
 }
+
+static inline void write_u64_be(char *buf, uint64_t val)
+{
+       write_portable_be(64, buf, val);
+}
+
+static inline void write_u32_be(char *buf, uint32_t val)
+{
+       write_portable_be(32, buf, (uint64_t) val);
+}
+
+static inline void write_u16_be(char *buf, uint16_t val)
+{
+       write_portable_be(16, buf, (uint64_t) val);
+}
index 088cc8b..ca71c4d 100644 (file)
--- a/server.c
+++ b/server.c
@@ -411,8 +411,9 @@ static int init_afs(int argc, char **argv)
 {
        int ret, afs_server_socket[2];
        pid_t afs_pid;
+       char c;
 
-       ret = socketpair(PF_UNIX, SOCK_DGRAM, 0, afs_server_socket);
+       ret = socketpair(PF_UNIX, SOCK_STREAM, 0, afs_server_socket);
        if (ret < 0)
                exit(EXIT_FAILURE);
        get_random_bytes_or_die((unsigned char *)&afs_socket_cookie,
@@ -422,6 +423,7 @@ static int init_afs(int argc, char **argv)
                exit(EXIT_FAILURE);
        if (afs_pid == 0) { /* child (afs) */
                int i;
+
                for (i = argc - 1; i >= 0; i--)
                        memset(argv[i], 0, strlen(argv[i]));
                sprintf(argv[0], "para_server (afs)");
@@ -430,6 +432,10 @@ static int init_afs(int argc, char **argv)
        }
        mmd->afs_pid = afs_pid;
        close(afs_server_socket[1]);
+       if (read(afs_server_socket[0], &c, 1) <= 0) {
+               PARA_EMERG_LOG("early afs exit\n");
+               exit(EXIT_FAILURE);
+       }
        ret = mark_fd_nonblocking(afs_server_socket[0]);
        if (ret < 0)
                exit(EXIT_FAILURE);
@@ -457,7 +463,7 @@ static void server_init(int argc, char **argv)
                .check_ambiguity = 0,
                .print_errors = 1
        };
-       int afs_socket;
+       int afs_socket, daemon_pipe = -1;
 
        valid_fd_012();
        init_random_seed_or_die();
@@ -477,7 +483,7 @@ static void server_init(int argc, char **argv)
        init_user_list(user_list_file);
        /* become daemon */
        if (conf.daemon_given)
-               daemonize(true /* parent waits for SIGTERM */);
+               daemon_pipe = daemonize(true /* parent waits for us */);
        PARA_NOTICE_LOG("initializing audio format handlers\n");
        afh_init();
 
@@ -503,8 +509,13 @@ static void server_init(int argc, char **argv)
        PARA_NOTICE_LOG("initializing virtual streaming system\n");
        init_vss_task(afs_socket, &sched);
        init_server_command_task(argc, argv);
-       if (conf.daemon_given)
-               kill(getppid(), SIGTERM);
+       if (daemon_pipe >= 0) {
+               if (write(daemon_pipe, "\0", 1) < 0) {
+                       PARA_EMERG_LOG("daemon_pipe: %s", strerror(errno));
+                       exit(EXIT_FAILURE);
+               }
+               close(daemon_pipe);
+       }
        PARA_NOTICE_LOG("server init complete\n");
 }
 
index 99e575d..1f9913e 100644 (file)
@@ -156,7 +156,7 @@ test_require_executables()
 test_duration()
 {
        local t=$(exec 2>&1 1>/dev/null; time -p "$@")
-       result=$(awk '{print $2 * 1000}' <<< $t)
+       result=$(awk '{print $2 * 1000; exit 0}' <<< "$t")
 }
 
 test_expect_success()
index f292af2..b226943 100644 (file)
 <h2> Source code documentation </h2>
 
 <ul>
-
-       <li> <a href="doxygen/html/index.html">API
-       Reference</a>. </li>
-
-       <li> <a href="HTML/index.html">Browsable source</a>. </li>
-
+       <li> <a href="doxygen/html/index.html">API Reference</a> </li>
 </ul>
index dd0b9c7..a09fd1c 100644 (file)
@@ -19,7 +19,7 @@ provided at this point. There are several ways to download the source:
                check out any of the four integration branches maint,
                master, next, pu (see the
 
-               <a href="manual.html#git_branches">git_branches</a>
+               <a href="manual.html#Git.branches">Git branches</a>
 
                section of the manual). All previous releases
                correspond to tagged commits and may be checked out