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 }