// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-FileCopyrightText: 2020-2021 Alyssa Ross #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include "env.h" #include "log.h" #include "util.h" #include "vsock.h" noreturn static void ex_usage(void) { if (verbosity) fprintf(stderr, "Usage: %s [ -1 ] [ -q | -Q | -v ] cid port prog...\n", program_invocation_short_name); exit(EX_USAGE); } int main(int argc, char *argv[]) { bool notify = false; int opt, conn; pid_t child; uint32_t lcid, lport, rcid, rport; while ((opt = getopt(argc, argv, "+1qQv")) != -1) { switch (opt) { case '1': notify = true; break; case 'q': case 'Q': case 'v': set_verbosity(opt); break; default: ex_usage(); } } // Check there are enough positional arguments (two for the // address and at least one to exec into). if (optind > argc - 3) ex_usage(); if (!strcmp(argv[optind], "-1")) lcid = VMADDR_CID_ANY; else if (getu32(argv[optind], 0, UINT32_MAX, &lcid)) ex_usage(); optind++; if (!strcmp(argv[optind], "-1")) lport = VMADDR_PORT_ANY; else if (getu32(argv[optind], 0, UINT32_MAX, &lport)) ex_usage(); optind++; int fd = socket(AF_VSOCK, SOCK_STREAM, 0); if (fd == -1) diee(EX_OSERR, "socket"); if (vsock_bind(fd, lcid, lport) == -1) diee(EX_OSERR, "bind"); if (listen(fd, 40) == -1) diee(EX_OSERR, "listen"); if (lport == VMADDR_PORT_ANY) if (vsock_get_port(fd, &lport) == -1) diee(EX_OSERR, "getsockname"); if (notify) { printf("%" PRIu32 "\n", lport); fclose(stdout); } setenvf("VSOCKLOCALCID", 1, "%" PRIu32, lcid); setenvf("VSOCKLOCALPORT", 1, "%" PRIu32, lport); ilog("listening as %" PRIu32 " on port %" PRIu32, lcid, lport); while ((conn = vsock_accept(fd, &rcid, &rport)) != -1) { setenvf("VSOCKREMOTECID", 1, "%" PRIu32, rcid); setenvf("VSOCKREMOTEPORT", 1, "%" PRIu32, rport); ilog("connection from %" PRIu32 " port %" PRIu32, rcid, rport); switch (child = fork()) { case -1: diee(EX_OSERR, "fork"); case 0: if (dup2(conn, STDIN_FILENO) == -1) diee(EX_OSERR, "dup2"); if (dup2(conn, STDOUT_FILENO) == -1) diee(EX_OSERR, "dup2"); if (conn != STDIN_FILENO && conn != STDOUT_FILENO) close(conn); execvp(argv[optind], &argv[optind]); diee(EX_OSERR, "exec"); } if (waitpid(child, NULL, 0) == -1) diee(EX_OSERR, "waitpid"); close(conn); } diee(EX_OSERR, "accept"); }