discover: Add 'sync' user event
[petitboot] / utils / pb-event.c
index 5ef811513c0eea5c079136ed9be02d4ea6ebf6fa..10bf4f59ab3857b8ab6af8ef50ff012871c5a76e 100644 (file)
@@ -20,8 +20,8 @@
 #include "config.h"
 #endif
 
-#define _GNU_SOURCE
 #include <assert.h>
+#include <err.h>
 #include <errno.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -40,43 +40,103 @@ static inline int __attribute__ ((format (printf, 1, 2))) DBG(
        __attribute__((unused)) const char *fmt, ...) {return 0; }
 #endif
 
-int main(void)
+static void print_version(void)
 {
-       int result;
-       struct sockaddr_un addr;
-       char buf[PBOOT_USER_EVENT_SIZE];
-       ssize_t len;
-       int s;
+       printf("pb-event (" PACKAGE_NAME ") " PACKAGE_VERSION "\n");
+}
+
+static void print_usage(void)
+{
+       print_version();
+       printf(
+"Usage: pb-event [-h] [event...]\n"
+"\n"
+"       Send a single petitboot user event to the petitboot discover server.\n"
+"       Events can be read from stdin, or provided on the command line.\n"
+"       User events must have the following format:\n"
+"\n"
+"         (add|remove|boot|sync)@device-id [name=value] [image=value] [args=value]\n"
+"\n"
+"       When read from stdin, components are separated by NUL chars\n"
+"\n"
+"Examples:\n"
+"\n"
+"    args:\n"
+"       pb-event add@/net/eth0 name=netboot image=tftp://192.168.1.10/vmlinux\n"
+"       pb-event remove@/net/eth0\n"
+"\n"
+"    stdin:\n"
+"       printf 'add@/net/eth0\\0name=netboot\\0image=tftp://10.0.0.2/vmlinux\\0' \\\n"
+"           | pb-event\n"
+"       printf 'remove@/net/eth0\\0' | pb-event\n"
+"\n");
+}
+
+static const char *err_max_size = "pb-event: message too large "
+                                       "(%zu byte max)\n";
+
+static ssize_t parse_event_args(int n, char * const * args,
+               char *buf, size_t max_len)
+{
+       ssize_t arg_len, total_len;
+       const char *arg;
        int i;
 
-       s = socket(PF_UNIX, SOCK_DGRAM, 0);
+       total_len = 0;
 
-       if (s < 0) {
-               fprintf(stderr, "pb-event: socket: %s\n", strerror(errno));
-               return EXIT_FAILURE;
+       for (i = 0; i < n; i++) {
+               arg = args[i];
+               arg_len = strlen(arg);
+
+               if (total_len + (size_t)i + 1 > max_len) {
+                       fprintf(stderr, err_max_size, max_len);
+                       return -1;
+               }
+
+               memcpy(buf + total_len, arg, arg_len);
+               total_len += arg_len;
+
+               buf[total_len] = '\0';
+               total_len++;
        }
 
-       result = EXIT_SUCCESS;
+       return total_len;
+
+}
+
+static ssize_t parse_event_file(FILE *filp, char *buf, size_t max_len)
+{
+       int len;
 
-       len = fread(buf, 1, sizeof(buf), stdin);
+       len = fread(buf, 1, max_len, filp);
 
-       if (!feof(stdin)) {
-               fprintf(stderr, "pb-event: msg too big (%u byte max)\n",
-                       sizeof(buf));
-               result = EXIT_FAILURE;
-               /* continue on and try to write msg */
+       if (!feof(filp)) {
+               fprintf(stderr, err_max_size, max_len);
+               return -1;
        }
 
        if (!len)
-               return result;
+               return -1;
+
+       return len;
+}
+
+static int send_event(char *buf, ssize_t len)
+{
+       struct sockaddr_un addr;
+       int sd, i;
+
+       sd = socket(PF_UNIX, SOCK_DGRAM, 0);
+       if (sd < 0)
+               err(EXIT_FAILURE, "socket");
 
        memset(&addr, 0, sizeof(addr));
        addr.sun_family = AF_UNIX;
        strcpy(addr.sun_path, PBOOT_USER_EVENT_SOCKET);
 
        for (i = 10; i; i--) {
-               ssize_t sent = sendto(s, buf, len, 0, (struct sockaddr *)&addr,
-                       SUN_LEN(&addr));
+               ssize_t sent = sendto(sd, buf, len, 0,
+                               (struct sockaddr *)&addr, SUN_LEN(&addr));
 
                if (sent == len)
                        break;
@@ -85,11 +145,37 @@ int main(void)
                sleep(1);
        }
 
-       if (!i) {
-               fprintf(stderr, "pb-event: send: %s\n", strerror(errno));
-               return EXIT_FAILURE;
+       close(sd);
+
+       if (!i)
+               err(EXIT_FAILURE, "send");
+
+       DBG("pb-event: wrote %zu bytes\n", len);
+
+       return 0;
+}
+
+int main(int argc, char *argv[])
+{
+       char buf[PBOOT_USER_EVENT_SIZE];
+       ssize_t len;
+
+       if (argc >= 2 && !strcmp(argv[1], "-h")) {
+               print_usage();
+               return EXIT_SUCCESS;
        }
 
-       DBG("pb-event: wrote %u bytes\n", len);
-       return result;
+       if (argc > 1) {
+               len = parse_event_args(argc - 1, argv + 1,
+                                       buf, sizeof(buf));
+       } else {
+               len = parse_event_file(stdin, buf, sizeof(buf));
+       }
+
+       if (len < 0)
+               return EXIT_FAILURE;
+
+       send_event(buf, len);
+
+       return EXIT_SUCCESS;
 }