/*
 * DF-2768 probe stage 3: cycle the OOB unit N times while holding
 * units 0..999.  Each cycle:
 *   - open ptmx #1001  -> clone creates unit-1000 pty (ptis[1000] OOB),
 *     master open fails ENODEV
 *   - open /dev/pts/1000 (O_NONBLOCK) then close it -> forces ptsclose ->
 *     pti_done -> termination -> bitmap_put(1000)
 * If the ptis[1000] OOB write persisted, every subsequent cycle REUSES
 * the same pti -> M_PTY 'ptys' count stays +1.  If each cycle allocates
 * a new pti, the count grows by 1 per cycle.
 */
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#define MAXPTYS 1000

static void
timeout(int sig __unused)
{
	fprintf(stderr, "ALARM: hung\n");
	_exit(9);
}

int
main(int argc, char **argv)
{
	int cycles = (argc > 1) ? atoi(argv[1]) : 5;
	int held[MAXPTYS];
	int i, fd, c;

	signal(SIGALRM, timeout);

	for (i = 0; i < MAXPTYS; i++) {
		if ((held[i] = open("/dev/ptmx", O_RDWR)) < 0) {
			printf("pre-fill #%d failed: %s\n", i, strerror(errno));
			return 1;
		}
	}
	printf("holding %d ptys; cycling OOB unit %d times\n", MAXPTYS, cycles);

	for (c = 0; c < cycles; c++) {
		errno = 0;
		alarm(15);
		fd = open("/dev/ptmx", O_RDWR);
		alarm(0);
		printf("cycle %d: ptmx #1001 -> %s(%d)\n", c,
		    fd >= 0 ? "OPENED" : strerror(errno), errno);
		fflush(stdout);
		if (fd >= 0)
			close(fd);

		alarm(15);
		fd = open("/dev/pts/1000", O_RDWR | O_NONBLOCK);
		alarm(0);
		if (fd < 0) {
			printf("cycle %d: open /dev/pts/1000 failed: %s(%d)\n",
			    c, strerror(errno), errno);
		} else {
			close(fd);
			printf("cycle %d: /dev/pts/1000 opened+closed\n", c);
		}
		fflush(stdout);
	}
	printf("done; exiting (holds released)\n");
	fflush(stdout);
	sleep(1);
	return 0;
}
