aboutsummaryrefslogtreecommitdiffstats
path: root/radharc-ipc.c
diff options
context:
space:
mode:
Diffstat (limited to 'radharc-ipc.c')
-rw-r--r--radharc-ipc.c147
1 files changed, 147 insertions, 0 deletions
diff --git a/radharc-ipc.c b/radharc-ipc.c
new file mode 100644
index 0000000..e246375
--- /dev/null
+++ b/radharc-ipc.c
@@ -0,0 +1,147 @@
+/* See LICENSE file for copyright and license details. */
+#include <libsimple-arg.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+USAGE("[-R rule] (pid | @name | &fd | address) ...");
+
+
+struct message {
+ char *text;
+ size_t len;
+};
+
+
+static int
+parse_uint(const char *s, uintmax_t *value)
+{
+ uintmax_t digit;
+ if (!*s)
+ return 0;
+ *value = 0;
+ for (; isdigit(*s); s++) {
+ digit = (*s & 15);
+ if (*value > (UINTMAX_MAX - digit) / 10)
+ return 0;
+ *value = *value * 10 + digit;
+ }
+ return !*s;
+}
+
+
+int
+main(int argc, char *argv[])
+{
+ const char *rule = "standard";
+ char *class, **addresses;
+ int ret = 0;
+ size_t i, j;
+ struct sockaddr_un addr;
+ size_t addrlen;
+ int sock;
+ struct message *messages = NULL;
+ size_t nmessages = 0;
+
+ ARGBEGIN {
+ case 'R':
+ rule = ARG();
+ break;
+ default:
+ usage();
+ } ARGEND;
+
+ if (!argc)
+ usage();
+
+ class = malloc(sizeof(PACKAGE_NAME"::"COMMAND_NAME"::") + strlen(rule));
+ if (!class)
+ goto fail;
+ stpcpy(stpcpy(class, PACKAGE_NAME"::"COMMAND_NAME"::"), rule);
+
+ addresses = calloc((size_t)argc, sizeof(*addresses));
+ if (!addresses)
+ goto fail;
+
+ for (i = 0; i < (size_t)argc; i++) {
+ const char *arg = argv[i];
+ uintmax_t num;
+ if (*arg == '@' || strchr(arg, '/')) {
+ addresses[i] = strdup(arg);
+ if (addresses[i])
+ goto fail;
+ if (*arg == '@')
+ addresses[i][0] = '\0';
+ } else if (parse_uint(&arg[*arg == '&'], &num)) {
+ if (*arg == '&') {
+ if (num > (uintmax_t)INT_MAX)
+ usage();
+ addresses[i] = malloc(sizeof("/proc/self/fd/") + strlen(&arg[1]));
+ if (!addresses[i])
+ goto fail;
+ stpcpy(stpcpy(addresses[i], "/proc/self/fd/"), &arg[1]);
+ } else {
+ addresses[i] = malloc(sizeof("@/proc//") + strlen(arg) + strlen(class));
+ if (!addresses[i])
+ goto fail;
+ stpcpy(stpcpy(stpcpy(stpcpy(&addresses[i][1], "/proc/"), arg), "/"), class);
+ addresses[i][0] = '\0';
+ }
+ } else {
+ usage();
+ }
+ if (strlen(&addresses[i][1]) + 1U > sizeof(addr.sun_path)) {
+ fprintf(stderr, "%s: socket name '%s%s' too long\n", argv0,
+ addresses[i][0] ? "" : "@", &addresses[i][!addresses[i][0]]);
+ return 1;
+ }
+ }
+
+ sock = socket(PF_UNIX, SOCK_DGRAM, 0);
+ if (sock < 0)
+ goto fail;
+
+ for (j = 0; j < nmessages; j++) {
+ for (i = 0; i < (size_t)argc; i++) {
+ size_t len;
+
+ if (!addresses[i])
+ continue;
+
+ len = strlen(&addresses[i][1]) + 1U;
+ memset(&addr, 0, sizeof(addr));
+ addr.sun_family = AF_UNIX;
+ memcpy(addr.sun_path, addresses[i], len);
+ addrlen = offsetof(struct sockaddr_un, sun_path) + len;
+
+ if (sendto(sock, messages[j].text, messages[j].len, MSG_NOSIGNAL,
+ (void *)&addr, (socklen_t)addrlen) < 0) {
+ fprintf(stderr, "%s: error while sending to '%s': %s\n",
+ argv0, argv[i], strerror(errno));
+ ret = 1;
+ addresses[i] = NULL;
+ }
+ }
+ free(messages[j].text);
+ }
+
+ close(sock);
+
+ for (i = 0; i < (size_t)argc; i++)
+ free(addresses[i]);
+ free(addresses);
+ free(messages);
+ free(class);
+ return ret;
+
+fail:
+ perror(argv0);
+ return 1;
+}