Merging the savefile branch. I hope it works; I even don't remember it.
/*
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 <sys/types.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <string.h>
#include <sys/select.h>
#include <sys/ioctl.h>
#include <termios.h>
#ifdef __APPLE__
#include <util.h>
#else
#include <pty.h>
#endif
#include "main.h"
struct winsize app_winsize; /* for xterm.c */
enum
{
STDIN,
STDOUT,
STDERR
};
static void set_close_on_exec(int fd)
{
int res;
res = fcntl(fd, F_SETFD, FD_CLOEXEC);
if (res == -1)
error("Set close-on-exec failed");
}
void pass_winsize_to_slave()
{
int res;
res = ioctl(0, TIOCGWINSZ, (char *) &app_winsize);
if (res >= 0)
ioctl(app_stdin, TIOCSWINSZ, (char *) &app_winsize);
}
void get_term_options(struct termios *tios, struct winsize *wsize)
{
int res;
/* Try to get the config from the actual terminal's stdout */
res = tcgetattr(1, tios);
if (res == -1)
{
/* Create the termios structure from scratch */
memset(tios, 0, sizeof(*tios));
cfmakeraw(tios);
}
/* if starting using shells' &, it doesn't get ECHO set.
* Let's force it. */
tios->c_lflag |= ECHO | ECHOE | ECHOK | ECHONL;
/* Try to emulate something compatible with xterm */
tios->c_oflag |= OPOST | ONLCR;
tios->c_lflag |= ISIG | ICANON | ECHOCTL | ECHOKE;
tios->c_iflag |= BRKINT | IGNPAR | IMAXBEL;
/* Get the original term's winsize */
res = ioctl(1, TIOCGWINSZ, wsize);
if (res == -1)
{
/* If we don't have original term, create an arbitrary winsize */
wsize->ws_row = 25;
wsize->ws_col = 80;
}
}
static void give_terminal(int parent[], int child[])
{
struct termios tios;
struct winsize wsize;
int res;
int master, slave;
get_term_options(&tios, &wsize);
app_winsize = wsize;
res = openpty(&master, &slave, 0, &tios, &wsize);
if (res == -1)
error("openpty");
parent[STDIN] = master;
parent[STDOUT] = master;
parent[STDERR] = master;
child[STDIN] = slave;
child[STDOUT] = slave;
child[STDERR] = slave;
set_close_on_exec(master);
set_close_on_exec(slave);
}
static void give_pipes(int parent[], int child[])
{
int p_stdin[2]; /* from us to mpg321 */
int p_stdout[2]; /* from mpg321 to us */
int p_stderr[2]; /* from mpg321 to us, its stderr */
pipe(p_stdin);
pipe(p_stdout);
pipe(p_stderr);
parent[STDIN] = p_stdin[1];
parent[STDOUT] = p_stdout[0];
parent[STDERR] = p_stderr[0];
child[STDIN] = p_stdin[0];
child[STDOUT] = p_stdout[1];
child[STDERR] = p_stderr[1];
set_close_on_exec(parent[STDIN]);
set_close_on_exec(parent[STDOUT]);
set_close_on_exec(parent[STDERR]);
set_close_on_exec(child[STDIN]);
set_close_on_exec(child[STDOUT]);
set_close_on_exec(child[STDERR]);
}
int fork_app(char * const command[])
{
int p_parent[3];
int p_child[3];
int pid;
int res;
if (command_line.s_param.run_in_subterminal)
{
give_terminal(p_parent, p_child);
}
else
give_pipes(p_parent, p_child);
/* globals */
app_stdin = p_parent[STDIN]; /* For us to write */
app_stdout = p_parent[STDOUT]; /* For us to read */
app_stderr = p_parent[STDERR]; /* For us to read */
pid = fork();
switch(pid)
{
case 0: /* child */
if (command_line.s_param.nohup)
ignore_sighup();
res = dup2(p_child[STDIN], 0);
if (res == -1) error("Dup2 stdin");
res = dup2(p_child[STDOUT], 1);
if (res == -1) error("Dup2 stdout");
res = dup2(p_child[STDERR], 2);
if (res == -1) error("Dup2 stderr");
if (command_line.s_param.run_in_subterminal)
{
int res;
res = setsid();
if (res < 0)
error("failed setsid()");
res = ioctl(0, TIOCSCTTY, 0);
if (res < 0)
error("failed ioctl(0,TIOCSCTTY,0)");
}
execvp(command[0], command);
error("Cannot execvp %s", command[0]);
case -1:
error("Failed fork");
default: /* parent */
close(p_child[STDIN]);
close(p_child[STDOUT]);
close(p_child[STDERR]);
}
return pid;
}