/* DF-2551 -- fhopen() returns success(0) without installing an fd when
 * the VREG vnode has v_object == NULL (vfs_syscalls.c:4933-4941 -> bad_drop
 * with error still 0).  Empirical probe: getfh() a file, fhopen() it,
 * compare returned fd validity.
 *
 * usage: fhopen_probe path
 */
#include <sys/param.h>
#include <sys/mount.h>
#include <sys/fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>

int
main(int argc, char **argv)
{
	struct fhandle fh;
	int fd, rc;

	if (argc != 2) { fprintf(stderr, "usage: %s path\n", argv[0]); return 2; }

	memset(&fh, 0, sizeof(fh));
	rc = getfh(argv[1], &fh);
	if (rc < 0) { printf("getfh(%s): %s\n", argv[1], strerror(errno)); return 1; }
	printf("getfh(%s): ok (fh_len=%zu)\n", argv[1], sizeof(fh));

	/* close 0..2 noise: use a known-good base */
	fd = fhopen(&fh, O_RDWR);
	printf("fhopen(O_RDWR)      = %d errno=%d (%s)\n", fd, errno,
	    fd >= 0 ? "fd" : strerror(errno));
	if (fd >= 3) {
		char b[16];
		ssize_t n = pread(fd, b, sizeof(b), 0);
		printf("  pread on fd -> %zd (errno %d)\n", n, errno);
		close(fd);
	} else if (fd == 0 || fd == 1 || fd == 2) {
		printf("  !! fd value overlaps std fd %d\n", fd);
	} else {
		printf("  !! error %d (%s)\n", fd, strerror(-fd));
	}

	/* read-only open of file opened O_RDWR fh */
	fd = fhopen(&fh, O_RDONLY);
	printf("fhopen(O_RDONLY)    = %d errno=%d (%s)\n", fd, errno,
	    fd >= 0 ? "fd" : strerror(errno));
	if (fd >= 3) close(fd);

	/* is the returned descriptor REALLY the file?  fd 0 dup probe */
	return 0;
}
