#include #include #include #include #include #include #include #include int check(const char *path, const char *service) { struct sockaddr_un addr = { 0 }; addr.sun_family = AF_UNIX; strncpy(addr.sun_path, path, sizeof addr.sun_path - 1); int connfd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0); if (connfd < 0) { perror("socket"); exit(111); } if (connect(connfd, (struct sockaddr *)&addr, sizeof addr) < 0) { perror("connect"); exit(111); } write(connfd, "s", 1); // XXX what if too low? char buf[4096]; ssize_t rd = read(connfd, buf, sizeof buf); if (rd < 0) { perror("read"); exit(111); } char *p; char *f = strstr(buf, service); if (f && (f == buf || f[-1] == '\n') && f[strlen(service)+1] == ' ' && (p = strstr(f, "pid="))) { p += 4; printf("found pid %c\n", p[0]); if (isdigit(p[0])) { close(connfd); return 1; // has pid >= 0 } } // XXX fix multiple strstr matches close(connfd); return 0; } int main(int argc, char *argv[]) { if (argc < 2 || ( strcmp(argv[1], "l") != 0 && strcmp(argv[1], "level") != 0 && strcmp(argv[1], "s") != 0 && strcmp(argv[1], "status") != 0 && strcmp(argv[1], "d") != 0 && strcmp(argv[1], "down") != 0 && strcmp(argv[1], "u") != 0 && strcmp(argv[1], "up") != 0 && strcmp(argv[1], "p") != 0 && strcmp(argv[1], "pause") != 0 && strcmp(argv[1], "c") != 0 && strcmp(argv[1], "cont") != 0 && strcmp(argv[1], "h") != 0 && strcmp(argv[1], "hup") != 0 && strcmp(argv[1], "a") != 0 && strcmp(argv[1], "alarm") != 0 && strcmp(argv[1], "i") != 0 && strcmp(argv[1], "interrupt") != 0 && strcmp(argv[1], "q") != 0 && strcmp(argv[1], "quit") != 0 && strcmp(argv[1], "t") != 0 && strcmp(argv[1], "term") != 0 && strcmp(argv[1], "k") != 0 && strcmp(argv[1], "kill") != 0 && strcmp(argv[1], "1") != 0 && strcmp(argv[1], "2") != 0 && strcmp(argv[1], "start") != 0 && strcmp(argv[1], "stop") != 0 && strcmp(argv[1], "Restart") != 0 && strcmp(argv[1], "Shutdown") != 0)) { dprintf(2, "usage: rvnitctl COMMAND [SERVICE]\n"); exit(2); } static const char default_sock[] = "/run/rvnit/rvnit.sock"; const char *path = getenv("RVNIT_SOCK"); if (!path || !*path) path = default_sock; struct sockaddr_un addr = { 0 }; addr.sun_family = AF_UNIX; strncpy(addr.sun_path, path, sizeof addr.sun_path - 1); int connfd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0); if (connfd < 0) { perror("socket"); exit(111); } if (connect(connfd, (struct sockaddr *)&addr, sizeof addr) < 0) { perror("connect"); exit(111); } char cmd = argv[1][0]; if (strcmp(argv[1], "start") == 0 && argv[2]) cmd = 'u'; else if (strcmp(argv[1], "stop") == 0 && argv[2]) cmd = 'd'; dprintf(connfd, "%c%s", cmd, argv[2] ? argv[2] : ""); int status = 1; ssize_t rd; do { char buf[4096]; rd = read(connfd, buf, sizeof buf); if (rd < 0) { perror("read"); exit(111); } if (rd > 0) status = 0; write(1, buf, rd); } while (rd > 0); if (strcmp(argv[1], "start") == 0 && argv[2]) { int i; int up = 0; for (i = 7*4; i > 0; i--) { if (check(path, argv[2])) { if (++up >= 2) break; } else { up = 0; } nanosleep(&(struct timespec){0, 250000000}, 0); } if (up < 2) { fprintf(stderr, "start failed\n"); return 1; } } else if (strcmp(argv[1], "stop") == 0 && argv[2]) { int i; int down = 0; for (i = 7*4; i > 0; i--) { if (!check(path, argv[2])) { if (++down >= 2) break; } else { down = 0; } nanosleep(&(struct timespec){0, 250000000}, 0); } if (down < 2) { fprintf(stderr, "stop failed\n"); return 1; } } return status; }