/*
 *  shell-on -- 指定したttyでシェルを起動する
 *
 *	0.0: May  5, 2014 by Dai ISHIJIMA
 *
 *  usage:
 *	shell-on tty [command [args]...]
 *
 *  see also:
 *	/usr/src/usr.sbin/sysinstall/system.c
 */

#include <stdio.h>
#include <stdlib.h>
#include <termios.h>
#include <sys/types.h>
#include <unistd.h>
#include <libutil.h>	/* login_tty(3), -lutil */
#include <fcntl.h>
#include <signal.h>


int main(int argc, char *argv[])
{
    int pid;
    char *tty;
    int fd;
    int i;
    char *prog;
    char *shell;
    char **args;

    prog = argv[0];
    if (argc <= 1) {
	fprintf(stderr, "Usage: %s tty [command [arg]...]\n", prog);
	exit(1);
    }
    tty = argv[1];
    if ((fd = open(tty, O_RDWR)) < 0) {
	fprintf(stderr, "%s: can't open %s\n", prog, tty);
	exit(1);
    }
    close(fd);
    args = (char **)calloc(argc, sizeof(char *));
    if (argc <= 2) {	/* オプションなし→シェル */
	shell = "sh";
	args[0] = "-sh";
	args[1] = NULL;
    }
    else {
	shell = argv[2];
	for (i = 0; i < argc - 2; i++) {
	    args[i] = argv[2 + i];
	}
	args[i] = NULL;
    }
#ifdef EBUG
    fprintf(stderr, "%s: tty = %s, shell = %s\n", prog, tty, shell);
    i = 0;
    while (args[i] != NULL) {
	fprintf(stderr, "%s\n", args[i]);
	++i;
    }
#endif
    if ((pid = fork()) == 0) {	/* 子供 */
	int cfd;
	int fd;
	struct termios t;

	ioctl(0, TIOCNOTTY, NULL);
	for (cfd = 0; cfd < getdtablesize(); cfd++) {
	    close(cfd);
	}
	if ((fd = open(tty, O_RDWR)) < 0) {
	    exit(1);
	}
	ioctl(0, TIOCSCTTY, &fd);
	dup2(0, 1);
	dup2(0, 2);
	if (login_tty(fd) < 0) {
	    exit(1);
	}
	signal(SIGTTOU, SIG_IGN);
	if (tcgetattr(fd, &t) < 0) {
	    fprintf(stderr, "unable to get terminal attributes\n");
	}
	else {
	    t.c_cc[VERASE] = '\010';
	    if (tcsetattr(fd, TCSANOW, &t) < 0) {
		fprintf(stderr, "unable to set terminal attributes\n");
	    }
	}
	execvp(shell, args);
	fprintf(stderr, "unable to execute sh\n");
	exit(1);
    }
    exit(0);
}

/* Local Variables: */
/* compile-command:"cc -Wall -o shell-on shell-on.c -lutil" */
/* End: */
