/* ttyprobe.c -- DF-3533: v1 ng_tty failed-open path.
 * Pre-create a netgraph node named "ttyN" to force ng_name_node() failure
 * inside ngt_open(), then TIOCSETD netgraph on a pty slave:
 *  - 1st TIOCSETD: expect error (name collision) -> error path runs
 *    ng_rmnode -> ngt_shutdown frees sc while tp->t_sc still points at it
 *    (latent dangling; no dispatch should occur -> no crash).
 *  - 2nd TIOCSETD: name now free -> expect success (t_sc replaced).
 *  - Final TIOCSETD back to ttydisc (0): cleanup.
 */
#include <sys/types.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <termios.h>
#include <sys/ttycom.h>

int main(int argc, char **argv)
{
	int mfd, sfd, disc, old;
	char pts[128];

	mfd = open("/dev/ptmx", O_RDWR);
	if (mfd < 0) { perror("ptmx"); return 1; }
	if (grantpt(mfd) < 0 || unlockpt(mfd) < 0) { perror("grant/unlock"); return 1; }
	{ char *pp = ptsname(mfd); if (pp == NULL) { perror("ptsname"); return 1; } strlcpy(pts, pp, sizeof(pts)); }
	sfd = open(pts, O_RDWR | O_NOCTTY);
	if (sfd < 0) { perror(pts); return 1; }
	if (ioctl(sfd, TIOCGETD, &old) < 0) { perror("TIOCGETD"); return 1; }
	printf("slave %s initial line discipline: %d\n", pts, old);

	disc = NETGRAPHDISC;
	errno = 0;
	int rc = ioctl(sfd, TIOCSETD, &disc);
	printf("TIOCSETD NETGRAPHDISC #1 (colliding node exists): rc=%d errno=%d (%s)\n",
	    rc, errno, rc ? strerror(errno) : "ok");
	if (ioctl(sfd, TIOCGETD, &disc) == 0)
		printf("discipline now: %d (expected unchanged %d)\n", disc, old);

	/* second attempt: node name tty1 free -> should succeed */
	errno = 0;
	rc = ioctl(sfd, TIOCSETD, &disc);
	printf("TIOCSETD NETGRAPHDISC #2: rc=%d errno=%d (%s)\n",
	    rc, errno, rc ? strerror(errno) : "ok");
	if (ioctl(sfd, TIOCGETD, &disc) == 0)
		printf("discipline now: %d\n", disc);

	/* write garbage through the tty while ng discipline active (no crash
	 * expected; exercises ngt_input on the LIVE sc) */
	if (disc == NETGRAPHDISC) {
		write(sfd, "hello-netgraph-tty\r\n", 20);
		printf("wrote 20 bytes through ng discipline: no crash\n");
	}

	/* restore */
	disc = old;
	rc = ioctl(sfd, TIOCSETD, &disc);
	printf("restore discipline %d: rc=%d\n", old, rc);
	printf("TTYPROBE-DONE guest alive\n");
	return 0;
}
