]> git.tuebingen.mpg.de Git - paraslash.git/commitdiff
Merge branch 'refs/heads/t/web-diet'
authorAndre Noll <maan@tuebingen.mpg.de>
Sun, 10 May 2015 18:27:35 +0000 (20:27 +0200)
committerAndre Noll <maan@tuebingen.mpg.de>
Sun, 10 May 2015 18:33:55 +0000 (20:33 +0200)
Was cooking in next for three weeks.

* web: Remove screenshots, license and credits page.
* web: Integrate Contact page into about.
* web: Make FEATURES the new homepage, rename it to "about".
* web: Shorten feature list

17 files changed:
NEWS
afs.c
afs.h
aft.c
audiod.c
audiod.h
audiod_command.c
command.c
daemon.c
error.h
m4/gengetopt/audiod.m4
m4/gengetopt/daemon.m4
server.h
t/t0004-server.sh
version.c
vss.c
web/manual.m4

diff --git a/NEWS b/NEWS
index c0ba3b28aad7e1c33258f4cc2cd7691d82df17ed..834b61fcb3b1906d88bccaae1eeea18c41fa1149 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -7,10 +7,19 @@ current master branch "magnetic momentum"
        - On Linux systems, local sockets are now created in the
          abstract name space by default. This allows to get rid of
          the socket specials in /var/paraslash.
+       - The --user-allow option of para_audiod now accepts also
+         usernames rather than only user IDs.
        - New autoconf macros to avoid duplication in configure.ac.
+       - Status items (as shown by para_gui) are updated correctly
+         when the meta information of the current audio changes.
+       - para_server and para_audiod no longer refuse to start in
+         the background if no log file is given. Instead, all log
+         messages go to /dev/null in this case.
+       - Web page cleanup.
 
 
 Download: ./releases/paraslash-git.tar.bz2 (tarball)
+
 ------------------------------------------
 0.5.4 (2015-01-23) "exponential alignment"
 ------------------------------------------
diff --git a/afs.c b/afs.c
index e73c668fb6d93b3a200eb841e4d4c34ce4b48e59..ea0a9f9f310d55f3e4fc56377a3583937e1bd92d 100644 (file)
--- a/afs.c
+++ b/afs.c
@@ -455,7 +455,7 @@ static int pass_afd(int fd, char *buf, size_t size)
 }
 
 /**
- * Open the audio file with highest score.
+ * Pass the fd of the next audio file to the server process.
  *
  * This stores all information for streaming the "best" audio file in a shared
  * memory area. The id of that area and an open file descriptor for the next
@@ -467,27 +467,15 @@ static int pass_afd(int fd, char *buf, size_t size)
  */
 static int open_next_audio_file(void)
 {
-       struct osl_row *aft_row;
        struct audio_file_data afd;
        int ret, shmid;
        char buf[8];
-       long score;
-again:
-       PARA_NOTICE_LOG("getting next audio file\n");
-       ret = score_get_best(&aft_row, &score);
+
+       ret = open_and_update_audio_file(&afd);
        if (ret < 0) {
                PARA_ERROR_LOG("%s\n", para_strerror(-ret));
                goto no_admissible_files;
        }
-       ret = open_and_update_audio_file(aft_row, score, &afd);
-       if (ret < 0) {
-               ret = score_delete(aft_row);
-               if (ret < 0) {
-                       PARA_ERROR_LOG("%s\n", para_strerror(-ret));
-                       goto no_admissible_files;
-               }
-               goto again;
-       }
        shmid = ret;
        if (!write_ok(server_socket)) {
                ret = -E_AFS_SOCKET;
@@ -1011,7 +999,13 @@ static void create_tables_callback(int fd, const struct osl_object *query)
 {
        uint32_t table_mask = *(uint32_t *)query->data;
        int i, ret;
-       struct para_buffer pb = {.buf = NULL};
+       struct para_buffer pb = {
+               .max_size = shm_get_shmmax(),
+               .private_data = &(struct afs_max_size_handler_data) {
+                       .fd = fd,
+                       .band = SBD_OUTPUT
+               }
+       };
 
        close_afs_tables();
        for (i = 0; i < NUM_AFS_TABLES; i++) {
diff --git a/afs.h b/afs.h
index 88b891c829d835efcef315ff8e5aa8fd1b725353..cccb143f5bdfa1e4aaa2cdcaa1d1e73e6780f119 100644 (file)
--- a/afs.h
+++ b/afs.h
@@ -245,8 +245,7 @@ int get_attribute_text(uint64_t *atts, const char *delim, char **text);
 /* aft */
 void aft_init(struct afs_table *t);
 int aft_get_row_of_path(const char *path, struct osl_row **row);
-int open_and_update_audio_file(struct osl_row *aft_row, long score,
-       struct audio_file_data *afd);
+int open_and_update_audio_file(struct audio_file_data *afd);
 int load_afd(int shmid, struct audio_file_data *afd);
 int get_afsi_of_row(const struct osl_row *row, struct afs_info *afsi);
 int get_afhi_of_row(const struct osl_row *row, struct afh_info *afhi);
diff --git a/aft.c b/aft.c
index ddb2244a550fa7ea1f1c5ddf327efe4fd3c58c05..acf751566c61d82e23cc34565c1189f2db147917 100644 (file)
--- a/aft.c
+++ b/aft.c
@@ -293,60 +293,36 @@ static struct osl_table_description audio_file_table_desc = {
        .column_descriptions = aft_cols
 };
 
-/* We don't want dot or dot-dot anywhere. */
-static int verify_dotfile(const char *rest)
-{
-       /*
-        * The first character was '.', but that has already been discarded, we
-        * now test the rest.
-        */
-       switch (*rest) {
-       case '\0': case '/': /* /foo/. and /foo/./bar are not ok */
-               return -1;
-       case '.': /* path start with /foo/.. */
-               if (rest[1] == '\0' || rest[1] == '/')
-                       return -1; /* /foo/.. or /foo/../bar are not ok */
-               /* /foo/..bar is ok */
-       }
-       return 1;
-}
-
 /*
- * We fundamentally don't like some paths: We don't want double slashes or
- * slashes at the end that can make pathnames ambiguous.
+ * Produce a canonicalized absolute pathname.
+ *
+ * Returns one if the resolved path a directory, zero if it is a regular file,
+ * negative on errors.
  */
 static int verify_path(const char *orig_path, char **resolved_path)
 {
-       char c;
-       size_t len;
-       char *path;
+       int ret;
+       char *path = NULL;
+       struct stat statbuf;
 
        if (*orig_path != '/') /* we only accept absolute paths */
-               return -E_BAD_PATH;
-       len = strlen(orig_path);
-       *resolved_path = para_strdup(orig_path);
-       path = *resolved_path;
-       while (len > 1 && path[--len] == '/')
-               path[len] = '\0'; /* remove slash at the end */
-       c = *path++;
-       while (c) {
-               if (c == '/') {
-                       c = *path++;
-                       switch (c) {
-                       case '/': /* double slash */
-                               goto bad_path;
-                       case '.':
-                               if (verify_dotfile(path) < 0)
-                                       goto bad_path;
-                       default:
-                               continue;
-                       }
-               }
-               c = *path++;
-       }
-       return 1;
-bad_path:
-       free(*resolved_path);
+               goto fail;
+       path = realpath(orig_path, NULL);
+       if (!path)
+               goto fail;
+       if (stat(path, &statbuf) < 0)
+               goto fail;
+       if (S_ISREG(statbuf.st_mode))
+               ret = 0;
+       else if (S_ISDIR(statbuf.st_mode))
+               ret = 1;
+       else
+               goto fail;
+       *resolved_path = path;
+       return ret;
+fail:
+       *resolved_path = NULL;
+       free(path);
        return -E_BAD_PATH;
 }
 
@@ -1037,17 +1013,33 @@ out:
        return ret;
 }
 
-static int make_status_items(struct audio_file_data *afd,
-               struct afs_info *afsi, char *path, long score,
-               unsigned char *hash)
+static struct ls_data status_item_ls_data;
+static struct osl_row *current_aft_row;
+
+static void make_inode_status_items(struct para_buffer *pb)
+{
+       struct stat statbuf = {.st_size = 0};
+       char *path, mtime_str[30] = "\0";
+       struct tm mtime_tm;
+       int ret;
+
+       ret = get_audio_file_path_of_row(current_aft_row, &path);
+       if (ret < 0)
+               goto out;
+       ret = stat(path, &statbuf);
+       if (ret < 0)
+               goto out;
+       localtime_r(&statbuf.st_mtime, &mtime_tm);
+       ret = strftime(mtime_str, 29, "%b %d %Y", &mtime_tm);
+       assert(ret > 0); /* number of bytes placed in mtime_str */
+out:
+       /* We don't care too much about errors here */
+       (void)WRITE_STATUS_ITEM(pb, SI_MTIME, "%s\n", mtime_str);
+       (void)WRITE_STATUS_ITEM(pb, SI_FILE_SIZE, "%ld\n", statbuf.st_size / 1024);
+}
+
+static int make_status_items(void)
 {
-       struct ls_data d = {
-               .afhi = afd->afhi,
-               .afsi = *afsi,
-               .path = path,
-               .score = score,
-               .hash = hash
-       };
        struct ls_options opts = {
                .flags = LS_FLAG_FULL_PATH | LS_FLAG_ADMISSIBLE_ONLY,
                .mode = LS_MODE_VERBOSE,
@@ -1057,30 +1049,30 @@ static int make_status_items(struct audio_file_data *afd,
        int ret;
 
        time(&current_time);
-       ret = print_list_item(&d, &opts, &pb, current_time);
+       ret = print_list_item(&status_item_ls_data, &opts, &pb, current_time);
        if (ret < 0)
                return ret;
+       make_inode_status_items(&pb);
        free(status_items);
        status_items = pb.buf;
        memset(&pb, 0, sizeof(pb));
        pb.max_size = shm_get_shmmax() - 1;
        pb.flags = PBF_SIZE_PREFIX;
-       ret = print_list_item(&d, &opts, &pb, current_time);
+       ret = print_list_item(&status_item_ls_data, &opts, &pb, current_time);
        if (ret < 0) {
                free(status_items);
                status_items = NULL;
                return ret;
        }
+       make_inode_status_items(&pb);
        free(parser_friendly_status_items);
        parser_friendly_status_items = pb.buf;
        return 1;
 }
 
 /**
- * Mmap the given audio file and update statistics.
+ * Open the audio file with highest score and set up an afd structure.
  *
- * \param aft_row Determines the audio file to be opened and updated.
- * \param score The score of the audio file.
  * \param afd Result pointer.
  *
  * On success, the numplayed field of the audio file selector info is increased
@@ -1089,66 +1081,75 @@ static int make_status_items(struct audio_file_data *afd,
  *
  * \return Positive shmid on success, negative on errors.
  */
-int open_and_update_audio_file(struct osl_row *aft_row, long score,
-       struct audio_file_data *afd)
+int open_and_update_audio_file(struct audio_file_data *afd)
 {
-       unsigned char *aft_hash, file_hash[HASH_SIZE];
+       unsigned char file_hash[HASH_SIZE];
        struct osl_object afsi_obj;
-       struct afs_info old_afsi, new_afsi;
-       int ret = get_hash_of_row(aft_row, &aft_hash);
+       struct afs_info new_afsi;
+       int ret;
        struct afsi_change_event_data aced;
        struct osl_object map, chunk_table_obj;
-       char *path;
-
+       struct ls_data *d = &status_item_ls_data;
+again:
+       ret = score_get_best(&current_aft_row, &d->score);
        if (ret < 0)
                return ret;
-       ret = get_audio_file_path_of_row(aft_row, &path);
+       ret = get_hash_of_row(current_aft_row, &d->hash);
        if (ret < 0)
                return ret;
-       PARA_NOTICE_LOG("%s\n", path);
-       ret = get_afsi_object_of_row(aft_row, &afsi_obj);
+       ret = get_audio_file_path_of_row(current_aft_row, &d->path);
        if (ret < 0)
                return ret;
-       ret = load_afsi(&old_afsi, &afsi_obj);
+       PARA_NOTICE_LOG("%s\n", d->path);
+       ret = get_afsi_object_of_row(current_aft_row, &afsi_obj);
        if (ret < 0)
                return ret;
-       ret = get_afhi_of_row(aft_row, &afd->afhi);
+       ret = load_afsi(&d->afsi, &afsi_obj);
        if (ret < 0)
                return ret;
-       afd->afhi.chunk_table = NULL;
-       ret = osl(osl_open_disk_object(audio_file_table, aft_row,
+       ret = get_afhi_of_row(current_aft_row, &afd->afhi);
+       if (ret < 0)
+               return ret;
+       d->afhi = afd->afhi;
+       d->afhi.chunk_table = afd->afhi.chunk_table = NULL;
+       ret = osl(osl_open_disk_object(audio_file_table, current_aft_row,
                AFTCOL_CHUNKS, &chunk_table_obj));
        if (ret < 0)
                return ret;
-       ret = mmap_full_file(path, O_RDONLY, &map.data, &map.size, &afd->fd);
+       ret = mmap_full_file(d->path, O_RDONLY, &map.data, &map.size, &afd->fd);
        if (ret < 0)
                goto out;
        hash_function(map.data, map.size, file_hash);
-       ret = hash_compare(file_hash, aft_hash);
+       ret = hash_compare(file_hash, d->hash);
        para_munmap(map.data, map.size);
        if (ret) {
                ret = -E_HASH_MISMATCH;
                goto out;
        }
-       new_afsi = old_afsi;
+       new_afsi = d->afsi;
        new_afsi.num_played++;
        new_afsi.last_played = time(NULL);
        save_afsi(&new_afsi, &afsi_obj); /* in-place update */
 
-       afd->audio_format_id = old_afsi.audio_format_id;
+       afd->audio_format_id = d->afsi.audio_format_id;
        load_chunk_table(&afd->afhi, chunk_table_obj.data);
-       ret = make_status_items(afd, &old_afsi, path, score, file_hash);
-       if (ret < 0)
-               goto out;
-       aced.aft_row = aft_row;
-       aced.old_afsi = &old_afsi;
+       aced.aft_row = current_aft_row;
+       aced.old_afsi = &d->afsi;
+       /*
+        * No need to update the status items as the AFSI_CHANGE event will
+        * recreate them.
+        */
        afs_event(AFSI_CHANGE, NULL, &aced);
        ret = save_afd(afd);
 out:
        free(afd->afhi.chunk_table);
        osl_close_disk_object(&chunk_table_obj);
-       if (ret < 0)
-               PARA_ERROR_LOG("%s: %s\n", path, para_strerror(-ret));
+       if (ret < 0) {
+               PARA_ERROR_LOG("%s: %s\n", d->path, para_strerror(-ret));
+               ret = score_delete(current_aft_row);
+               if (ret >= 0)
+                       goto again;
+       }
        return ret;
 }
 
@@ -1953,7 +1954,6 @@ int com_add(struct command_context *cc)
 {
        int i, ret;
        struct private_add_data pad = {.cc = cc, .flags = 0};
-       struct stat statbuf;
 
        for (i = 1; i < cc->argc; i++) {
                const char *arg = cc->argv[i];
@@ -1992,20 +1992,10 @@ int com_add(struct command_context *cc)
                                return ret;
                        continue;
                }
-               ret = stat(path, &statbuf);
-               if (ret < 0) {
-                       ret = send_sb_va(&cc->scc, SBD_ERROR_LOG,
-                               "failed to stat %s (%s)\n", path,
-                               strerror(errno));
-                       free(path);
-                       if (ret < 0)
-                               return ret;
-                       continue;
-               }
-               if (S_ISDIR(statbuf.st_mode))
+               if (ret == 1) /* directory */
                        ret = for_each_file_in_dir(path, add_one_audio_file,
                                &pad);
-               else
+               else /* regular file */
                        ret = add_one_audio_file(path, &pad);
                if (ret < 0) {
                        send_sb_va(&cc->scc, SBD_OUTPUT, "%s: %s\n", path,
@@ -2110,7 +2100,10 @@ static void com_touch_callback(int fd, const struct osl_object *query)
        struct touch_action_data tad = {.cto = query->data,
                .pb = {
                        .max_size = shm_get_shmmax(),
-                       .private_data = &fd,
+                       .private_data = &(struct afs_max_size_handler_data) {
+                               .fd = fd,
+                               .band = SBD_OUTPUT
+                       },
                        .max_size_handler = afs_max_size_handler
                }
        };
@@ -2251,7 +2244,10 @@ static void com_rm_callback(int fd, const struct osl_object *query)
        struct com_rm_action_data crd = {.flags = *(uint32_t *)query->data,
                .pb = {
                        .max_size = shm_get_shmmax(),
-                       .private_data = &fd,
+                       .private_data = &(struct afs_max_size_handler_data) {
+                               .fd = fd,
+                               .band = SBD_OUTPUT
+                       },
                        .max_size_handler = afs_max_size_handler
                }
        };
@@ -2393,7 +2389,10 @@ static void com_cpsi_callback(int fd, const struct osl_object *query)
                .flags = *(unsigned *)query->data,
                .pb = {
                        .max_size = shm_get_shmmax(),
-                       .private_data = &fd,
+                       .private_data = &(struct afs_max_size_handler_data) {
+                               .fd = fd,
+                               .band = SBD_OUTPUT
+                       },
                        .max_size_handler = afs_max_size_handler
                }
        };
@@ -2764,9 +2763,27 @@ static int aft_event_handler(enum afs_events event, struct para_buffer *pb,
                if (ret < 0)
                        return ret;
                return audio_file_loop(data, clear_attribute);
-               }
-       default:
+       } case AFSI_CHANGE: {
+               struct afsi_change_event_data *aced = data;
+               uint64_t old_last_played = status_item_ls_data.afsi.last_played;
+               if (aced->aft_row != current_aft_row)
+                       return 0;
+               ret = get_afsi_of_row(aced->aft_row, &status_item_ls_data.afsi);
+               if (ret < 0)
+                       return ret;
+               status_item_ls_data.afsi.last_played = old_last_played;
+               make_status_items();
                return 1;
+       } case AFHI_CHANGE: {
+               if (data != current_aft_row)
+                       return 0;
+               ret = get_afhi_of_row(data, &status_item_ls_data.afhi);
+               if (ret < 0)
+                       return ret;
+               make_status_items();
+               return 1;
+       } default:
+               return 0;
        }
 }
 
index 1f226265b0c9c79593f255bba4805cfdb8a53e9a..40443a612569988e00ade13c8f384a7090d133e3 100644 (file)
--- a/audiod.c
+++ b/audiod.c
@@ -14,6 +14,7 @@
 #include <sys/un.h>
 #include <netdb.h>
 #include <signal.h>
+#include <pwd.h>
 
 #include "para.h"
 #include "error.h"
@@ -172,6 +173,8 @@ static struct signal_task *signal_task;
 
 static struct status_task status_task_struct;
 
+static uid_t *uid_whitelist;
+
 /**
  * the task that calls the status command of para_server
  *
@@ -390,7 +393,7 @@ empty:
 
 static void parse_config_or_die(void)
 {
-       int ret;
+       int ret, i;
        char *config_file;
        struct audiod_cmdline_parser_params params = {
                .override = 0,
@@ -410,6 +413,7 @@ static void parse_config_or_die(void)
        ret = file_exists(config_file);
        if (conf.config_file_given && !ret) {
                PARA_EMERG_LOG("can not read config file %s\n", config_file);
+               free(config_file);
                goto err;
        }
        if (ret) {
@@ -417,9 +421,29 @@ static void parse_config_or_die(void)
                daemon_set_loglevel(conf.loglevel_arg);
        }
        free(config_file);
+       if (conf.user_allow_given > 0) {
+               uid_whitelist = para_malloc(conf.user_allow_given
+                       * sizeof(uid_t));
+               for (i = 0; i < conf.user_allow_given; i++) {
+                       int32_t val;
+                       struct passwd *pw;
+                       ret = para_atoi32(conf.user_allow_arg[i], &val);
+                       if (ret >= 0) {
+                               uid_whitelist[i] = val;
+                               continue;
+                       }
+                       errno = 0; /* see getpwnam(3) */
+                       pw = getpwnam(conf.user_allow_arg[i]);
+                       if (!pw) {
+                               PARA_EMERG_LOG("invalid username: %s\n",
+                                       conf.user_allow_arg[i]);
+                               goto err;
+                       }
+                       uid_whitelist[i] = pw->pw_uid;
+               }
+       }
        return;
 err:
-       free(config_file);
        exit(EXIT_FAILURE);
 }
 
@@ -1099,7 +1123,7 @@ static int command_post_select(struct sched *s, void *context)
        for (i = 0; i < 2; i++) {
                if (ct->fd[i] < 0)
                        continue;
-               ret = handle_connect(ct->fd[i], &s->rfds);
+               ret = handle_connect(ct->fd[i], &s->rfds, uid_whitelist);
                if (ret < 0) {
                        PARA_ERROR_LOG("%s\n", para_strerror(-ret));
                        if (ret == -E_AUDIOD_TERM) {
@@ -1226,6 +1250,7 @@ static void audiod_cleanup(void)
        close_unused_slots();
        audiod_cmdline_parser_free(&conf);
        close_stat_clients();
+       free(uid_whitelist);
 }
 
 /*
index 94288eec702dd016dbebcaa2f5bf68a882aab1e7..3b4b9bd0416720e5e7d9455df23221cb049a2fc8 100644 (file)
--- a/audiod.h
+++ b/audiod.h
@@ -40,7 +40,7 @@ __malloc char *audiod_get_decoder_flags(void);
 extern struct audiod_args_info conf;
 extern int audiod_status;
 
-int handle_connect(int accept_fd, fd_set *rfds);
+int handle_connect(int accept_fd, fd_set *rfds, uid_t *uid_whitelist);
 void audiod_status_dump(bool force);
 char *get_time_string(void);
 struct btr_node *audiod_get_btr_root(void);
index b847e5aa264fa4ccb9e8c9aafcfcb61713ae2131..98dba3b32dfcaee1a7532d8e3021947102d98f89 100644 (file)
@@ -396,14 +396,14 @@ static int com_version(int fd, int argc, char **argv)
        return ret;
 }
 
-static int check_perms(uid_t uid)
+static int check_perms(uid_t uid, uid_t *whitelist)
 {
        int i;
 
        if (!conf.user_allow_given)
                return 1;
        for (i = 0; i < conf.user_allow_given; i++)
-               if (uid == conf.user_allow_arg[i])
+               if (uid == whitelist[i])
                        return 1;
        return -E_UCRED_PERM;
 }
@@ -413,6 +413,7 @@ static int check_perms(uid_t uid)
  *
  * \param accept_fd The fd to accept connections on.
  * \param rfds If \a accept_fd is not set in \a rfds, do nothing.
+ * \param uid_whitelist Array of UIDs which are allowed to connect.
  *
  * This is called in each iteration of the select loop. If there is an incoming
  * connection on \a accept_fd, this function reads the command sent by the peer,
@@ -425,7 +426,7 @@ static int check_perms(uid_t uid)
  *
  * \sa para_accept(), recv_cred_buffer()
  * */
-int handle_connect(int accept_fd, fd_set *rfds)
+int handle_connect(int accept_fd, fd_set *rfds, uid_t *uid_whitelist)
 {
        int i, argc, ret, clifd;
        char buf[MAXLINE], **argv = NULL;
@@ -440,7 +441,7 @@ int handle_connect(int accept_fd, fd_set *rfds)
                goto out;
        uid = ret;
        PARA_INFO_LOG("connection from user %i, buf: %s\n",  ret, buf);
-       ret = check_perms(uid);
+       ret = check_perms(uid, uid_whitelist);
        if (ret < 0)
                goto out;
        ret = create_argv(buf, "\n", &argv);
index cb5cce16103f891e709dccce1dc39262d5ec0f84..175b496ca799820bc5d891676f71970d31ba7cc9 100644 (file)
--- a/command.c
+++ b/command.c
@@ -112,21 +112,15 @@ static char *vss_get_status_flags(unsigned int flags)
 static unsigned get_status(struct misc_meta_data *nmmd, int parser_friendly,
                char **result)
 {
-       char mtime[30] = "";
        char *status, *flags; /* vss status info */
        /* nobody updates our version of "now" */
        long offset = (nmmd->offset + 500) / 1000;
        struct timeval current_time;
-       struct tm mtime_tm;
        struct para_buffer b = {.flags = parser_friendly? PBF_SIZE_PREFIX : 0};
 
        /* report real status */
        status = vss_status_tohuman(nmmd->vss_status_flags);
        flags = vss_get_status_flags(nmmd->vss_status_flags);
-       if (nmmd->size) { /* parent currently has an audio file open */
-               localtime_r(&nmmd->mtime, &mtime_tm);
-               strftime(mtime, 29, "%b %d %Y", &mtime_tm);
-       }
        clock_get_realtime(&current_time);
        /*
         * The calls to WRITE_STATUS_ITEM() below never fail because
@@ -134,8 +128,6 @@ static unsigned get_status(struct misc_meta_data *nmmd, int parser_friendly,
         * is not smart enough to prove this and complains nevertheless.
         * Casting the return value to void silences clang.
         */
-       (void)WRITE_STATUS_ITEM(&b, SI_FILE_SIZE, "%zu\n", nmmd->size / 1024);
-       (void)WRITE_STATUS_ITEM(&b, SI_MTIME, "%s\n", mtime);
        (void)WRITE_STATUS_ITEM(&b, SI_STATUS, "%s\n", status);
        (void)WRITE_STATUS_ITEM(&b, SI_STATUS_FLAGS, "%s\n", flags);
        (void)WRITE_STATUS_ITEM(&b, SI_OFFSET, "%li\n", offset);
index 316432e68a5f116c9f2035d9bfb661b99b7061a1..ca74595695985ad866c6ad849cbc343e2801850a 100644 (file)
--- a/daemon.c
+++ b/daemon.c
@@ -199,7 +199,7 @@ void daemonize(bool parent_waits)
                goto err;
        if (chdir("/") < 0)
                goto err;
-       null = open("/dev/null", O_RDONLY);
+       null = open("/dev/null", O_RDWR);
        if (null < 0)
                goto err;
        if (dup2(null, STDIN_FILENO) < 0)
diff --git a/error.h b/error.h
index 31426b04839e829a7594f6127cf48ec0603a56ac..28ac9552315689124f2bfa1de0e50f874d2e9e61 100644 (file)
--- a/error.h
+++ b/error.h
@@ -266,7 +266,7 @@ extern const char **para_errlist[];
 
 
 #define AFT_ERRORS \
-       PARA_ERROR(BAD_AFSI, "invaiid afs info"), \
+       PARA_ERROR(BAD_AFSI, "invalid afs info"), \
        PARA_ERROR(LOCALTIME, "localtime() failed"), \
        PARA_ERROR(STRFTIME, "strftime() failed"), \
        PARA_ERROR(BAD_PATH, "invalid path"), \
index 2e6f936f3a94d058ee35d24afd59ca9966f958cf..732f80873cdf39529e61f158a4d6cc40c2ae0735 100644 (file)
@@ -82,20 +82,21 @@ details="
 
 option "user-allow" -
 #~~~~~~~~~~~~~~~~~~~~
-"allow this uid"
-int typestr="uid"
-default="-1"
+"allow this user to connect to audiod"
+string typestr = "username"
 optional
 multiple
-details="
-       Allow the user identified by \"uid\" to connect to para_audiod.
-       May be specified multiple times. If not specified at all,
-       all users are allowed to connect.
-
-       This feature requires unix socket credentials and is currently
-       only supported on Linux systems. On other operating systems,
-       the option is silently ignored and all local users are allowed
-       to connect to para_audiod.
+details = "
+       Allow the user identified by username (either a string or
+       a UID) to connect to para_audiod. This option may be given
+       multiple times. If not specified at all, all users are allowed
+       to connect.
+
+       This feature is based on the ability to send unix
+       credentials through local sockets using ancillary data
+       (SCM_CREDENTIALS). Currently it only works on Linux. On
+       other operating systems the option is silently ignored and
+       all local users are allowed to connect.
 "
 
 option "clock-diff-count" -
index b4e842ac049f4832e21e96a24658fab162f22a83..ebead6a806f372d63e0e5aaf2f4b4a1aba00f479 100644 (file)
@@ -3,9 +3,8 @@ option "daemon" d
 #~~~~~~~~~~~~~~~~
 "run as background daemon"
 flag off
-dependon="logfile"
-details="
-       Note that </qu>CURRENT_PROGRAM<qu> refuses to start in daemon mode if no
-       logfile was specified.
+details = "
+       If this option is given and no logfile was specified, all
+       messages go to /dev/null.
 "
 </qu>
index baefceee01b09ba8fbcc19f4f4eedce28d194267..93fd558cd7636db5ee0fe6c3ded7a053ab9d3a2e 100644 (file)
--- a/server.h
+++ b/server.h
@@ -52,8 +52,6 @@ struct sender_command_data {
 struct misc_meta_data {
        /** The size of the current audio file in bytes. */
        size_t size;
-       /** The last modification time of the current audio file. */
-       time_t mtime;
        /** The "old" status flags -- commands may only read them. */
        unsigned int vss_status_flags;
        /** The new status flags -- commands may set them. */
index 04d6cd609a33a9886130d31efff86f4af509ab6f..a14a04e9d05bbf33034b8630e05141aa9632a33d 100755 (executable)
@@ -21,7 +21,8 @@ pubkey=$privkey.pub
 serverlog=server.log
 
 get_audio_file_paths ogg
-oggs="$result"
+declare -a oggs=($result)
+declare -a oggs_base=(${oggs[@]##*/})
 
 declare -a commands=() cmdline=() required_objects=() good=() bad=()
 i=0
@@ -38,14 +39,14 @@ bad[$i]='!^successfully'
 let i++
 commands[$i]="add_ogg"
 required_objects[$i]='ogg_afh'
-cmdline[$i]="add $oggs"
+cmdline[$i]="add ${oggs[@]}"
 bad[$i]='.'
 
 let i++
 commands[$i]="ls_ogg"
 required_objects[$i]='ogg_afh'
-cmdline[$i]="ls -lv -p $oggs"
-good[$i]='^path:'
+cmdline[$i]="ls -lv ${oggs_base[@]}"
+good[$i]='^basename:'
 
 let i++
 commands[$i]="term"
index c9a329c3d9039831ccc4be56fa37d7e375d3dd94..695675613398c1ae52867bbd3a04c27bc81145db 100644 (file)
--- a/version.c
+++ b/version.c
@@ -43,7 +43,7 @@ const char *version_text(const char *pfx)
        static char buf[512];
 
        snprintf(buf, sizeof(buf) - 1, "%s\n"
-               "Copyright (C) 2014 Andre Noll\n"
+               "Copyright (C) 2002-2015 Andre Noll\n"
                "This is free software with ABSOLUTELY NO WARRANTY."
                " See COPYING for details.\n"
                "Report bugs to <maan@tuebingen.mpg.de>.\n"
diff --git a/vss.c b/vss.c
index fc42ba68662a00df0923ceb963c47e4ece5b1686..ea075df923a9e7b551ffc5cb220fb5bfe8a6e7c5 100644 (file)
--- a/vss.c
+++ b/vss.c
@@ -855,7 +855,6 @@ static void vss_eof(struct vss_task *vsst)
        mmd->afd.afhi.chunk_tv.tv_usec = 0;
        free(mmd->afd.afhi.chunk_table);
        mmd->afd.afhi.chunk_table = NULL;
-       mmd->mtime = 0;
        mmd->size = 0;
        mmd->events++;
 }
@@ -1011,7 +1010,6 @@ static void recv_afs_result(struct vss_task *vsst, fd_set *rfds)
                goto err;
        }
        mmd->size = statbuf.st_size;
-       mmd->mtime = statbuf.st_mtime;
        ret = para_mmap(mmd->size, PROT_READ, MAP_PRIVATE | MAP_POPULATE,
                passed_fd, 0, &vsst->map);
        if (ret < 0)
index b7e059785b193ccb67a1c47d34a6d60143b23229..d0fe28e0ac6fed4e67db6dd0d0cef8a6784e7940 100644 (file)
@@ -1289,10 +1289,10 @@ to the database, so they need to transfer data the other way round,
 from the client to the server.
 
 There is no knowledge about the server commands built into para_client,
-so it does not know about addblob commands. Instead, it inspects the
-first data package sent by the server for a magic string. If this
-string was found, it sends STDIN to the server, otherwise it dumps
-data from the server to STDOUT.
+so it does not know about addblob commands. Instead, the server sends
+a special "awaiting data" packet for these commands. If the client
+receives this packet, it sends STDIN to the server, otherwise it
+dumps data from the server to STDOUT.
 
 Streaming protocols
 ~~~~~~~~~~~~~~~~~~~
@@ -1551,7 +1551,7 @@ can be directly sent to the sound device or any other software that
 operates on undecoded PCM data (visualizers, equalizers etc.). Such
 filters are called _decoders_ in general, and xxxdec is the name of
 the paraslash decoder for the audio format xxx. For example, the mp3
-decoder filter is called mp3dec.
+decoder is called mp3dec.
 
 Note that the output of the decoder is about 10 times larger than
 its input. This means that filters that operate on the decoded audio
@@ -1560,8 +1560,7 @@ the audio stream before it is fed to the decoder.
 
 Paraslash relies on external libraries for most decoders, so these
 libraries must be installed for the decoder to be included in the
-para_filter and para_audiod executables. The oggdec filter depends
-on the libogg and libvorbis libraries for example.
+executables. For example, the mp3dec filter depends on the mad library.
 
 Forward error correction
 ~~~~~~~~~~~~~~~~~~~~~~~~