Obtain afs status items directly from afs.
[paraslash.git] / afs.c
diff --git a/afs.c b/afs.c
index 64d3b0f82fb9005b9e526d7ff3265640d3777114..6cbc744d71c2c65fea67968ff8f37fd40d530c1f 100644 (file)
--- a/afs.c
+++ b/afs.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2007-2008 Andre Noll <maan@systemlinux.org>
+ * Copyright (C) 2007-2009 Andre Noll <maan@systemlinux.org>
  *
  * Licensed under the GPL v2. For licencing details see COPYING.
  */
@@ -8,6 +8,7 @@
 
 #include <signal.h>
 #include <fnmatch.h>
+#include <osl.h>
 #include "server.cmdline.h"
 #include "para.h"
 #include "error.h"
@@ -85,7 +86,6 @@ static struct signal_task signal_task_struct;
 static enum play_mode current_play_mode;
 static char *current_mop; /* mode or playlist specifier. NULL means dummy mooe */
 
-
 /**
  * A random number used to "authenticate" the connection.
  *
@@ -141,6 +141,36 @@ struct callback_result {
        size_t result_size;
 };
 
+static int dispatch_result(int result_shmid, callback_result_handler *handler,
+               void *private_result_data)
+{
+       struct osl_object result;
+       void *result_shm;
+       int ret2, ret = shm_attach(result_shmid, ATTACH_RO, &result_shm);
+       struct callback_result *cr = result_shm;
+
+       if (ret < 0) {
+               PARA_ERROR_LOG("attach failed: %s\n", para_strerror(-ret));
+               return ret;
+       }
+       result.size = cr->result_size;
+       result.data = result_shm + sizeof(*cr);
+       if (result.size) {
+               assert(handler);
+               ret = handler(&result, private_result_data);
+               if (ret < 0)
+                       PARA_NOTICE_LOG("result handler error: %s\n",
+                               para_strerror(-ret));
+       }
+       ret2 = shm_detach(result_shm);
+       if (ret2 < 0) {
+               PARA_ERROR_LOG("detach failed: %s\n", para_strerror(-ret2));
+               if (ret >= 0)
+                       ret = ret2;
+       }
+       return ret;
+}
+
 /**
  * Ask the afs process to call a given function.
  *
@@ -161,8 +191,7 @@ struct callback_result {
  * shmid are passed to that function as an osl object. The private_result_data
  * pointer is passed as the second argument to \a result_handler.
  *
- * \return Negative, on errors, the return value of the callback function
- * otherwise.
+ * \return Standard.
  *
  * \sa send_option_arg_callback_request(), send_standard_callback_request().
  */
@@ -171,10 +200,11 @@ int send_callback_request(callback_function *f, struct osl_object *query,
                void *private_result_data)
 {
        struct callback_query *cq;
-       int num_results = 0, ret, fd = -1, query_shmid, result_shmid;
-       void *query_shm, *result_shm;
+       int ret, fd = -1, query_shmid, result_shmid;
+       void *query_shm;
        char buf[sizeof(afs_socket_cookie) + sizeof(int)];
        size_t query_shm_size = sizeof(*cq);
+       int dispatch_error = 0;
 
        if (query)
                query_shm_size += query->size;
@@ -205,45 +235,37 @@ int send_callback_request(callback_function *f, struct osl_object *query,
        ret = send_bin_buffer(fd, buf, sizeof(buf));
        if (ret < 0)
                goto out;
+       /*
+        * Read all shmids from afs.
+        *
+        * Even if the dispatcher returns an error we _must_ continue to read
+        * shmids from fd so that we can destroy all shared memory areas that
+        * have been created for us by the afs process.
+        */
        for (;;) {
                ret = recv_bin_buffer(fd, buf, sizeof(int));
                if (ret <= 0)
                        goto out;
-               if (ret != sizeof(int)) {
-                       ret = -E_AFS_SHORT_READ;
-                       goto out;
-               }
+               assert(ret == sizeof(int));
                ret = *(int *) buf;
-               if (ret <= 0)
-                       goto out;
+               assert(ret > 0);
                result_shmid = ret;
-               ret = shm_attach(result_shmid, ATTACH_RO, &result_shm);
-               if (ret >= 0) {
-                       struct callback_result *cr = result_shm;
-                       struct osl_object result;
-                       num_results++;
-                       result.size = cr->result_size;
-                       result.data = result_shm + sizeof(*cr);
-                       if (result.size) {
-                               assert(result_handler);
-                               ret = result_handler(&result, private_result_data);
-                               if (shm_detach(result_shm) < 0)
-                                       PARA_ERROR_LOG("can not detach result\n");
-                       }
-               } else
-                       PARA_ERROR_LOG("attach result failed: %d\n", ret);
-               if (shm_destroy(result_shmid) < 0)
-                       PARA_ERROR_LOG("destroy result failed\n");
+               if (!dispatch_error) {
+                       ret = dispatch_result(result_shmid, result_handler,
+                               private_result_data);
+                       if (ret < 0)
+                               dispatch_error = 1;
+               }
+               ret = shm_destroy(result_shmid);
                if (ret < 0)
-                       break;
+                       PARA_CRIT_LOG("destroy result failed: %s\n",
+                               para_strerror(-ret));
        }
 out:
        if (shm_destroy(query_shmid) < 0)
-               PARA_ERROR_LOG("%s\n", "shm destroy error");
+               PARA_CRIT_LOG("shm destroy error\n");
        if (fd >= 0)
                close(fd);
-       if (ret >= 0)
-               ret = num_results;
 //     PARA_DEBUG_LOG("callback_ret: %d\n", ret);
        return ret;
 }
@@ -320,7 +342,7 @@ static int action_if_pattern_matches(struct osl_row *row, void *data)
        struct pattern_match_data *pmd = data;
        struct osl_object name_obj;
        const char *p, *name;
-       int ret = osl_get_object(pmd->table, row, pmd->match_col_num, &name_obj);
+       int ret = osl(osl_get_object(pmd->table, row, pmd->match_col_num, &name_obj));
        const char *pattern_txt = (const char *)pmd->patterns.data;
 
        if (ret < 0)
@@ -347,16 +369,15 @@ static int action_if_pattern_matches(struct osl_row *row, void *data)
  *
  * \param pmd Describes what to match and how.
  *
- * \return The return value of the underlying call to osl_rbtree_loop()
- * or osl_rbtree_loop_reverse().
+ * \return Standard.
  */
 int for_each_matching_row(struct pattern_match_data *pmd)
 {
        if (pmd->pm_flags & PM_REVERSE_LOOP)
-               return osl_rbtree_loop_reverse(pmd->table, pmd->loop_col_num, pmd,
-                       action_if_pattern_matches);
-       return osl_rbtree_loop(pmd->table, pmd->loop_col_num, pmd,
-                       action_if_pattern_matches);
+               return osl(osl_rbtree_loop_reverse(pmd->table, pmd->loop_col_num, pmd,
+                       action_if_pattern_matches));
+       return osl(osl_rbtree_loop(pmd->table, pmd->loop_col_num, pmd,
+                       action_if_pattern_matches));
 }
 
 /**
@@ -708,7 +729,7 @@ static void get_database_dir(void)
                else {
                        char *home = para_homedir();
                        database_dir = make_message(
-                               "%s/.paraslash/afs_database", home);
+                               "%s/.paraslash/afs_database-0.4", home);
                        free(home);
                }
        }
@@ -754,7 +775,7 @@ static void signal_pre_select(struct sched *s, struct task *t)
        para_fd_set(st->fd, &s->rfds, &s->max_fileno);
 }
 
-static void signal_post_select(struct sched *s, struct task *t)
+static void afs_signal_post_select(struct sched *s, struct task *t)
 {
        struct signal_task *st = container_of(t, struct signal_task, task);
        if (getppid() == 1) {
@@ -766,6 +787,7 @@ static void signal_post_select(struct sched *s, struct task *t)
        st->signum = para_next_signal();
        if (st->signum == SIGHUP) {
                close_afs_tables();
+               parse_config_or_die(1);
                t->error = open_afs_tables();
                if (t->error < 0)
                        return;
@@ -782,14 +804,7 @@ static void register_signal_task(void)
 {
        struct signal_task *st = &signal_task_struct;
 
-       if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) {
-               PARA_EMERG_LOG("failed to ignore SIGPIPE\n");
-               exit(EXIT_FAILURE);
-       }
-       if (signal(SIGUSR1, SIG_IGN) == SIG_ERR) {
-               PARA_EMERG_LOG("failed to ignore SIGUSR1\n");
-               exit(EXIT_FAILURE);
-       }
+       para_sigaction(SIGPIPE, SIG_IGN);
        st->fd = para_signal_init();
        PARA_INFO_LOG("signal pipe: fd %d\n", st->fd);
        para_install_sighandler(SIGINT);
@@ -797,7 +812,7 @@ static void register_signal_task(void)
        para_install_sighandler(SIGHUP);
 
        st->task.pre_select = signal_pre_select;
-       st->task.post_select = signal_post_select;
+       st->task.post_select = afs_signal_post_select;
        sprintf(st->task.status, "signal task");
        register_task(&st->task);
 }
@@ -892,7 +907,7 @@ static int call_callback(int fd, int query_shmid)
        query.data = (char *)query_shm + sizeof(*cq);
        query.size = cq->query_size;
        cq->handler(fd, &query);
-       return 1;
+       return shm_detach(query_shm);
 }
 
 static int execute_server_command(void)
@@ -1105,7 +1120,7 @@ int com_init(int fd, int argc, char * const * const argv)
                                return -E_BAD_TABLE_NAME;
                }
        }
-       ret = send_callback_request(create_tables_callback, &query, NULL, NULL);
+       ret = send_callback_request(create_tables_callback, &query, &send_result, &fd);
        if (ret < 0)
                return send_va_buffer(fd, "%s\n", para_strerror(-ret));
        return ret;
@@ -1174,6 +1189,16 @@ int com_check(int fd, int argc, char * const * const argv)
        return 1;
 }
 
+/**
+ * The afs event dispatcher.
+ *
+ * \param event Type of the event.
+ * \param pb May be \p NULL.
+ * \param data Type depends on \a event.
+ *
+ * This function calls the table handlers of all tables and passes \a pb and \a
+ * data verbatim. It's up to the handlers to interpret the \a data pointer.
+ */
 void afs_event(enum afs_events event, struct para_buffer *pb,
                void *data)
 {