mirror of
https://github.com/kaboomserver/buildpack.git
synced 2024-09-29 19:53:13 +00:00
285 lines
7.1 KiB
C
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;
|
||
|
}
|