Merge branch 'maint'
[paraslash.git] / audiod_command.c
index ce1aff6..07b2c81 100644 (file)
@@ -1,15 +1,13 @@
 /*
- * Copyright (C) 2005-2010 Andre Noll <maan@systemlinux.org>
+ * Copyright (C) 2005-2013 Andre Noll <maan@systemlinux.org>
  *
  * Licensed under the GPL v2. For licencing details see COPYING.
  */
 
-/** \file audiod_command.c commands for para_audiod */
+/** \file audiod_command.c Commands for para_audiod. */
 
 #include <regex.h>
 #include <sys/types.h>
-#include <dirent.h>
-#include <stdbool.h>
 
 #include "para.h"
 #include "audiod.cmdline.h"
 #include "fd.h"
 #include "audiod_command_list.h"
 
+extern struct sched sched;
 extern char *stat_item_values[NUM_STAT_ITEMS];
 
+
+static struct audiod_command audiod_cmds[] = {DEFINE_AUDIOD_CMD_ARRAY};
+
 /** Iterate over the array of all audiod commands. */
 #define FOR_EACH_COMMAND(c) for (c = 0; audiod_cmds[c].name; c++)
 
@@ -107,6 +109,31 @@ static int stat_client_add(int fd, uint64_t mask, int parser_friendly)
        num_clients++;
        return 1;
 }
+
+static void close_stat_client(struct stat_client *sc)
+{
+       PARA_INFO_LOG("closing client fd %d\n", sc->fd);
+       close(sc->fd);
+       list_del(&sc->node);
+       free(sc);
+       num_clients--;
+}
+
+/**
+ * Empty the status clients list.
+ *
+ * This iterates over the list of connected status clients, closes each client
+ * file descriptor and frees the resources.
+ */
+void close_stat_clients(void)
+{
+       struct stat_client *sc, *tmp;
+
+       list_for_each_entry_safe(sc, tmp, &client_list, node)
+               close_stat_client(sc);
+       assert(num_clients == 0);
+}
+
 /**
  * Write a message to all connected status clients.
  *
@@ -121,35 +148,27 @@ void stat_client_write_item(int item_num)
        struct para_buffer pb = {.flags = 0};
        struct para_buffer pfpb = {.flags = PBF_SIZE_PREFIX};
        const uint64_t one = 1;
+       char *msg = stat_item_values[item_num];
+       struct para_buffer *b;
 
        list_for_each_entry_safe(sc, tmp, &client_list, node) {
-               int fd = sc->fd, ret;
+               int ret;
 
                if (!((one << item_num) & sc->item_mask))
                        continue;
-               if (write_ok(fd) > 0) {
-                       struct para_buffer *b =
-                               (sc->flags & SCF_PARSER_FRIENDLY)? &pfpb : &pb;
-                       char *msg = stat_item_values[item_num];
-                       if (!b->buf)
-                               WRITE_STATUS_ITEM(b, item_num, "%s\n",
-                                       msg? msg : "");
-                       ret = write(fd, b->buf, b->offset);
-                       if (ret == b->offset)
-                               continue;
-               }
-               /* write error or fd not ready for writing */
-               close(fd);
-               num_clients--;
-               PARA_INFO_LOG("deleting client on fd %d\n", fd);
-               list_del(&sc->node);
-               free(sc);
+               b = (sc->flags & SCF_PARSER_FRIENDLY)? &pfpb : &pb;
+               if (!b->buf)
+                       (void)WRITE_STATUS_ITEM(b, item_num, "%s\n",
+                               msg? msg : "");
+               ret = write(sc->fd, b->buf, b->offset);
+               if (ret == b->offset)
+                       continue;
+               /* write error or short write */
+               close_stat_client(sc);
                dump_stat_client_list();
        }
        free(pb.buf);
        free(pfpb.buf);
-//     if (num_clients)
-//             PARA_DEBUG_LOG("%d client(s)\n", num_clients);
 }
 
 /**
@@ -199,7 +218,7 @@ static int get_play_time_slot_num(void)
        FOR_EACH_SLOT(i) {
                struct slot_info *s = &slot[i];
                struct timeval wstime;
-               if (!s->wns)
+               if (!s->wns || !s->wns[0].btrn)
                        continue;
                btr_get_node_start(s->wns[0].btrn, &wstime);
                if (oldest_slot >= 0 && tv_diff(&wstime, &oldest_wstime, NULL) > 0)
@@ -254,7 +273,7 @@ static int dump_commands(int fd)
  * to each individual command to close the fd if necessary.
  */
 
-int com_help(int fd, int argc, char **argv)
+static int com_help(int fd, int argc, char **argv)
 {
        int i, ret;
        char *buf;
@@ -289,9 +308,9 @@ out:
        return ret;
 }
 
-int com_tasks(int fd, __a_unused int argc, __a_unused char **argv)
+static int com_tasks(int fd, __a_unused int argc, __a_unused char **argv)
 {
-       char *tl = get_task_list();
+       char *tl = get_task_list(&sched);
        int ret = 1;
        if (tl)
                ret = client_write(fd, tl);
@@ -301,28 +320,16 @@ int com_tasks(int fd, __a_unused int argc, __a_unused char **argv)
        return ret;
 }
 
-int com_kill(int fd, int argc, char **argv)
-{
-       int i, ret = 1;
-       if (argc < 2)
-               return -E_AUDIOD_SYNTAX;
-       for (i = 1; i < argc; i++) {
-               ret = kill_task(argv[i]);
-               if (ret < 0)
-                       break;
-       }
-       if (ret > 0)
-               close(fd);
-       return ret;
-}
-
-int com_stat(int fd, int argc, char **argv)
+static int com_stat(int fd, int argc, char **argv)
 {
        int i, ret, parser_friendly = 0;
        uint64_t mask = 0;
        const uint64_t one = 1;
        struct para_buffer b = {.flags = 0};
 
+       ret = mark_fd_nonblocking(fd);
+       if (ret < 0)
+               return ret;
        for (i = 1; i < argc; i++) {
                const char *arg = argv[i];
                if (arg[0] != '-')
@@ -334,7 +341,6 @@ int com_stat(int fd, int argc, char **argv)
                if (!strncmp(arg, "-p", 2)) {
                        parser_friendly = 1;
                        b.flags = PBF_SIZE_PREFIX;
-                       continue;
                }
        }
        if (i >= argc)
@@ -350,7 +356,7 @@ int com_stat(int fd, int argc, char **argv)
                char *item = stat_item_values[i];
                if (!((one << i) & mask))
                        continue;
-               WRITE_STATUS_ITEM(&b, i, "%s\n", item? item : "");
+               (void)WRITE_STATUS_ITEM(&b, i, "%s\n", item? item : "");
        }
        ret = client_write(fd, b.buf);
        if (ret >= 0)
@@ -359,39 +365,39 @@ int com_stat(int fd, int argc, char **argv)
        return ret;
 }
 
-int com_grab(int fd, int argc, char **argv)
+static int com_grab(int fd, int argc, char **argv)
 {
-       return grab_client_new(fd, argc, argv);
+       return grab_client_new(fd, argc, argv, &sched);
 }
 
-__noreturn int com_term(int fd, __a_unused int argc, __a_unused char **argv)
+__noreturn static int com_term(int fd, __a_unused int argc, __a_unused char **argv)
 {
        close(fd);
        clean_exit(EXIT_SUCCESS, "terminating on user request");
 }
 
-int com_on(int fd, __a_unused int argc, __a_unused char **argv)
+static int com_on(int fd, __a_unused int argc, __a_unused char **argv)
 {
        audiod_status = AUDIOD_ON;
        close(fd);
        return 1;
 }
 
-int com_off(int fd, __a_unused int argc, __a_unused char **argv)
+static int com_off(int fd, __a_unused int argc, __a_unused char **argv)
 {
        audiod_status = AUDIOD_OFF;
        close(fd);
        return 1;
 }
 
-int com_sb(int fd, __a_unused int argc, __a_unused char **argv)
+static int com_sb(int fd, __a_unused int argc, __a_unused char **argv)
 {
        audiod_status = AUDIOD_STANDBY;
        close(fd);
        return 1;
 }
 
-int com_cycle(int fd, int argc, char **argv)
+static int com_cycle(int fd, int argc, char **argv)
 {
        switch (audiod_status) {
                case  AUDIOD_ON:
@@ -456,7 +462,7 @@ int handle_connect(int accept_fd, fd_set *rfds)
        if (ret < 0)
                goto out;
        ret = create_argv(buf, "\n", &argv);
-       if (ret < 0)
+       if (ret <= 0)
                goto out;
        argc = ret;
        //PARA_INFO_LOG("argv[0]: %s, argc = %d\n", argv[0], argc);
@@ -480,8 +486,10 @@ out:
 
 /**
  * Send the current audiod status to all connected stat clients.
+ *
+ * \param force Whether to write unchanged items.
  */
-void audiod_status_dump(void)
+void audiod_status_dump(bool force)
 {
        int slot_num = get_play_time_slot_num();
        char *old, *new;
@@ -489,7 +497,7 @@ void audiod_status_dump(void)
        old = stat_item_values[SI_PLAY_TIME];
        new = get_time_string(slot_num);
        if (new) {
-               if (!old || strcmp(old, new)) {
+               if (force || !old || strcmp(old, new)) {
                        free(old);
                        stat_item_values[SI_PLAY_TIME] = new;
                        stat_client_write_item(SI_PLAY_TIME);
@@ -497,9 +505,9 @@ void audiod_status_dump(void)
                        free(new);
        }
 
-       new = uptime_str();
+       new = get_server_uptime_str(now);
        old = stat_item_values[SI_AUDIOD_UPTIME];
-       if (!old || strcmp(old, new)) {
+       if (force || !old || strcmp(old, new)) {
                free(old);
                stat_item_values[SI_AUDIOD_UPTIME] = new;
                stat_client_write_item(SI_AUDIOD_UPTIME);
@@ -508,7 +516,7 @@ void audiod_status_dump(void)
 
        old = stat_item_values[SI_AUDIOD_STATUS];
        new = audiod_status_string();
-       if (!old || strcmp(old, new)) {
+       if (force || !old || strcmp(old, new)) {
                free(old);
                stat_item_values[SI_AUDIOD_STATUS] = new;
                stat_client_write_item(SI_AUDIOD_STATUS);
@@ -517,7 +525,7 @@ void audiod_status_dump(void)
 
        old = stat_item_values[SI_DECODER_FLAGS];
        new = decoder_flags();
-       if (!old || strcmp(old, new)) {
+       if (force || !old || strcmp(old, new)) {
                free(old);
                stat_item_values[SI_DECODER_FLAGS] = new;
                stat_client_write_item(SI_DECODER_FLAGS);