Introduce afs_error().
[paraslash.git] / afs.c
diff --git a/afs.c b/afs.c
index 6493586a6abad51c1f6bd5d3716c7a1dd1beeb23..b15f83852e6919c4f0867065d13776c211416087 100644 (file)
--- a/afs.c
+++ b/afs.c
@@ -728,6 +728,43 @@ err:
        return ret;
 }
 
+/**
+ * Format and send an error message to the command handler.
+ *
+ * To pass an error message from the callback of an afs command to the client,
+ * this function should be called. It formats the message into a buffer which
+ * is passed as a shared memory area to the command handler from where it
+ * propagates to the client.
+ *
+ * The message will be tagged with the ERROR_LOG sideband designator so that
+ * the client writes it to its stderr stream rather than to stdout as with
+ * aca->pbout. In analogy to the default Unix semantics of stderr, the message
+ * is sent without buffering.
+ *
+ * If sending the error message fails, an error is logged on the server side,
+ * but no other action is taken.
+ *
+ * \param aca Used to obtain the fd to send the shmid to.
+ * \param fmt Usual format string.
+ */
+__printf_2_3 void afs_error(const struct afs_callback_arg *aca,
+               const char *fmt,...)
+{
+       va_list argp;
+       char *msg;
+       unsigned n;
+       int ret;
+
+       va_start(argp, fmt);
+       n = xvasprintf(&msg, fmt, argp);
+       va_end(argp);
+       ret = pass_buffer_as_shm(aca->fd, SBD_ERROR_LOG, msg, n + 1);
+       if (ret < 0)
+               PARA_ERROR_LOG("Could not send %s: %s\n", msg,
+                       para_strerror(-ret));
+       free(msg);
+}
+
 static int call_callback(int fd, int query_shmid)
 {
        void *query_shm;
@@ -958,12 +995,12 @@ static int com_select_callback(struct afs_callback_arg *aca)
        /* ignore subsequent errors (but log them) */
        if (current_mop && strcmp(current_mop, arg) != 0) {
                int ret2;
-               para_printf(&aca->pbout, "switching back to %s\n", current_mop);
+               afs_error(aca, "switching back to %s\n", current_mop);
                ret2 = activate_mood_or_playlist(current_mop, &aca->pbout);
                if (ret2 >= 0)
                        goto free_lpr;
-               para_printf(&aca->pbout, "could not reactivate %s: %s\n",
-                       current_mop, para_strerror(-ret2));
+               afs_error(aca, "could not reactivate %s: %s\n", current_mop,
+                       para_strerror(-ret2));
        }
        activate_mood_or_playlist(NULL, &aca->pbout);
 free_lpr:
@@ -1001,8 +1038,7 @@ static int com_init_callback(struct afs_callback_arg *aca)
                        continue;
                ret = t->ops->create(database_dir);
                if (ret < 0) {
-                       para_printf(&aca->pbout, "cannot create table %s\n",
-                               t->name);
+                       afs_error(aca, "cannot create table %s\n", t->name);
                        goto out;
                }
                para_printf(&aca->pbout, "successfully created %s table\n",
@@ -1010,7 +1046,7 @@ static int com_init_callback(struct afs_callback_arg *aca)
        }
        ret = open_afs_tables();
        if (ret < 0)
-               para_printf(&aca->pbout, "cannot open afs tables: %s\n",
+               afs_error(aca, "cannot open afs tables: %s\n",
                        para_strerror(-ret));
 out:
        return ret;