buildpack/vendor/dtach/main.c
2019-11-30 20:37:28 +02:00

285 lines
7.1 KiB
C

/*
dtach - A simple program that emulates the detach feature of screen.
Copyright (C) 2004-2016 Ned T. Crigler
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "dtach.h"
/*
** dtach is a quick hack, since I wanted the detach feature of screen without
** all the other crud. It'll work best with full-screen applications, as it
** does not keep track of the screen or anything like that.
*/
/* Make sure the binary has a copyright. */
const char copyright[] = "dtach - version " PACKAGE_VERSION "(C)Copyright 2004-2016 Ned T. Crigler";
/* argv[0] from the program */
char *progname;
/* The name of the passed in socket. */
char *sockname;
/* The character used for detaching. Defaults to '^\' */
int detach_char = '\\' - 64;
/* 1 if we should not interpret the suspend character. */
int no_suspend;
/* The default redraw method. Initially set to unspecified. */
int redraw_method = REDRAW_UNSPEC;
/*
** The original terminal settings. Shared between the master and attach
** processes. The master uses it to initialize the pty, and the attacher uses
** it to restore the original settings.
*/
struct termios orig_term;
int dont_have_tty;
static void
usage()
{
printf(
"dtach - version %s, compiled on %s at %s.\n"
"Usage: dtach -a <socket> <options>\n"
" dtach -A <socket> <options> <command...>\n"
" dtach -c <socket> <options> <command...>\n"
" dtach -n <socket> <options> <command...>\n"
" dtach -N <socket> <options> <command...>\n"
" dtach -p <socket>\n"
"Modes:\n"
" -a\t\tAttach to the specified socket.\n"
" -A\t\tAttach to the specified socket, or create it if it\n"
"\t\t does not exist, running the specified command.\n"
" -c\t\tCreate a new socket and run the specified command.\n"
" -n\t\tCreate a new socket and run the specified command "
"detached.\n"
" -N\t\tCreate a new socket and run the specified command "
"detached,\n"
"\t\t and have dtach run in the foreground.\n"
" -p\t\tCopy the contents of standard input to the specified\n"
"\t\t socket.\n"
"Options:\n"
" -e <char>\tSet the detach character to <char>, defaults "
"to ^\\.\n"
" -E\t\tDisable the detach character.\n"
" -r <method>\tSet the redraw method to <method>. The "
"valid methods are:\n"
"\t\t none: Don't redraw at all.\n"
"\t\t ctrl_l: Send a Ctrl L character to the program.\n"
"\t\t winch: Send a WINCH signal to the program.\n"
" -z\t\tDisable processing of the suspend key.\n"
"\nReport any bugs to <" PACKAGE_BUGREPORT ">.\n",
PACKAGE_VERSION, __DATE__, __TIME__);
exit(0);
}
int
main(int argc, char **argv)
{
int mode = 0;
/* Save the program name */
progname = argv[0];
++argv; --argc;
/* Parse the arguments */
if (argc >= 1 && **argv == '-')
{
if (strncmp(*argv, "--help", strlen(*argv)) == 0)
usage();
else if (strncmp(*argv, "--version", strlen(*argv)) == 0)
{
printf("dtach - version %s, compiled on %s at %s.\n",
PACKAGE_VERSION, __DATE__, __TIME__);
return 0;
}
mode = argv[0][1];
if (mode == '?')
usage();
else if (mode != 'a' && mode != 'c' && mode != 'n' &&
mode != 'A' && mode != 'N' && mode != 'p')
{
printf("%s: Invalid mode '-%c'\n", progname, mode);
printf("Try '%s --help' for more information.\n",
progname);
return 1;
}
}
if (!mode)
{
printf("%s: No mode was specified.\n", progname);
printf("Try '%s --help' for more information.\n",
progname);
return 1;
}
++argv; --argc;
if (argc < 1)
{
printf("%s: No socket was specified.\n", progname);
printf("Try '%s --help' for more information.\n",
progname);
return 1;
}
sockname = *argv;
++argv; --argc;
if (mode == 'p')
{
if (argc > 0)
{
printf("%s: Invalid number of arguments.\n",
progname);
printf("Try '%s --help' for more information.\n",
progname);
return 1;
}
return push_main();
}
while (argc >= 1 && **argv == '-')
{
char *p;
for (p = argv[0] + 1; *p; ++p)
{
if (*p == 'E')
detach_char = -1;
else if (*p == 'z')
no_suspend = 1;
else if (*p == 'e')
{
++argv; --argc;
if (argc < 1)
{
printf("%s: No escape character "
"specified.\n", progname);
printf("Try '%s --help' for more "
"information.\n", progname);
return 1;
}
if (argv[0][0] == '^' && argv[0][1])
{
if (argv[0][1] == '?')
detach_char = '\177';
else
detach_char = argv[0][1] & 037;
}
else
detach_char = argv[0][0];
break;
}
else if (*p == 'r')
{
++argv; --argc;
if (argc < 1)
{
printf("%s: No redraw method "
"specified.\n", progname);
printf("Try '%s --help' for more "
"information.\n", progname);
return 1;
}
if (strcmp(argv[0], "none") == 0)
redraw_method = REDRAW_NONE;
else if (strcmp(argv[0], "ctrl_l") == 0)
redraw_method = REDRAW_CTRL_L;
else if (strcmp(argv[0], "winch") == 0)
redraw_method = REDRAW_WINCH;
else
{
printf("%s: Invalid redraw method "
"specified.\n", progname);
printf("Try '%s --help' for more "
"information.\n", progname);
return 1;
}
break;
}
else
{
printf("%s: Invalid option '-%c'\n",
progname, *p);
printf("Try '%s --help' for more information.\n",
progname);
return 1;
}
}
++argv; --argc;
}
if (mode != 'a' && argc < 1)
{
printf("%s: No command was specified.\n", progname);
printf("Try '%s --help' for more information.\n",
progname);
return 1;
}
/* Save the original terminal settings. */
if (tcgetattr(0, &orig_term) < 0)
{
memset(&orig_term, 0, sizeof(struct termios));
dont_have_tty = 1;
}
if (dont_have_tty && mode != 'n' && mode != 'N')
{
printf("%s: Attaching to a session requires a terminal.\n",
progname);
return 1;
}
if (mode == 'a')
{
if (argc > 0)
{
printf("%s: Invalid number of arguments.\n",
progname);
printf("Try '%s --help' for more information.\n",
progname);
return 1;
}
return attach_main(0);
}
else if (mode == 'n')
return master_main(argv, 0, 0);
else if (mode == 'N')
return master_main(argv, 0, 1);
else if (mode == 'c')
{
if (master_main(argv, 1, 0) != 0)
return 1;
return attach_main(0);
}
else if (mode == 'A')
{
/* Try to attach first. If that doesn't work, create a new
** socket. */
if (attach_main(1) != 0)
{
if (errno == ECONNREFUSED || errno == ENOENT)
{
if (errno == ECONNREFUSED)
unlink(sockname);
if (master_main(argv, 1, 0) != 0)
return 1;
}
return attach_main(0);
}
}
return 0;
}