+}
+
+/* --- @a_ok@, @a_info@, @a_fail@ --- *
+ *
+ * Arguments: @admin *a@ = connection
+ * @const char *fmt@ = format string
+ * @...@ = other arguments
+ *
+ * Returns: ---
+ *
+ * Use: Convenience functions for @a_write@.
+ */
+
+static void a_ok(admin *a) { a_write(a, "OK", 0); }
+
+static void a_info(admin *a, const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ a_vwrite(a, "INFO", fmt, ap);
+ va_end(ap);
+}
+
+static void a_fail(admin *a, const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ a_vwrite(a, "FAIL", fmt, ap);
+ va_end(ap);
+}
+
+/* --- @a_alert@, @a_valert@, @a_rawalert@ --- *
+ *
+ * Arguments: @unsigned f_and, f_eq@ = filter for connections
+ * @const char *tag@ = tag prefix string
+ * @const char *fmt@ = pointer to format string
+ @ @const char *p@ = pointer to raw string
+ * @size_t sz@ = size of raw string
+ * @va_list ap@ = arguments in list
+ * @...@ = other arguments
+ *
+ * Returns: ---
+ *
+ * Use: Write a message to all admin connections matched by the given
+ * filter.
+ */
+
+static void a_rawalert(unsigned f_and, unsigned f_eq, const char *tag,
+ const char *p, size_t sz)
+{
+ admin *a, *aa;
+ dstr d = DSTR_INIT;
+
+ if (!(flags & F_INIT))
+ return;
+ if (tag) {
+ dstr_puts(&d, tag);
+ if (p)
+ dstr_putc(&d, ' ');
+ }
+ if (p)
+ dstr_putm(&d, p, sz);
+ dstr_putc(&d, '\n');
+ p = d.buf;
+ sz = d.len;
+ for (a = admins; a; a = aa) {
+ aa = a->next;
+ if ((a->f & f_and) == f_eq)
+ dosend(a, d.buf, d.len);
+ }