From 8a3b6ad4e2f93e43c219295ef4fdc598c23bb7e4 Mon Sep 17 00:00:00 2001 From: Derek Zhou Date: Fri, 27 Mar 2020 11:45:23 -0400 Subject: [PATCH] Add -N switch to keep abduco in the forground Useful for systemd/runit/daemontools. dtach has it --- abduco.1 | 8 +++++++ abduco.c | 67 +++++++++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 72 insertions(+), 3 deletions(-) diff --git a/abduco.1 b/abduco.1 index 73382fb..b4c4f4b 100644 --- a/abduco.1 +++ b/abduco.1 @@ -30,6 +30,12 @@ .Cm name .Cm command Op args ... . +.Nm +.Fl N +.Op options ... +.Cm name +.Cm command Op args ... +. .Sh DESCRIPTION . .Nm @@ -85,6 +91,8 @@ Try to connect to an existing session, upon failure create said session and atta Create a new session and attach immediately to it. .It Fl n Create a new session but do not attach to it. +.It Fl N +Create a new session but do not attach to it and stay in the forground until the program exits. .El . .Ss OPTIONS diff --git a/abduco.c b/abduco.c index 84ddb9a..5bf4dde 100644 --- a/abduco.c +++ b/abduco.c @@ -463,7 +463,8 @@ static bool create_session(const char *name, char * const argv[]) { sa.sa_handler = SIG_IGN; sigaction(SIGPIPE, &sa, NULL); sigaction(SIGHUP, &sa, NULL); - chdir("/"); + if (chdir("/") == -1) /* should not happen, just to make the compiler happy */ + _exit(EXIT_FAILURE); #ifdef NDEBUG int fd = open("/dev/null", O_RDWR); if (fd != -1) { @@ -513,6 +514,59 @@ static bool create_session(const char *name, char * const argv[]) { return true; } +static bool launch_session(const char *name, char * const argv[]) { + /* this is basically create_session without the double fork + */ + char errormsg[255]; + struct sigaction sa; + + if (session_exists(name)) { + errno = EADDRINUSE; + return false; + } + + if ((server.socket = server_create_socket(name)) == -1) + return false; + + sa.sa_flags = 0; + sigemptyset(&sa.sa_mask); + sa.sa_handler = server_pty_died_handler; + sigaction(SIGCHLD, &sa, NULL); + switch (server.pid = forkpty(&server.pty, NULL, has_term ? &server.term : NULL, &server.winsize)) { + case 0: /* child = user application process */ + execvp(argv[0], argv); + snprintf(errormsg, sizeof(errormsg), "server-execvp: %s: %s\n", + argv[0], strerror(errno)); + _exit(EXIT_FAILURE); + break; + case -1: /* forkpty failed */ + snprintf(errormsg, sizeof(errormsg), "server-forkpty: %s\n", strerror(errno)); + _exit(EXIT_FAILURE); + break; + default: /* parent = server process */ + sa.sa_handler = server_sigterm_handler; + sigaction(SIGTERM, &sa, NULL); + sigaction(SIGINT, &sa, NULL); + sigaction(SIGHUP, &sa, NULL); + sa.sa_handler = server_sigusr1_handler; + sigaction(SIGUSR1, &sa, NULL); + sa.sa_handler = SIG_IGN; + sigaction(SIGPIPE, &sa, NULL); +#ifdef NDEBUG + int fd = open("/dev/null", O_RDWR); + if (fd != -1) { + dup2(fd, STDIN_FILENO); + dup2(fd, STDOUT_FILENO); + dup2(fd, STDERR_FILENO); + close(fd); + } +#endif /* NDEBUG */ + server_mainloop(); + break; + } + return true; +} + static bool attach_session(const char *name, const bool terminate) { if (server.socket > 0) close(server.socket); @@ -606,12 +660,13 @@ int main(int argc, char *argv[]) { server.name = basename(argv[0]); gethostname(server.host+1, sizeof(server.host) - 1); - while ((opt = getopt(argc, argv, "aAclne:fpqrv")) != -1) { + while ((opt = getopt(argc, argv, "aAclnNe:fpqrv")) != -1) { switch (opt) { case 'a': case 'A': case 'c': case 'n': + case 'N': action = opt; break; case 'e': @@ -679,10 +734,11 @@ int main(int argc, char *argv[]) { server.winsize.ws_row = 25; } - server.read_pty = (action == 'n'); + server.read_pty = (action == 'n') || (action == 'N'); redo: switch (action) { + case 'N': case 'n': case 'c': if (force) { @@ -693,6 +749,11 @@ int main(int argc, char *argv[]) { if (session_exists(server.session_name)) attach_session(server.session_name, false); } + if (action == 'N') { + if (!launch_session(server.session_name, cmd)) + die("launch-session"); + break; + } if (!create_session(server.session_name, cmd)) die("create-session"); if (action == 'n')