/* Test whether a basic tcgetwinsize invocation works. */

#include <sys/ioctl.h>
#include <sys/wait.h>

#include <fcntl.h>
#include <signal.h>
#include <stdlib.h>
#include <termios.h>
#include <unistd.h>

#include "../basic.h"

static volatile sig_atomic_t received;

void on_signal(int signo)
{
	received = signo;
}

int main(void)
{
	int controller = posix_openpt(O_RDWR | O_NOCTTY);
	if ( controller < 0 )
		err(1, "posix_openpt");
	if ( grantpt(controller) < 0 )
		err(1, "grantpt");
	if ( unlockpt(controller) < 0 )
		err(1, "unlockpt");
	char* name = ptsname(controller);
	if ( !name )
		err(1, "unlockpt");
	pid_t session = fork();
	if ( session < 0 )
		err(1, "fork");
	if ( !session )
	{
		close(controller);
		if ( setsid() < 0 )
			err(1, "setsid");
		int pty = open(name, O_RDWR);
		if ( pty < 0 )
			err(1, "%s", name);
#ifdef TIOCSCTTY
		if ( ioctl(pty, TIOCSCTTY, 0) < 0 && errno != ENOTTY )
			err(1, "ioctl: TIOCSCTTY");
#endif
		struct winsize ws = { .ws_row = 24, .ws_col = 80 };
		struct sigaction sa = { .sa_handler = on_signal };
		if ( sigaction(SIGWINCH, &sa, NULL) < 0 )
			err(1, "sigaction");
		if ( tcsetwinsize(pty, &ws) < 0 )
			err(1, "tcsetwinsize");
		if ( received != SIGWINCH )
			errx(1, "SIGWINCH was not received");
		struct winsize new_ws;
		if ( tcgetwinsize(pty, &new_ws) < 0 )
			err(1, "tcgetwinsize");
		if ( new_ws.ws_row != ws.ws_row || new_ws.ws_col != ws.ws_col )
			errx(1, "tcgetwinsize gave wrong size");
		exit(0);
	}
	int status;
	if ( waitpid(session, &status, 0) < 0 )
		err(1, "waitpid");
	close(controller);
	if ( WIFEXITED(status) )
		return WEXITSTATUS(status);
	else if ( WIFSIGNALED(status) )
		errx(1, "%s", strsignal(WTERMSIG(status)));
	else
		errx(1, "unknown exit: %#x", status);
	return 0;
}
