Fixing a problem on savefile (stdin was not saved well, and the file not
truncated)
/*
Terminal Mixer - multi-point multi-user access to terminal applications
Copyright (C) 2007 LluĂs Batlle i Rossell
Please find the license in the provided COPYING file.
*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/select.h>
#include "main.h"
#include "handlers.h"
extern char *optarg;
extern int optind, opterr, optopt;
/* From main.h given external */
int app_stdin;
int app_stdout;
int app_stderr;
struct Command_line command_line;
static const char version[] = "0.4.1";
static int showhelp(const char *pname)
{
printf("tm v%s - terminal mixer, Copyright (C) 2007 "
"Lluis Batlle i Rossell\n",
version);
printf("usage: %s [opts] [appcommand] [param1] [param2] ...\n", pname);
printf(" If you give _appcommand_, it starts the application and\n");
printf(" serves it through a Unix socket on $TM_SOCKET or "
"/tmp/tm-socket.UID,\n");
printf(" unless '-p' is used.\n");
printf(" Without _appcomand_, starts a the Unix socket client.\n");
printf("options: \n");
printf(" -h Show help.\n");
printf(" -P Run the child as connected to a pipe (default).\n");
printf(" -t Run the child as connected to a terminal (raw mode in "
"client).\n");
printf(" -n Unlink the program from the terminal (as 'nohup').\n");
printf(" -N MAX Serve at most MAX sockets for each transport (1 default)."
"\n");
printf(" -w The remote clients can write to the application.\n");
printf(" -C The remote clients end will close app's stdin.\n");
printf(" -p NUM Listen to tcp port NUM for 'telnet', and not listen to "
"any\n"
" Unix socket.\n");
printf(" -E Echo remote input to the server terminal.\n");
#ifdef linux
printf(" -e dev[:port] Also serve/connect using raw ethernet, device 'dev'.\n");
printf(" -c adr Connect to address (MAC if eth).\n");
printf(" -s fil Save the child stdin/stdout to the filename 'fil'.\n");
#endif /* linux */
printf(" -x Send xterm's resize control string to clients.\n");
return 0;
}
static int my_getopt(int argc, char * argv[], const char *optstring)
{
char *old_getopt_env;
static char getopt_env[100] = "POSIXLY_CORRECT=YES";
int res;
old_getopt_env = getenv("POSIXLY_CORRECT");
putenv(getopt_env);
res = getopt(argc, argv, optstring);
if (old_getopt_env == 0)
{
putenv("POSIXLY_CORRECT");
}
else
snprintf(getopt_env, sizeof getopt_env, "POSIXLY_CORRECT=%s",
old_getopt_env);
return res;
}
static void parse_eth_device(char *str)
{
char *p;
for (p = str; *p != 0 && *p != ':'; ++p);
if (*p == ':')
{
*p = '\0'; /* We want only the eth device name in str */
++p;
command_line.eth_port = atoi(p);
}
/* The string will not have any colon or port. */
command_line.eth_device = strdup(str);
}
static void default_command_line()
{
command_line.is_server = 0;
command_line.s_param.use_blocking_sockets = 1;
command_line.s_param.run_in_subterminal = 0;
command_line.s_param.max_served = 1;
command_line.s_param.serve_unix = 1;
command_line.s_param.serve_tcp = 0;
command_line.s_param.send_xterm_resize = 1;
command_line.s_param.client_may_close_app_stdin = 0;
command_line.s_param.nohup = 0;
command_line.s_param.client_can_write = 0;
command_line.s_param.echo_in_local_terminal = 0;
command_line.s_param.send_xterm_resize = 0;
command_line.s_param.serve_eth = 0;
command_line.s_param.savefile = 0;
command_line.tcp_port = 40000; /* Arbitrary */
command_line.eth_port = 100; /* Arbitrary */
command_line.buffer_size = 4096; /* Arbitrary */
command_line.eth_device = 0;
get_unix_path(); /* for command_line.unix_path */
command_line.c_param.transport = UNIX;
command_line.c_param.wait_until_char = -1;
command_line.c_param.raw_mode = 0;
command_line.c_param.server_address = 0; /* TODO: free it */
}
static int parse_opts(int argc, char * argv[])
{
int c;
extern char *optarg;
extern int optind, opterr, optopt;
while(1) {
c = my_getopt(argc, argv, "s:tp:nBxdPN:hwCED"
#ifdef linux
"c:e:"
#endif /* linux */
);
if (c == -1)
break;
switch(c)
{
case 't':
command_line.s_param.run_in_subterminal = 1;
command_line.c_param.raw_mode = 1;
break;
case 'P':
command_line.s_param.run_in_subterminal = 0;
break;
case 'B':
command_line.s_param.use_blocking_sockets = 0;
break;
case 'n':
command_line.s_param.nohup = 1;
break;
case 'p':
command_line.tcp_port = atoi(optarg);
command_line.s_param.serve_tcp = 1;
command_line.s_param.serve_unix = 0;
break;
case 'N':
command_line.s_param.max_served = atoi(optarg);
break;
case 'c':
command_line.c_param.server_address = strdup(optarg);
break;
case 'h':
showhelp(argv[0]);
exit(0);
break;
case 'w':
command_line.s_param.client_can_write = 1;
break;
case 'C':
command_line.s_param.client_may_close_app_stdin = 1;
break;
case 'x':
command_line.s_param.send_xterm_resize = 1;
break;
case 'E':
command_line.s_param.echo_in_local_terminal = 1;
break;
case 'D':
should_dump = 1;
break;
case 'e':
command_line.s_param.serve_eth = 1;
command_line.s_param.serve_unix = 0;
parse_eth_device(optarg);
command_line.c_param.transport = ETHERNET;
break;
case 's':
command_line.s_param.savefile = strdup(optarg);
break;
case '?':
error("Wrong option %c.\n", optopt);
}
}
if (command_line.s_param.use_blocking_sockets == 0)
not_implemented("Not using blocking sockets.");
if (optind < argc)
{
command_line.is_server = 1;
command_line.s_param.command = &argv[optind];
}
return 0;
}
int main(int argc, char * argv[])
{
int res;
default_command_line();
parse_opts(argc, argv);
init_stream_buffers();
if (command_line.is_server)
res = server();
else
res = client();
return res;
}