rats

RAdix iniT Suite
git clone https://git.daat.foo/repos/rats.git
Log | Files | Refs | README | LICENSE

svc.c (2508B)


      1 /* svc: control client for ssv */
      2 
      3 #ifndef _POSIX_C_SOURCE
      4 #define _POSIX_C_SOURCE 200809L
      5 #endif
      6 
      7 #include "arg.h"
      8 #include "util.h"
      9 
     10 #include <sys/socket.h>
     11 #include <sys/un.h>
     12 #include <errno.h>
     13 #include <stdio.h>
     14 #include <string.h>
     15 #include <unistd.h>
     16 
     17 #ifndef SOCK_PATH
     18 #define SOCK_PATH "/run/serva.sock"
     19 #endif
     20 
     21 static void
     22 usage(void)
     23 {
     24 	eprintf("usage: %s [-udrkts] [-a] [service...]\n", argv0);
     25 }
     26 
     27 static int
     28 request(int action, const char *name)
     29 {
     30 	int sock, len;
     31 	struct sockaddr_un addr;
     32 	char buf[4096], resp[4096], prefix[5];
     33 	ssize_t n;
     34 	size_t have = 0, chunk;
     35 
     36 	if (strchr(name, '\n') || strchr(name, '\r'))
     37 		eprintf("invalid service name\n");
     38 	len = snprintf(buf, sizeof(buf), "%c %s\n", action, name);
     39 	if (len < 0 || (size_t)len >= sizeof(buf))
     40 		eprintf("command too long\n");
     41 
     42 	/* connect to ssv control socket */
     43 	sock = socket(AF_UNIX, SOCK_STREAM, 0);
     44 	if (sock < 0)
     45 		eprintf("socket:");
     46 	memset(&addr, 0, sizeof(addr));
     47 	addr.sun_family = AF_UNIX;
     48 	if (strlcpy(addr.sun_path, SOCK_PATH, sizeof(addr.sun_path)) >= sizeof(addr.sun_path))
     49 		eprintf("socket path too long: %s\n", SOCK_PATH);
     50 	if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0)
     51 		eprintf("connect %s:", SOCK_PATH);
     52 
     53 	/* send command, print response */
     54 	if (writeall(sock, buf, len) != len)
     55 		eprintf("write socket:");
     56 	if (shutdown(sock, SHUT_WR) < 0)
     57 		eprintf("shutdown socket:");
     58 	for (;;) {
     59 		n = read(sock, resp, sizeof(resp));
     60 		if (n < 0 && errno == EINTR)
     61 			continue;
     62 		if (n < 0)
     63 			eprintf("read socket:");
     64 		if (n == 0)
     65 			break;
     66 		chunk = MIN((size_t)n, sizeof(prefix) - have);
     67 		memcpy(prefix + have, resp, chunk);
     68 		have += chunk;
     69 		if (writeall(STDOUT_FILENO, resp, n) != n)
     70 			eprintf("write stdout:");
     71 	}
     72 	close(sock);
     73 	return have == sizeof(prefix) && memcmp(prefix, "ERR: ", sizeof(prefix)) == 0;
     74 }
     75 
     76 int
     77 main(int argc, char *argv[])
     78 {
     79 	int aflag = 0, action = 0, ret = 0, i;
     80 
     81 	ARGBEGIN {
     82 	case 'u': action = 'u'; break;
     83 	case 'd': action = 'd'; break;
     84 	case 'r': action = 'r'; break;
     85 	case 'k': action = 'k'; break;
     86 	case 't': action = 't'; break;
     87 	case 's': action = 's'; break;
     88 	case 'a': aflag = 1;    break;
     89 	default:  usage();
     90 	} ARGEND
     91 
     92 	if (!action || (action != 's' && !aflag && argc == 0))
     93 		usage();
     94 	if (aflag && (argc != 0 || (action != 'u' && action != 'd')))
     95 		usage();
     96 
     97 	if (aflag || argc == 0)
     98 		ret = request(action, aflag ? "a" : "");
     99 	else
    100 		for (i = 0; i < argc; i++)
    101 			ret |= request(action, argv[i]);
    102 
    103 	if (fshut(stdout, "<stdout>"))
    104 		return 2;
    105 	return ret;
    106 }