// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-FileCopyrightText: 2020 Alyssa Ross #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include "env.h" #include "log.h" #include "util.h" #include "vsock.h" static void ex_usage(void) __attribute__((noreturn)); static void ex_usage(void) { if (verbosity) fprintf(stderr, "Usage: %s [ -q | -Q | -v ] cid port prog...\n", program_invocation_short_name); exit(EX_USAGE); } int main(int argc, char *argv[]) { int opt, fd; uint32_t rcid, rport; while ((opt = getopt(argc, argv, "+qQv")) != -1) { switch (opt) { case 'q': verbosity = nothing; break; case 'Q': verbosity = errors; break; case 'v': verbosity = all; 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 (getu32(argv[optind++], 0, UINT32_MAX, &rcid)) ex_usage(); if (getu32(argv[optind++], 0, UINT32_MAX, &rport)) ex_usage(); setenvf("VSOCKREMOTECID", 1, "%" PRIu32, rcid); setenvf("VSOCKREMOTEPORT", 1, "%" PRIu32, rport); ilog("connecting to %" PRIu32 ":%" PRIu32 "...", rcid, rport); // Linux will sometimes randomly time out connections, even on // the same host with no backlog, so retry a few times. { int i = 0; do fd = vsock_open(rcid, rport); while (i++ < 3 && fd == -1 && errno == ETIMEDOUT); } if (fd == -1) diee(EX_UNAVAILABLE, "connect to %" PRIu32 ":%" PRIu32 " failed", rcid, rport); ilog("connected to %" PRIu32 ":%" PRIu32 "!", rcid, rport); // Set up the file descriptors to the well-known UCSPI numbers. if (dup2(fd, 6) == -1) diee(EX_OSERR, "dup2"); if (dup2(fd, 7) == -1) diee(EX_OSERR, "dup2"); if (fd != 6 && fd != 7) close(fd); execvp(argv[optind], &argv[optind]); diee(EX_OSERR, "exec"); }