/* vim: set shiftwidth=4 tabstop=8 softtabstop=4: */
/* $Id: test.c,v 1.14 2003/12/06 18:43:01 shinra Exp $ */
#define LIBSPT_STATIC
#include "sptprivate.h"
#include <stdio.h>
#include <sys/param.h>
#include <signal.h>
#include <sys/ioctl.h>
#include <sys/wait.h>
#if defined(HAVE_TERMIOS_H)
# include <termios.h> /* for TIOCGWINSZ on sun */
#endif

/*
 * This is a test program; *NOT* a sample program.
 */
int
main(int argc, char *const argv[])
{
    int r;
    spt_handle *phandle;
    int masterfd, slavefd;
    int i;
    int use_installed = 0;
    spt_termios *oldtio, *newtio;

    for (i = 1; i < argc; ++i) {
	if (!strcmp(argv[i], "-i"))
	    use_installed = 1;
    }
    errno = 0;
    if (!use_installed)
	spt_set_agent_path("./sptagent");
    spt_termios_alloc(&oldtio);
    spt_termios_alloc(&newtio);
    r = spt_termios_get(oldtio, 0);
    if (r) {
	perror("tcgetattr");
	spt_free_obj(oldtio);
	spt_free_obj(newtio);
	return 1;
    }
    r = spt_open_pty(&phandle, &masterfd, NULL, NULL);
    perror(NULL);
    spt_perror(NULL, r);
    if (!r || r == SPT_E_CHOWN_FAIL) {
	pid_t pid;
	slavefd = spt_open_slave(phandle);
	if (slavefd < 0) {
	    perror("open slave");
	    spt_free_obj(oldtio);
	    spt_free_obj(newtio);
	    spt_close_pty(phandle);
	    return 1;
	}
	fprintf(stderr, "slavefd = %d\n", slavefd);
	spt_perror("init_slavefd", spt_init_slavefd(phandle, slavefd));
	spt_termios_default(newtio);
	spt_perror("termios_set(slave)", spt_termios_set(newtio, slavefd));
	pid = fork();
	if (pid == 0) {
#ifdef TIOCGWINSZ
	    struct winsize wsize;
#endif
	    spt_detach_handle(phandle);
	    close(masterfd);
#ifdef TIOCGWINSZ
	    ioctl(0, TIOCGWINSZ, &wsize);
	    ioctl(slavefd, TIOCSWINSZ, &wsize);
#endif
	    errno = 0;
	    if ((r = spt_detach_ctty())) {
		spt_perror(NULL, r);
		perror("detachctty");
		_exit(1);
	    }
	    if ((r = spt_set_ctty2(slavefd))) {
		spt_perror(NULL, r);
		perror("setctty");
		_exit(1);
	    }
	    spt_free_obj(oldtio);
	    spt_free_obj(newtio);
	    dup2(slavefd, 0);
	    dup2(slavefd, 1);
	    dup2(slavefd, 2);
	    close(slavefd);
	    execl("/bin/sh", "-sh", NULL);
	    /* NOTREACHED */
	    perror(NULL);
	    _exit(1);
	} else {
	    int exit_st = 0;
	    close(slavefd);
	    signal(SIGINT, SIG_IGN);
	    spt_utmp_set_host(phandle, "testhost");
	    spt_utmp_set_pid(phandle, pid);
	    spt_perror("login_utmp", spt_login_utmp(phandle));
	    spt_perror("login_wtmp", spt_login_wtmp(phandle));
	    spt_perror("update_lastlog", spt_update_lastlog(phandle));
	    spt_termios_copy(newtio, oldtio);
	    spt_termios_raw(newtio);
	    r = spt_termios_sset(newtio, 0, oldtio);
	    if (r) {
		perror("termios_sset");
		spt_perror("termios_sset", r);
		spt_close_pty(phandle);
		spt_free_obj(newtio);
		spt_free_obj(oldtio);
		exit(1);
	    }
	    while (1) {
		int rr;
		char buf[30];
		fd_set fds;
		FD_ZERO(&fds);
		FD_SET(masterfd, &fds);
		FD_SET(0, &fds);
		rr = select(masterfd + 1, &fds, NULL, NULL, NULL);
		if (rr <= 0)
		    break;
		if (FD_ISSET(masterfd, &fds)) {
		    r = read(masterfd, buf, sizeof buf);
		    if (r <= 0)
			break;
		    write(1, buf, r);
		}
		if (FD_ISSET(0, &fds)) {
		    r = read(0, buf, sizeof buf);
		    if (r <= 0)
			break;
		    if (buf[0] == '!')
			break;
		    write(masterfd, buf, r);
		}
	    }
	    spt_perror("termios_set(restore)", spt_termios_set(oldtio, 0));
	    kill(pid, SIGTERM);
	    if (waitpid(pid, &exit_st, WNOHANG) != pid) {
		usleep(50000);
		kill(pid, SIGKILL);
		if (waitpid(pid, &exit_st, WNOHANG) != pid) {
		    sleep(1);
		    if (waitpid(pid, &exit_st, WNOHANG) != pid)
			fprintf(stderr, "warning: wait failed\n");
		}
	    }
	    fprintf(stderr, "exit status=%d,%d\n",
		    WTERMSIG(exit_st), WEXITSTATUS(exit_st));
	    spt_utmp_set_exit(phandle, exit_st);
	    spt_perror("logout_utmp", spt_logout_utmp(phandle));
	    spt_perror("logout_wtmp", spt_logout_wtmp(phandle));
	    spt_close_pty(phandle);
	    spt_free_obj(newtio);
	    spt_free_obj(oldtio);
	    MEMORY_REPORT();
	    return 0;
	}
    }
    return r;
}
