Subject: Sample ptyfs implementation, feedback requested
To: None <tech-kern@netbsd.org>
From: Christos Zoulas <christos@zoulas.com>
List: tech-kern
Date: 11/07/2004 17:25:20
Hello,

This is work in progress for a ptyfs implementation. To use it, untar the
tar file apply the patch, build a new kernel and reboot. You can build and
modload the ptyfs lkm, and then mkdir /dev/pts, mount_ptyfs /dev/pts /dev/pts.

Why I did this:

1. I wanted to get rid of all the tty and pty files in /dev
2. It is needed for compat_linux (new matlab)
3. I wanted to learn more about filesystems

This is experimental code and things don't work properly.

What works:
	- script, window, screen
What does not work:
	- xterm -- starts the pty up, but then it the master parts dies
	  in ptcwrite with EIO
	- sshd -- starts up the shell in the pty, but somehow tcsh prints
	  that it cannot do job control.

Implementation notes:

1. I split the code in tty_pty.c into:
	tty_pty.c -- basic pty code.
	tty_ptm.c -- /dev/ptm /dev/ptmx
	tty_bsdpty.c -- /dev/ptyXX /dev/ttyXX pty allocation code for ptmx
	sys/pty.h -- variables shared between ptyfs and the rest.
2. There are two functions that describe the interface for ptm to create
   ptys (in sys/pty.h). A makename function and an allocvp function. Both
   the bsdpty and the ptyfs implementation use them. Once you mount the
   ptyfs filesystem, it replaces the bsdpty implementation with the ptyfs
   one, and once you unmount it, it puts back the original.
3. I wanted the old bsd ptys to co-exist with /dev/pts. For that when ptyfs
   starts up, it will copy the permissions from /dev/ptyXX and /dev/ttyXX
   for its nodes. 
4. I did not like the way ttyname() worked with looking up the db file,
   so I let the ioctl to find the pty name work on the slave too. Now
   ttyname() will do the ioctl first to find the ttyname. If that fails,
   then it will lookup in the db. This is a lot faster in the regular
   case these days which is ptys. It is also silly to have entries for
   all the ptys in /etc/ttys. You can now remove them, and the code
   will take up the last + 1 slot for each pty (for either the old
   or the new ptys).
5. I have not done anything about printing the correct pty name in utmp/utmpx
   fields. This is easy to be fixed, and I will do so when all the kernel
   part works. My plan is to print the pty short names as pN where N is the
   minor number of the pty.
6. The ioctl to retrieve the pty name and file descriptor returned the
   names of the master and slave parts and the fd's associated with them.
   Under ptyfs, there is no filesystem node for the master portion, only
   the slave one. I don't think that we should create one for the master
   side. I populate the structure with /dev/null for now.

Please let me know what you think,

christos
Index: lib/libc/gen/ttyname.c
===================================================================
RCS file: /cvsroot/src/lib/libc/gen/ttyname.c,v
retrieving revision 1.19
diff -u -u -r1.19 ttyname.c
--- lib/libc/gen/ttyname.c	7 Aug 2003 16:42:58 -0000	1.19
+++ lib/libc/gen/ttyname.c	7 Nov 2004 22:23:20 -0000
@@ -51,12 +51,14 @@
 #include <string.h>
 #include <termios.h>
 #include <unistd.h>
+#include <sys/ioctl.h>
 
 #ifdef __weak_alias
 __weak_alias(ttyname,_ttyname)
 #endif
 
 static char buf[sizeof(_PATH_DEV) + MAXNAMLEN] = _PATH_DEV;
+static struct ptmget ptm;
 static char *oldttyname __P((struct stat *));
 
 char *
@@ -74,6 +76,10 @@
 
 	_DIAGASSERT(fd != -1);
 
+	/* If it is a pty, deal with it quickly */
+	if (ioctl(fd, TIOCPTSNAME, &ptm) != -1)
+		return ptm.sn;
+
 	/* Must be a terminal. */
 	if (tcgetattr(fd, &ttyb) < 0)
 		return (NULL);
Index: lib/libc/gen/ttyslot.c
===================================================================
RCS file: /cvsroot/src/lib/libc/gen/ttyslot.c,v
retrieving revision 1.11
diff -u -u -r1.11 ttyslot.c
--- lib/libc/gen/ttyslot.c	7 Aug 2003 16:42:58 -0000	1.11
+++ lib/libc/gen/ttyslot.c	7 Nov 2004 22:23:20 -0000
@@ -44,34 +44,51 @@
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
 
 #ifdef __weak_alias
 __weak_alias(ttyslot,_ttyslot)
 #endif
 
 int
-ttyslot()
+ttyslot(void)
 {
 	struct ttyent *ttyp;
-	int slot;
+	int slot = 0, ispty = 0;
 	char *p;
 	int cnt;
 	char *name;
+	struct ptmget ptm;
 
 	setttyent();
-	for (cnt = 0; cnt < 3; ++cnt) 
-		if ((name = ttyname(cnt)) != NULL) {
-			if ((p = strrchr(name, '/')) != NULL)
-				++p;
-			else
-				p = name;
-			for (slot = 1; (ttyp = getttyent()) != NULL; ++slot)
-				if (!strcmp(ttyp->ty_name, p)) {
-					endttyent();
-					return(slot);
-				}
-			break;
-		}
+	for (cnt = 0; cnt < 3; ++cnt) {
+		if (ioctl(cnt, TIOCPTSNAME, &ptm) != -1) {
+			ispty = 1;
+			name = ptm.sn;
+		} else if ((name = ttyname(cnt)) != NULL) {
+			ispty = 0;
+		} else
+			continue;
+
+		if ((p = strrchr(name, '/')) != NULL)
+			++p;
+		else
+			p = name;
+
+		for (slot = 1; (ttyp = getttyent()) != NULL; ++slot)
+			if (!strcmp(ttyp->ty_name, p)) {
+				endttyent();
+				return slot;
+			}
+		break;
+	}
 	endttyent();
-	return(0);
+	if (ispty) {
+		struct stat st;
+		if (fstat(cnt, &st) == -1)
+			return 0;
+		return slot + minor(st.st_rdev) + 1;
+	}
+	return 0;
 }
Index: regress/lib/libc/pty/ptm/ptm.c
===================================================================
RCS file: /cvsroot/src/regress/lib/libc/pty/ptm/ptm.c,v
retrieving revision 1.2
diff -u -u -r1.2 ptm.c
--- regress/lib/libc/pty/ptm/ptm.c	27 May 2004 03:18:19 -0000	1.2
+++ regress/lib/libc/pty/ptm/ptm.c	7 Nov 2004 22:23:20 -0000
@@ -71,23 +71,28 @@
 		err(1, "ioctl(TIOCPTMGET)");
 
 	if (strncmp(ptm.cn, "/dev/pty", 8) != 0)
-		errx(1, "bad master name %s", ptm.cn);
+		if (strncmp(ptm.cn, "/dev/null", 9) != 0)
+			errx(1, "bad master name %s", ptm.cn);
 
 	if (strncmp(ptm.sn, "/dev/tty", 8) != 0)
+		if (strncmp(ptm.sn, "/dev/pts/", 9) != 0)
 		errx(1, "bad slave name %s", ptm.sn);
 
-	if (fstat(ptm.cfd, &stm) == -1)
-		err(1, "fstat master");
-	if (stat(ptm.cn, &sts) == -1)
-		err(1, "stat master");
-	if (stm.st_rdev != sts.st_rdev)
-		errx(1, "master device mismatch %lu != %lu",
-		    (unsigned long)stm.st_rdev, (unsigned long)sts.st_rdev);
+	if (strncmp(ptm.cn, "/dev/null", 9) != 0) {
+		if (fstat(ptm.cfd, &stm) == -1)
+			err(1, "fstat master");
+		if (stat(ptm.cn, &sts) == -1)
+			err(1, "stat master");
+		if (stm.st_rdev != sts.st_rdev)
+			errx(1, "master device mismatch %lu != %lu",
+			    (unsigned long)stm.st_rdev,
+			    (unsigned long)sts.st_rdev);
+	}
 
 	if (fstat(ptm.sfd, &stm) == -1)
-		err(1, "fstat master");
+		err(1, "fstat slave");
 	if (stat(ptm.sn, &sts) == -1)
-		err(1, "stat master");
+		err(1, "stat slave");
 	if (stm.st_rdev != sts.st_rdev)
 		errx(1, "slave device mismatch %lu != %lu",
 		    (unsigned long)stm.st_rdev, (unsigned long)sts.st_rdev);
Index: sbin/Makefile
===================================================================
RCS file: /cvsroot/src/sbin/Makefile,v
retrieving revision 1.88
diff -u -u -r1.88 Makefile
--- sbin/Makefile	19 Aug 2004 10:20:59 -0000	1.88
+++ sbin/Makefile	7 Nov 2004 22:23:20 -0000
@@ -33,6 +33,7 @@
 SUBDIR+= mount_overlay
 SUBDIR+= mount_portal
 SUBDIR+= mount_procfs
+SUBDIR+= mount_ptyfs
 SUBDIR+= mount_smbfs
 SUBDIR+= mount_umap
 SUBDIR+= mount_union
Index: sys/arch/i386/conf/GENERIC
===================================================================
RCS file: /cvsroot/src/sys/arch/i386/conf/GENERIC,v
retrieving revision 1.638
diff -u -u -r1.638 GENERIC
--- sys/arch/i386/conf/GENERIC	1 Nov 2004 23:20:42 -0000	1.638
+++ sys/arch/i386/conf/GENERIC	7 Nov 2004 22:23:22 -0000
@@ -135,6 +135,7 @@
 options 	COMPAT_IBCS2	# binary compatibility with SCO and ISC
 options 	COMPAT_LINUX	# binary compatibility with Linux
 options 	COMPAT_FREEBSD	# binary compatibility with FreeBSD
+options		COMPAT_BSDPTY	# /dev/[pt]ty?? ptys.
 #options 	COMPAT_MACH	# binary compatibility with Mach binaries
 #options 	COMPAT_DARWIN	# binary compatibility with Darwin binaries
 #options 	EXEC_MACHO	# exec MACH-O binaries
Index: sys/conf/files
===================================================================
RCS file: /cvsroot/src/sys/conf/files,v
retrieving revision 1.693
diff -u -u -r1.693 files
--- sys/conf/files	23 Oct 2004 17:25:14 -0000	1.693
+++ sys/conf/files	7 Nov 2004 22:23:23 -0000
@@ -45,7 +45,7 @@
 
 defflag	opt_ntp.h		PPS_SYNC NTP
 
-defflag	opt_ptm.h		NO_DEV_PTM
+defflag	opt_ptm.h		NO_DEV_PTM COMPAT_BSDPTY
 
 defparam opt_kmempages.h	NKMEMPAGES KMEMPAGES_MIN NKMEMPAGES_MAX
 defflag	opt_malloclog.h		MALLOCLOG
@@ -1240,7 +1240,9 @@
 file	kern/sysv_shm.c			sysvshm
 file	kern/tty.c
 file	kern/tty_conf.c
+file	kern/tty_bsdpty.c		compat_bsdpty
 file	kern/tty_pty.c			pty 			needs-flag
+file	kern/tty_ptm.c			pty
 file	kern/tty_subr.c
 file	kern/tty_tb.c			tb			needs-count
 file	kern/tty_tty.c
Index: sys/kern/tty_pty.c
===================================================================
RCS file: /cvsroot/src/sys/kern/tty_pty.c,v
retrieving revision 1.80
diff -u -u -r1.80 tty_pty.c
--- sys/kern/tty_pty.c	18 Jun 2004 15:02:53 -0000	1.80
+++ sys/kern/tty_pty.c	7 Nov 2004 22:23:23 -0000
@@ -34,7 +34,6 @@
 /*
  * Pseudo-teletype Driver
  * (Actually two drivers, requiring two entries in 'cdevsw')
- * Additional multiplexor driver /dev/ptm{,x}
  */
 
 #include <sys/cdefs.h>
@@ -60,16 +59,11 @@
 #include <sys/conf.h>
 #include <sys/poll.h>
 #include <sys/malloc.h>
+#include <sys/pty.h>
 
 #define	DEFAULT_NPTYS		16	/* default number of initial ptys */
 #define DEFAULT_MAXPTYS		992	/* default maximum number of ptys */
 
-#ifdef DEBUG_PTM
-#define DPRINTF(a) uprintf a
-#else
-#define DPRINTF(a)
-#endif
-
 /* Macros to clear/set/test flags. */
 #define	SET(t, f)	(t) |= (f)
 #define	CLR(t, f)	(t) &= ~((unsigned)(f))
@@ -77,18 +71,6 @@
 
 #define BUFSIZ 100		/* Chunk size iomoved to/from user */
 
-/*
- * pts == /dev/tty[pqrs]?
- * ptc == /dev/pty[pqrs]?
- */
-
-#define TTY_TEMPLATE	"/dev/XtyXX"
-#define TTY_NAMESIZE	sizeof(TTY_TEMPLATE)
-/* XXX this needs to come from somewhere sane, and work with MAKEDEV */
-#define TTY_LETTERS	"pqrstuvwxyzPQRST"
-#define TTY_OLD_SUFFIX  "0123456789abcdef"
-#define TTY_NEW_SUFFIX  "ghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
-
 struct	pt_softc {
 	struct	tty *pt_tty;
 	int	pt_flags;
@@ -98,9 +80,9 @@
 };
 
 static struct pt_softc **pt_softc = NULL;	/* pty array */
-static int npty = 0;			/* for pstat -t */
 static int maxptys = DEFAULT_MAXPTYS;	/* maximum number of ptys (sysctable) */
-static struct simplelock pt_softc_mutex = SIMPLELOCK_INITIALIZER;
+struct simplelock pt_softc_mutex = SIMPLELOCK_INITIALIZER;
+int npty = 0;			/* for pstat -t */
 
 #define	PF_PKT		0x08		/* packet mode */
 #define	PF_STOPPED	0x10		/* user told stopped */
@@ -114,35 +96,6 @@
 int	pty_maxptys(int, int);
 
 static struct pt_softc **ptyarralloc(int);
-static int check_pty(int);
-
-#ifndef NO_DEV_PTM
-
-static int pts_major;
-
-static dev_t pty_getfree(void);
-static char *pty_makename(char *, dev_t, char);
-static int pty_grant_slave(struct proc *, dev_t);
-static int pty_alloc_master(struct proc *, int *, dev_t *);
-static int pty_alloc_slave(struct proc *, int *, dev_t);
-static void pty_fill_ptmget(dev_t, int, int, void *);
-
-void ptmattach(int);
-
-dev_type_open(ptmopen);
-dev_type_close(ptmclose);
-dev_type_ioctl(ptmioctl);
-
-const struct cdevsw ptm_cdevsw = {
-	ptmopen, ptmclose, noread, nowrite, ptmioctl,
-	nullstop, notty, nopoll, nommap, nokqfilter, D_TTY
-};
-#else
-const struct cdevsw ptm_cdevsw = {
-	noopen, noclose, noread, nowrite, noioctl,
-	nostop, notty, nopoll, nommap, nokqfilter, D_TTY
-};
-#endif
 
 dev_type_open(ptcopen);
 dev_type_close(ptcclose);
@@ -184,6 +137,22 @@
 #endif /* defined(pmax) */
 
 /*
+ * Check if a pty is free to use.
+ */
+int
+pty_isfree(int minor, int lock)
+{
+	struct pt_softc *pt = pt_softc[minor];
+	if (lock)
+		simple_lock(&pt_softc_mutex);
+	minor = pt == NULL || pt->pt_tty == NULL ||
+	    pt->pt_tty->t_oproc == NULL;
+	if (lock)
+		simple_unlock(&pt_softc_mutex);
+	return minor;
+}
+
+/*
  * Allocate and zero array of nelem elements.
  */
 static struct pt_softc **
@@ -200,8 +169,8 @@
  * Check if the minor is correct and ensure necessary structures
  * are properly allocated.
  */
-static int
-check_pty(int ptn)
+int
+pty_check(int ptn)
 {
 	struct pt_softc *pti;
 
@@ -305,7 +274,7 @@
 
 	/*
 	 * We have to grab the pt_softc lock, so that we would pick correct
-	 * value of npty (might be modified in check_pty()).
+	 * value of npty (might be modified in pty_check()).
 	 */
 	simple_lock(&pt_softc_mutex);
 
@@ -353,7 +322,7 @@
 	int ptn = minor(dev);
 	int s;
 
-	if ((error = check_pty(ptn)))
+	if ((error = pty_check(ptn)) != 0)
 		return (error);
 
 	pti = pt_softc[ptn];
@@ -599,7 +568,7 @@
 	int ptn = minor(dev);
 	int s;
 
-	if ((error = check_pty(ptn)))
+	if ((error = pty_check(ptn)) != 0)
 		return (error);
 
 	pti = pt_softc[ptn];
@@ -1057,7 +1026,6 @@
 	int stop, error, sig;
 	int s;
 
-	cdev = cdevsw_lookup(dev);
 	/*
 	 * IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG.
 	 * ttywflush(tp) will hang if there are characters in the outq.
@@ -1085,15 +1053,18 @@
 		return(0);
 	}
 
+#ifndef NO_DEV_PTM
+	/* Allow getting the name from either the master or the slave */
+	if (cmd == TIOCPTSNAME)
+		return pty_fill_ptmget(dev, -1, -1, data);
+#endif
+
+	cdev = cdevsw_lookup(dev);
 	if (cdev != NULL && cdev->d_open == ptcopen)
 		switch (cmd) {
 #ifndef NO_DEV_PTM
 		case TIOCGRANTPT:
 			return pty_grant_slave(p, dev);
-
-		case TIOCPTSNAME:
-			pty_fill_ptmget(dev, -1, -1, data);
-			return 0;
 #endif
 
 		case TIOCGPGRP:
@@ -1217,328 +1188,3 @@
 	}
 	return (error);
 }
-
-#ifndef NO_DEV_PTM
-/*
- * Check if a pty is free to use.
- */
-static __inline int
-pty_isfree_locked(int minor)
-{
-	struct pt_softc *pt = pt_softc[minor];
-	return (pt == NULL || pt->pt_tty == NULL ||
-	    pt->pt_tty->t_oproc == NULL);
-}
-
-static int
-pty_isfree(int minor)
-{
-	int isfree;
-
-	simple_lock(&pt_softc_mutex);
-	isfree = pty_isfree_locked(minor);
-	simple_unlock(&pt_softc_mutex);
-	return(isfree);
-}
-
-static char *
-pty_makename(char *buf, dev_t dev, char c)
-{
-	size_t nt;
-	dev_t minor = minor(dev);
-
-	(void)memcpy(buf, TTY_TEMPLATE, TTY_NAMESIZE);
-
-	buf[5] = c;
-
-	if (minor < 256) {
-		nt = sizeof(TTY_OLD_SUFFIX) - 1;
-		buf[8] = TTY_LETTERS[minor / nt];
-		buf[9] = TTY_OLD_SUFFIX[minor % nt];
-	} else {
-		minor -= 256;
-		nt = sizeof(TTY_NEW_SUFFIX) - sizeof(TTY_OLD_SUFFIX);
-		buf[8] = TTY_LETTERS[minor / nt];
-		buf[9] = TTY_NEW_SUFFIX[minor % nt];
-	}
-	return buf;
-}
-
-static dev_t
-pty_getfree(void)
-{
-	int i;
-
-	simple_lock(&pt_softc_mutex);
-	for (i = 0; i < npty; i++) {
-		if (pty_isfree_locked(i))
-			break;
-	}
-	simple_unlock(&pt_softc_mutex);
-	return (makedev(pts_major, i));
-}
-
-/*
- * Hacked up version of vn_open. We _only_ handle ptys and only open
- * them with FREAD|FWRITE and never deal with creat or stuff like that.
- *
- * We need it because we have to fake up root credentials to open the pty.
- */
-static int
-ptm_vn_open(struct nameidata *ndp)
-{
-	struct vnode *vp;
-	struct proc *p = ndp->ni_cnd.cn_proc;
-	struct ucred *cred;
-	int error;
-
-	if ((error = namei(ndp)) != 0)
-		return (error);
-	vp = ndp->ni_vp;
-	if (vp->v_type != VCHR) {
-		error = EINVAL;
-		goto bad;
-	}
-
-	/*
-	 * Get us a fresh cred with root privileges.
-	 */
-	cred = crget();
-	error = VOP_OPEN(vp, FREAD|FWRITE, cred, p);
-	crfree(cred);
-
-	if (error)
-		goto bad;
-
-	vp->v_writecount++;
-
-	return (0);
-bad:
-	vput(vp);
-	return (error);
-}
-
-static int
-pty_alloc_master(struct proc *p, int *fd, dev_t *dev)
-{
-	int error;
-	struct nameidata nd;
-	struct pt_softc *pti;
-	struct file *fp;
-	int md;
-	char name[TTY_NAMESIZE];
-
-	if ((error = falloc(p, &fp, fd)) != 0) {
-		DPRINTF(("falloc %d\n", error));
-		return error;
-	}
-retry:
-	/* Find and open a free master pty. */
-	*dev = pty_getfree();
-	md = minor(*dev);
-	if ((error = check_pty(md)) != 0) {
-		DPRINTF(("ckeck_pty %d\n", error));
-		goto bad;
-	}
-	pti = pt_softc[md];
-	NDINIT(&nd, LOOKUP, NOFOLLOW|LOCKLEAF, UIO_SYSSPACE,
-	    pty_makename(name, *dev, 'p'), p);
-	if ((error = ptm_vn_open(&nd)) != 0) {
-		/*
-		 * Check if the master open failed because we lost
-		 * the race to grab it.
-		 */
-		if (error == EIO && !pty_isfree(md))
-			goto retry;
-		DPRINTF(("ptm_vn_open %d\n", error));
-		goto bad;
-	}
-	fp->f_flag = FREAD|FWRITE;
-	fp->f_type = DTYPE_VNODE;
-	fp->f_ops = &vnops;
-	fp->f_data = nd.ni_vp;
-	VOP_UNLOCK(nd.ni_vp, 0);
-	FILE_SET_MATURE(fp);
-	FILE_UNUSE(fp, p);
-	return 0;
-bad:
-	FILE_UNUSE(fp, p);
-	fdremove(p->p_fd, *fd);
-	ffree(fp);
-	return error;
-}
-
-static int
-pty_grant_slave(struct proc *p, dev_t dev)
-{
-	int error;
-	struct nameidata nd;
-	char name[TTY_NAMESIZE];
-
-	/*
-	 * Open the slave.
-	 * namei -> setattr -> unlock -> revoke -> vrele ->
-	 * namei -> open -> unlock
-	 * Three stage rocket:
-	 * 1. Change the owner and permissions on the slave.
-	 * 2. Revoke all the users of the slave.
-	 * 3. open the slave.
-	 */
-	NDINIT(&nd, LOOKUP, NOFOLLOW|LOCKLEAF, UIO_SYSSPACE,
-	    pty_makename(name, dev, 't'), p);
-	if ((error = namei(&nd)) != 0) {
-		DPRINTF(("namei %d\n", error));
-		return error;
-	}
-	if ((nd.ni_vp->v_mount->mnt_flag & MNT_RDONLY) == 0) {
-		struct vattr vattr;
-		struct ucred *cred;
-		gid_t gid = _TTY_GID;
-		/* get real uid */
-		uid_t uid = p->p_cred->p_ruid;
-
-		VATTR_NULL(&vattr);
-		vattr.va_uid = uid;
-		vattr.va_gid = gid;
-		vattr.va_mode = (S_IRUSR|S_IWUSR|S_IWGRP) & ALLPERMS;
-		/* Get a fake cred to pretend we're root. */
-		cred = crget();
-		error = VOP_SETATTR(nd.ni_vp, &vattr, cred, p);
-		crfree(cred);
-		if (error) {
-			DPRINTF(("setattr %d\n", error));
-			VOP_UNLOCK(nd.ni_vp, 0);
-			vrele(nd.ni_vp);
-			return error;
-		}
-	}
-	VOP_UNLOCK(nd.ni_vp, 0);
-	if (nd.ni_vp->v_usecount > 1 ||
-	    (nd.ni_vp->v_flag & (VALIASED | VLAYER)))
-		VOP_REVOKE(nd.ni_vp, REVOKEALL);
-
-	/*
-	 * The vnode is useless after the revoke, we need to
-	 * namei again.
-	 */
-	vrele(nd.ni_vp);
-	return 0;
-}
-
-static int
-pty_alloc_slave(struct proc *p, int *fd, dev_t dev)
-{
-	int error;
-	struct file *fp;
-	struct nameidata nd;
-	char name[TTY_NAMESIZE];
-
-	/* Grab a filedescriptor for the slave */
-	if ((error = falloc(p, &fp, fd)) != 0) {
-		DPRINTF(("falloc %d\n", error));
-		return error;
-	}
-
-	NDINIT(&nd, LOOKUP, NOFOLLOW|LOCKLEAF, UIO_SYSSPACE,
-	    pty_makename(name, dev, 't'), p);
-
-	/* now open it */
-	if ((error = ptm_vn_open(&nd)) != 0) {
-		DPRINTF(("vn_open %d\n", error));
-		FILE_UNUSE(fp, p);
-		fdremove(p->p_fd, *fd);
-		ffree(fp);
-		return error;
-	}
-	fp->f_flag = FREAD|FWRITE;
-	fp->f_type = DTYPE_VNODE;
-	fp->f_ops = &vnops;
-	fp->f_data = nd.ni_vp;
-	VOP_UNLOCK(nd.ni_vp, 0);
-	FILE_SET_MATURE(fp);
-	FILE_UNUSE(fp, p);
-	return 0;
-}
-
-static void
-pty_fill_ptmget(dev_t dev, int cfd, int sfd, void *data)
-{
-	struct ptmget *ptm = data;
-	ptm->cfd = cfd;
-	ptm->sfd = sfd;
-	(void)pty_makename(ptm->cn, dev, 'p');
-	(void)pty_makename(ptm->sn, dev, 't');
-}
-
-void
-/*ARGSUSED*/
-ptmattach(int n)
-{
-	/* find the major and minor of the pty devices */
-	if ((pts_major = cdevsw_lookup_major(&pts_cdevsw)) == -1)
-		panic("ptmattach: Can't find pty slave in cdevsw");
-}
-
-int
-/*ARGSUSED*/
-ptmopen(dev_t dev, int flag, int mode, struct proc *p)
-{
-	int error;
-	int fd;
-
-	switch(minor(dev)) {
-	case 0:		/* /dev/ptmx */
-		if ((error = pty_alloc_master(p, &fd, &dev)) != 0)
-			return error;
-		curlwp->l_dupfd = fd;
-		return ENXIO;
-	case 1:		/* /dev/ptm */
-		return 0;
-	default:
-		return ENODEV;
-	}
-		
-}
-
-int
-/*ARGSUSED*/
-ptmclose(dev_t dev, int flag, int mode, struct proc *p)
-{
-	return (0);
-}
-
-int
-/*ARGSUSED*/
-ptmioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
-{
-	int error;
-	dev_t newdev;
-	int cfd, sfd;
-	struct file *fp;
-
-	error = 0;
-	switch (cmd) {
-	case TIOCPTMGET:
-		if ((error = pty_alloc_master(p, &cfd, &newdev)) != 0)
-			return error;
-
-		if ((error = pty_grant_slave(p, newdev)) != 0)
-			goto bad;
-
-		if ((error = pty_alloc_slave(p, &sfd, newdev)) != 0)
-			goto bad;
-
-		/* now, put the indices and names into struct ptmget */
-		pty_fill_ptmget(newdev, cfd, sfd, data);
-		return 0;
-	default:
-		DPRINTF(("ptmioctl EINVAL\n"));
-		return EINVAL;
-	}
-bad:
-	fp = fd_getfile(p->p_fd, cfd);
-	fdremove(p->p_fd, cfd);
-	ffree(fp);
-	return error;
-}
-#endif
Index: sys/lkm/vfs/miscfs/Makefile
===================================================================
RCS file: /cvsroot/src/sys/lkm/vfs/miscfs/Makefile,v
retrieving revision 1.5
diff -u -u -r1.5 Makefile
--- sys/lkm/vfs/miscfs/Makefile	17 Mar 2003 09:18:54 -0000	1.5
+++ sys/lkm/vfs/miscfs/Makefile	7 Nov 2004 22:23:23 -0000
@@ -1,5 +1,5 @@
 #	$NetBSD: Makefile,v 1.5 2003/03/17 09:18:54 jdolecek Exp $
 
-SUBDIR=	fdesc kernfs nullfs overlay portal procfs umapfs union
+SUBDIR=	fdesc kernfs nullfs overlay portal procfs ptyfs umapfs union
 
 .include <bsd.subdir.mk>
Index: sys/sys/mount.h
===================================================================
RCS file: /cvsroot/src/sys/sys/mount.h,v
retrieving revision 1.124
diff -u -u -r1.124 mount.h
--- sys/sys/mount.h	15 Aug 2004 07:19:55 -0000	1.124
+++ sys/sys/mount.h	7 Nov 2004 22:23:23 -0000
@@ -102,10 +102,11 @@
 #define	MOUNT_ADOSFS	"adosfs"	/* AmigaDOS Filesystem */
 #define	MOUNT_EXT2FS	"ext2fs"	/* Second Extended Filesystem */
 #define	MOUNT_CFS	"coda"		/* Coda Filesystem */
-#define	MOUNT_CODA	"coda"		/* Coda Filesystem */
+#define	MOUNT_CODA	MOUNT_CFS	/* Coda Filesystem */
 #define	MOUNT_FILECORE	"filecore"	/* Acorn Filecore Filesystem */
 #define	MOUNT_NTFS	"ntfs"		/* Windows/NT Filesystem */
 #define	MOUNT_SMBFS	"smbfs"		/* CIFS (SMB) */
+#define	MOUNT_PTYFS	"ptyfs"		/* Pseudo tty filesystem */
 
 /*
  * Structure per mounted file system.  Each mounted file system has an
Index: sys/sys/vnode.h
===================================================================
RCS file: /cvsroot/src/sys/sys/vnode.h,v
retrieving revision 1.126
diff -u -u -r1.126 vnode.h
--- sys/sys/vnode.h	21 Sep 2004 03:10:35 -0000	1.126
+++ sys/sys/vnode.h	7 Nov 2004 22:23:23 -0000
@@ -66,7 +66,7 @@
 	VT_NON, VT_UFS, VT_NFS, VT_MFS, VT_MSDOSFS, VT_LFS, VT_LOFS, VT_FDESC,
 	VT_PORTAL, VT_NULL, VT_UMAP, VT_KERNFS, VT_PROCFS, VT_AFS, VT_ISOFS,
 	VT_UNION, VT_ADOSFS, VT_EXT2FS, VT_CODA, VT_FILECORE, VT_NTFS, VT_VFS,
-	VT_OVERLAY, VT_SMBFS
+	VT_OVERLAY, VT_SMBFS, VT_PTYFS
 };
 
 LIST_HEAD(buflists, buf);
Index: usr.bin/pmap/pmap.c
===================================================================
RCS file: /cvsroot/src/usr.bin/pmap/pmap.c,v
retrieving revision 1.22
diff -u -u -r1.22 pmap.c
--- usr.bin/pmap/pmap.c	10 Feb 2004 01:31:41 -0000	1.22
+++ usr.bin/pmap/pmap.c	7 Nov 2004 22:23:23 -0000
@@ -413,6 +413,7 @@
 		case VT_VFS:
 		case VT_OVERLAY:
 		case VT_SMBFS:
+		case VT_PTYFS:
 			break;
 		}
 	}
# This is a shell archive.  Save it in a file, remove anything before
# this line, and then unpack it by entering "sh file".  Note, it may
# create directories; files and directories will be owned by you and
# have default permissions.
#
# This archive contains:
#
#	sbin/mount_ptyfs/Makefile
#	sbin/mount_ptyfs/mount_ptyfs.8
#	sbin/mount_ptyfs/mount_ptyfs.c
#	sbin/mount_ptyfs/obj
#	sys/kern/tty_bsdpty.c
#	sys/kern/tty_ptm.c
#	sys/lkm/vfs/miscfs/ptyfs/Makefile
#	sys/lkm/vfs/miscfs/ptyfs/lkminit_vfs.c
#	sys/lkm/vfs/miscfs/ptyfs/obj
#	sys/miscfs/ptyfs/Makefile
#	sys/miscfs/ptyfs/files.ptyfs
#	sys/miscfs/ptyfs/ptyfs.h
#	sys/miscfs/ptyfs/ptyfs_subr.c
#	sys/miscfs/ptyfs/ptyfs_vfsops.c
#	sys/miscfs/ptyfs/ptyfs_vnops.c
#	sys/sys/pty.h
#
echo x - sbin/mount_ptyfs/Makefile
sed 's/^X//' >sbin/mount_ptyfs/Makefile << 'END-of-sbin/mount_ptyfs/Makefile'
X#	$NetBSD: Makefile,v 1.11 2003/03/22 12:43:59 jdolecek Exp $
X#	@(#)Makefile	8.2 (Berkeley) 3/27/94
X
X.include <bsd.own.mk>
X
XPROG=	mount_ptyfs
XSRCS=	mount_ptyfs.c
XMAN=	mount_ptyfs.8
X
XDPADD+=${LIBUTIL}
XLDADD+=-lutil
X
X.include <bsd.prog.mk>
END-of-sbin/mount_ptyfs/Makefile
echo x - sbin/mount_ptyfs/mount_ptyfs.8
sed 's/^X//' >sbin/mount_ptyfs/mount_ptyfs.8 << 'END-of-sbin/mount_ptyfs/mount_ptyfs.8'
X.\"	$NetBSD: mount_kernfs.8,v 1.14 2003/09/08 06:52:00 itojun Exp $
X.\"
X.\" Copyright (c) 1992, 1993, 1994
X.\"	The Regents of the University of California.  All rights reserved.
X.\" All rights reserved.
X.\"
X.\" This code is derived from software donated to Berkeley by
X.\" Jan-Simon Pendry.
X.\"
X.\" Redistribution and use in source and binary forms, with or without
X.\" modification, are permitted provided that the following conditions
X.\" are met:
X.\" 1. Redistributions of source code must retain the above copyright
X.\"    notice, this list of conditions and the following disclaimer.
X.\" 2. Redistributions in binary form must reproduce the above copyright
X.\"    notice, this list of conditions and the following disclaimer in the
X.\"    documentation and/or other materials provided with the distribution.
X.\" 3. Neither the name of the University nor the names of its contributors
X.\"    may be used to endorse or promote products derived from this software
X.\"    without specific prior written permission.
X.\"
X.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
X.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
X.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
X.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
X.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
X.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
X.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
X.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
X.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
X.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
X.\" SUCH DAMAGE.
X.\"
X.\"	@(#)mount_kernfs.8	8.2 (Berkeley) 3/27/94
X.\"
X.Dd September 8, 2003
X.Dt MOUNT_KERNFS 8
X.Os
X.Sh NAME
X.Nm mount_kernfs
X.Nd mount the /kern file system
X.Sh SYNOPSIS
X.Nm
X.Op Fl o Ar options
X.Ar /kern
X.Ar mount_point
X.Sh DESCRIPTION
XThe
X.Nm
Xcommand attaches an instance of the kernel parameter
Xnamespace to the global filesystem namespace.
XThe conventional mount point is
X.Pa /kern .
XThis command is normally executed by
X.Xr mount 8
Xat boot time.
X.Pp
XThe filesystem includes several regular files which can be read,
Xsome of which can also be written.
XThe contents of the files is in a machine-independent format,
Xeither a string, or an integer in decimal ASCII.
XWhere numbers are returned, a trailing newline character is also added.
X.Pp
XThe options are as follows:
X.Bl -tag -width indent
X.It Fl o
XOptions are specified with a
X.Fl o
Xflag followed by a comma separated string of options.
XSee the
X.Xr mount 8
Xman page for possible options and their meanings.
X.El
X.Sh FILES
X.Bl -tag -width copyright -compact
X.It Pa boottime
Xthe time at which the system was last booted (decimal ASCII).
X.It Pa copyright
Xkernel copyright message.
X.It Pa hostname
Xthe hostname, with a trailing newline.
XThe hostname can be changed by writing to this file.
XA trailing newline will be stripped from the hostname being written.
X.It Pa hz
Xthe frequency of the system clock (decimal ASCII).
X.It Pa ipsecsa
Xthe directory contains IPsec security associations (SA) in
X.Dv PF_KEY
Xformat.
XFilenames are SPI in decimal number.
XThe content of files can be inspected by using
X.Xr setkey 8 .
X.It Pa ipsecsp
Xthe directory contains IPsec security policies in
X.Dv PF_KEY
Xformat.
XFilenames are security policy ID in decimal number.
XThe content of files can be inspected by using
X.Xr setkey 8 .
X.It Pa loadavg
Xthe 1, 5 and 15 minute load average in kernel fixed-point format.
XThe final integer is the fix-point scaling factor.
XAll numbers are in decimal ASCII.
X.It Pa msgbuf
Xthe kernel message buffer, also read by
X.Xr syslogd 8 ,
Xthrough the
X.Pa log
Xdevice, and by
X.Xr dmesg 8 .
X.It Pa pagesize
Xthe machine pagesize (decimal ASCII).
X.It Pa physmem
Xthe number of pages of physical memory in the machine (decimal ASCII).
X.\" .It Pa root
X.\" the system root directory.
X.\" In a chroot'ed environment,
X.\" .Nm
X.\" can be used to create a new
X.\" .Pa /kern
X.\" mount point.
X.\" .Pa /kern/root
X.\" will then refer to the system global root, not the current process root.
X.It Pa rootdev
Xthe root device.
X.It Pa rrootdev
Xthe raw root device.
X.It Pa time
Xthe second and microsecond value of the system clock.
XBoth numbers are in decimal ASCII.
X.It Pa version
Xthe kernel version string.
XThe head line for
X.Pa /etc/motd
Xcan be generated by running:
X.Dq Ic "sed 1q /kern/version"
X.El
X.Sh SEE ALSO
X.Xr mount 2 ,
X.Xr unmount 2 ,
X.Xr ipsec 4 ,
X.Xr fstab 5 ,
X.Xr dmesg 8 ,
X.Xr mount 8 ,
X.Xr setkey 8 ,
X.Xr syslogd 8
X.Sh HISTORY
XThe
X.Nm
Xutility first appeared in
X.Bx 4.4 .
X.Sh BUGS
XThis filesystem may not be NFS-exported.
X.Pp
X.Xr lkm 4
Xversion does not support IPsec-related files/directories.
END-of-sbin/mount_ptyfs/mount_ptyfs.8
echo x - sbin/mount_ptyfs/mount_ptyfs.c
sed 's/^X//' >sbin/mount_ptyfs/mount_ptyfs.c << 'END-of-sbin/mount_ptyfs/mount_ptyfs.c'
X/*	$NetBSD: mount_ptyfs.c,v 1.15 2003/08/07 10:04:28 agc Exp $	*/
X
X/*
X * Copyright (c) 1992, 1993, 1994
X *	The Regents of the University of California.  All rights reserved.
X *
X * This code is derived from software contributed to Berkeley by
X * Jan-Simon Pendry.
X *
X * Redistribution and use in source and binary forms, with or without
X * modification, are permitted provided that the following conditions
X * are met:
X * 1. Redistributions of source code must retain the above copyright
X *    notice, this list of conditions and the following disclaimer.
X * 2. Redistributions in binary form must reproduce the above copyright
X *    notice, this list of conditions and the following disclaimer in the
X *    documentation and/or other materials provided with the distribution.
X * 3. Neither the name of the University nor the names of its contributors
X *    may be used to endorse or promote products derived from this software
X *    without specific prior written permission.
X *
X * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
X * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
X * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
X * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
X * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
X * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
X * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
X * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
X * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
X * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
X * SUCH DAMAGE.
X */
X
X/*
X * Copyright (c) 1990, 1992 Jan-Simon Pendry
X *
X * This code is derived from software contributed to Berkeley by
X * Jan-Simon Pendry.
X *
X * Redistribution and use in source and binary forms, with or without
X * modification, are permitted provided that the following conditions
X * are met:
X * 1. Redistributions of source code must retain the above copyright
X *    notice, this list of conditions and the following disclaimer.
X * 2. Redistributions in binary form must reproduce the above copyright
X *    notice, this list of conditions and the following disclaimer in the
X *    documentation and/or other materials provided with the distribution.
X * 3. All advertising materials mentioning features or use of this software
X *    must display the following acknowledgement:
X *	This product includes software developed by the University of
X *	California, Berkeley and its contributors.
X * 4. Neither the name of the University nor the names of its contributors
X *    may be used to endorse or promote products derived from this software
X *    without specific prior written permission.
X *
X * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
X * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
X * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
X * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
X * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
X * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
X * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
X * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
X * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
X * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
X * SUCH DAMAGE.
X */
X
X#include <sys/cdefs.h>
X#ifndef lint
X__COPYRIGHT("@(#) Copyright (c) 1992, 1993, 1994\n\
X	The Regents of the University of California.  All rights reserved.\n");
X#endif /* not lint */
X
X#ifndef lint
X#if 0
Xstatic char sccsid[] = "@(#)mount_ptyfs.c	8.3 (Berkeley) 5/4/95";
X#else
X__RCSID("$NetBSD: mount_ptyfs.c,v 1.15 2003/08/07 10:04:28 agc Exp $");
X#endif
X#endif /* not lint */
X
X#include <sys/param.h>
X#include <sys/mount.h>
X
X#include <err.h>
X#include <unistd.h>
X#include <stdio.h>
X#include <stdlib.h>
X#include <string.h>
X
X#include <mntopts.h>
X
Xstatic const struct mntopt mopts[] = {
X	MOPT_STDOPTS,
X	MOPT_GETARGS,
X	{ NULL }
X};
X
Xint	main __P((int, char *[]));
Xint	mount_ptyfs __P((int argc, char **argv));
Xstatic void	usage __P((void));
X
X#ifndef MOUNT_NOMAIN
Xint
Xmain(argc, argv)
X	int argc;
X	char **argv;
X{
X	return mount_ptyfs(argc, argv);
X}
X#endif
X
Xint
Xmount_ptyfs(argc, argv)
X	int argc;
X	char *argv[];
X{
X	int ch, mntflags;
X
X	mntflags = 0;
X	while ((ch = getopt(argc, argv, "o:")) != -1)
X		switch (ch) {
X		case 'o':
X			getmntopts(optarg, mopts, &mntflags, 0);
X			break;
X		case '?':
X		default:
X			usage();
X		}
X	argc -= optind;
X	argv += optind;
X
X	if (argc != 2)
X		usage();
X
X	if (mount(MOUNT_PTYFS, argv[1], mntflags, NULL))
X		err(1, "ptyfs on %s", argv[1]);
X	exit(0);
X}
X
Xstatic void
Xusage()
X{
X	(void)fprintf(stderr,
X		"usage: mount_ptyfs [-o options] /pty mount_point\n");
X	exit(1);
X}
END-of-sbin/mount_ptyfs/mount_ptyfs.c
echo c - sbin/mount_ptyfs/obj
mkdir -p sbin/mount_ptyfs/obj > /dev/null 2>&1
echo x - sys/kern/tty_bsdpty.c
sed 's/^X//' >sys/kern/tty_bsdpty.c << 'END-of-sys/kern/tty_bsdpty.c'
X/*	$NetBSD$	*/
X
X/*-
X * Copyright (c) 2004 The NetBSD Foundation, Inc.
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms, with or without
X * modification, are permitted provided that the following conditions
X * are met:
X * 1. Redistributions of source code must retain the above copyright
X *    notice, this list of conditions and the following disclaimer.
X * 2. Redistributions in binary form must reproduce the above copyright
X *    notice, this list of conditions and the following disclaimer in the
X *    documentation and/or other materials provided with the distribution.
X * 3. All advertising materials mentioning features or use of this software
X *    must display the following acknowledgement:
X *        This product includes software developed by the NetBSD
X *        Foundation, Inc. and its contributors.
X * 4. Neither the name of The NetBSD Foundation nor the names of its
X *    contributors may be used to endorse or promote products derived
X *    from this software without specific prior written permission.
X *
X * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
X * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
X * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
X * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
X * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
X * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
X * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
X * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
X * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
X * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
X * POSSIBILITY OF SUCH DAMAGE.
X */
X
X#include <sys/cdefs.h>
X__KERNEL_RCSID(0, "$NetBSD: tty_pty.c,v 1.80 2004/06/18 15:02:53 christos Exp $");
X
X#include "opt_ptm.h"
X
X#ifdef COMPAT_BSDPTY
X/* bsd tty implementation for pty multiplexor driver /dev/ptm{,x} */
X
X#include <sys/param.h>
X#include <sys/systm.h>
X#include <sys/ioctl.h>
X#include <sys/proc.h>
X#include <sys/tty.h>
X#include <sys/stat.h>
X#include <sys/file.h>
X#include <sys/uio.h>
X#include <sys/kernel.h>
X#include <sys/vnode.h>
X#include <sys/namei.h>
X#include <sys/signalvar.h>
X#include <sys/uio.h>
X#include <sys/filedesc.h>
X#include <sys/conf.h>
X#include <sys/poll.h>
X#include <sys/malloc.h>
X#include <sys/pty.h>
X
X/*
X * pts == /dev/tty[pqrs]?
X * ptc == /dev/pty[pqrs]?
X */
X
X#define TTY_TEMPLATE	"/dev/XtyXX"
X#define TTY_NAMESIZE	sizeof(TTY_TEMPLATE)
X/* XXX this needs to come from somewhere sane, and work with MAKEDEV */
X#define TTY_LETTERS	"pqrstuvwxyzPQRST"
X#define TTY_OLD_SUFFIX  "0123456789abcdef"
X#define TTY_NEW_SUFFIX  "ghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
X
Xstatic int pty_makename(struct ptm_pty *, char *, size_t, dev_t, char);
Xstatic int pty_allocvp(struct ptm_pty *, struct proc *, struct vnode **,
X    dev_t, char);
X
Xstruct ptm_pty ptm_bsdpty = {
X	pty_allocvp,
X	pty_makename,
X	NULL
X};
X
Xstatic int
X/*ARGSUSED*/
Xpty_makename(struct ptm_pty *ptm, char *buf, size_t bufsiz, dev_t dev, char c)
X{
X	size_t nt;
X	dev_t minor = minor(dev);
X	if (bufsiz < TTY_NAMESIZE)
X		return EINVAL;
X	(void)memcpy(buf, TTY_TEMPLATE, TTY_NAMESIZE);
X
X	buf[5] = c;
X
X	if (minor < 256) {
X		nt = sizeof(TTY_OLD_SUFFIX) - 1;
X		buf[8] = TTY_LETTERS[minor / nt];
X		buf[9] = TTY_OLD_SUFFIX[minor % nt];
X	} else {
X		minor -= 256;
X		nt = sizeof(TTY_NEW_SUFFIX) - sizeof(TTY_OLD_SUFFIX);
X		buf[8] = TTY_LETTERS[minor / nt];
X		buf[9] = TTY_NEW_SUFFIX[minor % nt];
X	}
X	return 0;
X}
X
X
Xstatic int
X/*ARGSUSED*/
Xpty_allocvp(struct ptm_pty *ptm, struct proc *p, struct vnode **vp, dev_t dev,
X    char ms)
X{
X	int error;
X	struct nameidata nd;
X	char name[TTY_NAMESIZE];
X
X	error = (*ptm->makename)(ptm, name, sizeof(name), dev, ms);
X	if (error)
X		return error;
X
X	NDINIT(&nd, LOOKUP, NOFOLLOW|LOCKLEAF, UIO_SYSSPACE, name, p);
X	if ((error = namei(&nd)) != 0)
X		return error;
X	*vp = nd.ni_vp;
X	return 0;
X}
X#endif
END-of-sys/kern/tty_bsdpty.c
echo x - sys/kern/tty_ptm.c
sed 's/^X//' >sys/kern/tty_ptm.c << 'END-of-sys/kern/tty_ptm.c'
X/*	$NetBSD$	*/
X
X/*-
X * Copyright (c) 2004 The NetBSD Foundation, Inc.
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms, with or without
X * modification, are permitted provided that the following conditions
X * are met:
X * 1. Redistributions of source code must retain the above copyright
X *    notice, this list of conditions and the following disclaimer.
X * 2. Redistributions in binary form must reproduce the above copyright
X *    notice, this list of conditions and the following disclaimer in the
X *    documentation and/or other materials provided with the distribution.
X * 3. All advertising materials mentioning features or use of this software
X *    must display the following acknowledgement:
X *        This product includes software developed by the NetBSD
X *        Foundation, Inc. and its contributors.
X * 4. Neither the name of The NetBSD Foundation nor the names of its
X *    contributors may be used to endorse or promote products derived
X *    from this software without specific prior written permission.
X *
X * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
X * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
X * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
X * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
X * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
X * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
X * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
X * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
X * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
X * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
X * POSSIBILITY OF SUCH DAMAGE.
X */
X
X#include <sys/cdefs.h>
X__KERNEL_RCSID(0, "$NetBSD: tty_pty.c,v 1.80 2004/06/18 15:02:53 christos Exp $");
X
X#include "opt_ptm.h"
X
X/* pty multiplexor driver /dev/ptm{,x} */
X
X#include <sys/param.h>
X#include <sys/systm.h>
X#include <sys/ioctl.h>
X#include <sys/proc.h>
X#include <sys/tty.h>
X#include <sys/stat.h>
X#include <sys/file.h>
X#include <sys/uio.h>
X#include <sys/kernel.h>
X#include <sys/vnode.h>
X#include <sys/namei.h>
X#include <sys/signalvar.h>
X#include <sys/uio.h>
X#include <sys/filedesc.h>
X#include <sys/conf.h>
X#include <sys/poll.h>
X#include <sys/malloc.h>
X#include <sys/pty.h>
X
X#ifdef DEBUG_PTM
X#define DPRINTF(a)	printf a
X#else
X#define DPRINTF(a)
X#endif
X
X#ifdef NO_DEV_PTM
Xconst struct cdevsw ptm_cdevsw = {
X	noopen, noclose, noread, nowrite, noioctl,
X	nostop, notty, nopoll, nommap, nokqfilter, D_TTY
X};
X#else
X
Xstatic struct ptm_pty *ptm;
Xint pts_major, ptc_major;
X
Xstatic dev_t pty_getfree(void);
Xstatic int pty_alloc_master(struct proc *, int *, dev_t *);
Xstatic int pty_alloc_slave(struct proc *, int *, dev_t);
X
Xvoid ptmattach(int);
X
Xdev_type_open(ptmopen);
Xdev_type_close(ptmclose);
Xdev_type_ioctl(ptmioctl);
X
Xconst struct cdevsw ptm_cdevsw = {
X	ptmopen, ptmclose, noread, nowrite, ptmioctl,
X	nullstop, notty, nopoll, nommap, nokqfilter, D_TTY
X};
X
Xdev_t
Xpty_makedev(char ms, int minor)
X{
X	return makedev(ms == 't' ? pts_major : ptc_major, minor);
X}
X
Xstatic dev_t
Xpty_getfree(void)
X{
X	extern struct simplelock pt_softc_mutex;
X	int i;
X
X	simple_lock(&pt_softc_mutex);
X	for (i = 0; i < npty; i++) {
X		if (pty_isfree(i, 0))
X			break;
X	}
X	simple_unlock(&pt_softc_mutex);
X	return pty_makedev('t', i);
X}
X
X/*
X * Hacked up version of vn_open. We _only_ handle ptys and only open
X * them with FREAD|FWRITE and never deal with creat or stuff like that.
X *
X * We need it because we have to fake up root credentials to open the pty.
X */
Xint
Xpty_vn_open(struct vnode *vp, struct proc *p)
X{
X	struct ucred *cred;
X	int error;
X
X	if (vp->v_type != VCHR) {
X		vput(vp);
X		return EINVAL;
X	}
X
X	/*
X	 * Get us a fresh cred with root privileges.
X	 */
X	cred = crget();
X	error = VOP_OPEN(vp, FREAD|FWRITE, cred, p);
X	crfree(cred);
X
X	if (error) {
X		vput(vp);
X		return error;
X	}
X
X	vp->v_writecount++;
X
X	return 0;
X}
X
Xstatic int
Xpty_alloc_master(struct proc *p, int *fd, dev_t *dev)
X{
X	int error;
X	struct file *fp;
X	struct vnode *vp;
X	int md;
X
X	if ((error = falloc(p, &fp, fd)) != 0) {
X		DPRINTF(("falloc %d\n", error));
X		return error;
X	}
Xretry:
X	/* Find and open a free master pty. */
X	*dev = pty_getfree();
X	md = minor(*dev);
X	if ((error = pty_check(md)) != 0) {
X		DPRINTF(("pty_check %d\n", error));
X		goto bad;
X	}
X	if (ptm == NULL) {
X		error = EOPNOTSUPP;
X		goto bad;
X	}
X	if ((error = (*ptm->allocvp)(ptm, p, &vp, *dev, 'p')) != 0)
X		goto bad;
X
X	if ((error = pty_vn_open(vp, p)) != 0) {
X		/*
X		 * Check if the master open failed because we lost
X		 * the race to grab it.
X		 */
X		if (error != EIO)
X			goto bad;
X		error = !pty_isfree(md, 1);
X		if (error)
X			goto retry;
X		else
X			goto bad;
X	}
X	fp->f_flag = FREAD|FWRITE;
X	fp->f_type = DTYPE_VNODE;
X	fp->f_ops = &vnops;
X	fp->f_data = vp;
X	VOP_UNLOCK(vp, 0);
X	FILE_SET_MATURE(fp);
X	FILE_UNUSE(fp, p);
X	return 0;
Xbad:
X	FILE_UNUSE(fp, p);
X	fdremove(p->p_fd, *fd);
X	ffree(fp);
X	return error;
X}
X
Xint
Xpty_grant_slave(struct proc *p, dev_t dev)
X{
X	int error;
X	struct vnode *vp;
X
X	/*
X	 * Open the slave.
X	 * namei -> setattr -> unlock -> revoke -> vrele ->
X	 * namei -> open -> unlock
X	 * Three stage rocket:
X	 * 1. Change the owner and permissions on the slave.
X	 * 2. Revoke all the users of the slave.
X	 * 3. open the slave.
X	 */
X	if (ptm == NULL)
X		return EOPNOTSUPP;
X
X	if ((error = (*ptm->allocvp)(ptm, p, &vp, dev, 't')) != 0)
X		return error;
X
X	if ((vp->v_mount->mnt_flag & MNT_RDONLY) == 0) {
X		struct vattr vattr;
X		struct ucred *cred;
X		/* get real uid */
X		VATTR_NULL(&vattr);
X		vattr.va_uid = p->p_cred->p_ruid;
X		vattr.va_gid = _TTY_GID;
X		vattr.va_mode = S_IRUSR|S_IWUSR|S_IWGRP;
X		/* Get a fake cred to pretend we're root. */
X		cred = crget();
X		error = VOP_SETATTR(vp, &vattr, cred, p);
X		crfree(cred);
X		if (error) {
X			DPRINTF(("setattr %d\n", error));
X			VOP_UNLOCK(vp, 0);
X			vrele(vp);
X			return error;
X		}
X	}
X	VOP_UNLOCK(vp, 0);
X	if (vp->v_usecount > 1 ||
X	    (vp->v_flag & (VALIASED | VLAYER)))
X		VOP_REVOKE(vp, REVOKEALL);
X
X	/*
X	 * The vnode is useless after the revoke, we need to get it again.
X	 */
X	vrele(vp);
X	return 0;
X}
X
Xstatic int
Xpty_alloc_slave(struct proc *p, int *fd, dev_t dev)
X{
X	int error;
X	struct file *fp;
X	struct vnode *vp;
X
X	/* Grab a filedescriptor for the slave */
X	if ((error = falloc(p, &fp, fd)) != 0) {
X		DPRINTF(("falloc %d\n", error));
X		return error;
X	}
X
X	if (ptm == NULL) {
X		error = EOPNOTSUPP;
X		goto bad;
X	}
X
X	if ((error = (*ptm->allocvp)(ptm, p, &vp, dev, 't')) != 0)
X		goto bad;
X	if ((error = pty_vn_open(vp, p)) != 0)
X		goto bad;
X
X	fp->f_flag = FREAD|FWRITE;
X	fp->f_type = DTYPE_VNODE;
X	fp->f_ops = &vnops;
X	fp->f_data = vp;
X	VOP_UNLOCK(vp, 0);
X	FILE_SET_MATURE(fp);
X	FILE_UNUSE(fp, p);
X	return 0;
Xbad:
X	FILE_UNUSE(fp, p);
X	fdremove(p->p_fd, *fd);
X	ffree(fp);
X	return error;
X}
X
Xstruct ptm_pty *
Xpty_sethandler(struct ptm_pty *nptm)
X{
X	struct ptm_pty *optm = ptm;
X	ptm = nptm;
X	return optm;
X}
X
Xint
Xpty_fill_ptmget(dev_t dev, int cfd, int sfd, void *data)
X{
X	struct ptmget *ptmg = data;
X	int error;
X
X	if (ptm == NULL)
X		return EOPNOTSUPP;
X
X	ptmg->cfd = cfd;
X	ptmg->sfd = sfd;
X
X	error = (*ptm->makename)(ptm, ptmg->cn, sizeof(ptmg->cn), dev, 'p');
X	if (error)
X		return error;
X
X	return (*ptm->makename)(ptm, ptmg->sn, sizeof(ptmg->sn), dev, 't');
X}
X
Xvoid
X/*ARGSUSED*/
Xptmattach(int n)
X{
X	extern const struct cdevsw pts_cdevsw, ptc_cdevsw;
X	/* find the major and minor of the pty devices */
X	if ((pts_major = cdevsw_lookup_major(&pts_cdevsw)) == -1)
X		panic("ptmattach: Can't find pty slave in cdevsw");
X	if ((ptc_major = cdevsw_lookup_major(&ptc_cdevsw)) == -1)
X		panic("ptmattach: Can't find pty master in cdevsw");
X#ifdef COMPAT_BSDPTY
X	ptm = &ptm_bsdpty;
X#endif
X}
X
Xint
X/*ARGSUSED*/
Xptmopen(dev_t dev, int flag, int mode, struct proc *p)
X{
X	int error;
X	int fd;
X
X	switch(minor(dev)) {
X	case 0:		/* /dev/ptmx */
X		if ((error = pty_alloc_master(p, &fd, &dev)) != 0)
X			return error;
X		curlwp->l_dupfd = fd;
X		return ENXIO;
X	case 1:		/* /dev/ptm */
X		return 0;
X	default:
X		return ENODEV;
X	}
X}
X
Xint
X/*ARGSUSED*/
Xptmclose(dev_t dev, int flag, int mode, struct proc *p)
X{
X	return (0);
X}
X
Xint
X/*ARGSUSED*/
Xptmioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
X{
X	int error;
X	dev_t newdev;
X	int cfd, sfd;
X	struct file *fp;
X
X	error = 0;
X	switch (cmd) {
X	case TIOCPTMGET:
X		if ((error = pty_alloc_master(p, &cfd, &newdev)) != 0)
X			return error;
X
X		if ((error = pty_grant_slave(p, newdev)) != 0)
X			goto bad;
X
X		if ((error = pty_alloc_slave(p, &sfd, newdev)) != 0)
X			goto bad;
X
X		/* now, put the indices and names into struct ptmget */
X		return pty_fill_ptmget(newdev, cfd, sfd, data);
X	default:
X		DPRINTF(("ptmioctl EINVAL\n"));
X		return EINVAL;
X	}
Xbad:
X	fp = fd_getfile(p->p_fd, cfd);
X	fdremove(p->p_fd, cfd);
X	ffree(fp);
X	return error;
X}
X#endif
END-of-sys/kern/tty_ptm.c
echo x - sys/lkm/vfs/miscfs/ptyfs/Makefile
sed 's/^X//' >sys/lkm/vfs/miscfs/ptyfs/Makefile << 'END-of-sys/lkm/vfs/miscfs/ptyfs/Makefile'
X#	$NetBSD: Makefile,v 1.17 2003/01/03 13:22:23 christos Exp $
X
X.include "../Makefile.inc"
X
X.PATH:	$S/miscfs/ptyfs ${.CURDIR}/../.. $S/arch/${MACHINE}/${MACHINE} \
X	$S/arch/${MACHINE_CPU}/${MACHINE_CPU}
X
XKMOD=	ptyfs
X
XSRCS=	lkminit_vfs.c
XSRCS+=	ptyfs_vfsops.c ptyfs_vnops.c ptyfs_subr.c
X
X.include <bsd.kmod.mk>
END-of-sys/lkm/vfs/miscfs/ptyfs/Makefile
echo x - sys/lkm/vfs/miscfs/ptyfs/lkminit_vfs.c
sed 's/^X//' >sys/lkm/vfs/miscfs/ptyfs/lkminit_vfs.c << 'END-of-sys/lkm/vfs/miscfs/ptyfs/lkminit_vfs.c'
X/* $NetBSD: lkminit_vfs.c,v 1.6 2004/05/20 06:34:28 atatat Exp $ */
X
X/*-
X * Copyright (c) 1996 The NetBSD Foundation, Inc.
X * All rights reserved.
X *
X * This code is derived from software contributed to The NetBSD Foundation
X * by Michael Graff <explorer@flame.org>.
X *
X * Redistribution and use in source and binary forms, with or without
X * modification, are permitted provided that the following conditions
X * are met:
X * 1. Redistributions of source code must retain the above copyright
X *    notice, this list of conditions and the following disclaimer.
X * 2. Redistributions in binary form must reproduce the above copyright
X *    notice, this list of conditions and the following disclaimer in the
X *    documentation and/or other materials provided with the distribution.
X * 3. All advertising materials mentioning features or use of this software
X *    must display the following acknowledgement:
X *        This product includes software developed by the NetBSD
X *        Foundation, Inc. and its contributors.
X * 4. Neither the name of The NetBSD Foundation nor the names of its
X *    contributors may be used to endorse or promote products derived
X *    from this software without specific prior written permission.
X *
X * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
X * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
X * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
X * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
X * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
X * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
X * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
X * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
X * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
X * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
X * POSSIBILITY OF SUCH DAMAGE.
X */
X
X#include <sys/cdefs.h>
X__KERNEL_RCSID(0, "$NetBSD: lkminit_vfs.c,v 1.6 2004/05/20 06:34:28 atatat Exp $");
X
X#include <sys/param.h>
X#include <sys/sysctl.h>
X#include <sys/ioctl.h>
X#include <sys/systm.h>
X#include <sys/conf.h>
X#include <sys/mount.h>
X#include <sys/exec.h>
X#include <sys/lkm.h>
X#include <sys/file.h>
X#include <sys/errno.h>
X
X#include <miscfs/ptyfs/ptyfs.h>
X
Xint ptyfs_lkmentry(struct lkm_table *, int, int);
X
X/*
X * This is the vfsops table for the file system in question
X */
Xextern struct vfsops ptyfs_vfsops;
X
X/*
X * declare the filesystem
X */
XMOD_VFS("ptyfs", -1, &ptyfs_vfsops);
X
X/*
X * take care of fs specific sysctl nodes
X */
Xstatic int load(struct lkm_table *, int);
Xstatic int unload(struct lkm_table *, int);
Xstatic struct sysctllog *_ptyfs_log;
X
X/*
X * entry point
X */
Xint
Xptyfs_lkmentry(struct lkm_table *lkmtp, int cmd, int ver)
X{
X
X	DISPATCH(lkmtp, cmd, ver, load, unload, lkm_nofunc)
X}
X
Xstatic int
Xload(struct lkm_table *lkmtp, int cmd)
X{
X
X	sysctl_vfs_ptyfs_setup(&_ptyfs_log);
X	return (0);
X}
X
Xstatic int
Xunload(struct lkm_table *lkmtp, int cmd)
X{
X
X	sysctl_teardown(&_ptyfs_log);
X	return (0);
X}
END-of-sys/lkm/vfs/miscfs/ptyfs/lkminit_vfs.c
echo c - sys/lkm/vfs/miscfs/ptyfs/obj
mkdir -p sys/lkm/vfs/miscfs/ptyfs/obj > /dev/null 2>&1
echo x - sys/miscfs/ptyfs/Makefile
sed 's/^X//' >sys/miscfs/ptyfs/Makefile << 'END-of-sys/miscfs/ptyfs/Makefile'
X#	$NetBSD: Makefile,v 1.1 1998/06/12 23:23:02 cgd Exp $
X
XINCSDIR= /usr/include/miscfs/ptyfs
X
XINCS=	ptyfs.h
X
X.include <bsd.kinc.mk>
END-of-sys/miscfs/ptyfs/Makefile
echo x - sys/miscfs/ptyfs/files.ptyfs
sed 's/^X//' >sys/miscfs/ptyfs/files.ptyfs << 'END-of-sys/miscfs/ptyfs/files.ptyfs'
X#	$NetBSD: files.ptyfs,v 1.2 2003/09/08 06:51:53 itojun Exp $
X
Xdeffs	fs_ptyfs.h			PTYFS		# XXX
X
Xfile	miscfs/ptyfs/ptyfs_subr.c	ptyfs
Xfile	miscfs/ptyfs/ptyfs_vfsops.c	ptyfs
Xfile	miscfs/ptyfs/ptyfs_vnops.c	ptyfs
END-of-sys/miscfs/ptyfs/files.ptyfs
echo x - sys/miscfs/ptyfs/ptyfs.h
sed 's/^X//' >sys/miscfs/ptyfs/ptyfs.h << 'END-of-sys/miscfs/ptyfs/ptyfs.h'
X/*	$NetBSD: ptyfs.h,v 1.56 2004/09/20 17:53:08 jdolecek Exp $	*/
X
X/*
X * Copyright (c) 1993
X *	The Regents of the University of California.  All rights reserved.
X *
X * This code is derived from software contributed to Berkeley by
X * Jan-Simon Pendry.
X *
X * Redistribution and use in source and binary forms, with or without
X * modification, are permitted provided that the following conditions
X * are met:
X * 1. Redistributions of source code must retain the above copyright
X *    notice, this list of conditions and the following disclaimer.
X * 2. Redistributions in binary form must reproduce the above copyright
X *    notice, this list of conditions and the following disclaimer in the
X *    documentation and/or other materials provided with the distribution.
X * 3. Neither the name of the University nor the names of its contributors
X *    may be used to endorse or promote products derived from this software
X *    without specific prior written permission.
X *
X * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
X * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
X * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
X * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
X * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
X * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
X * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
X * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
X * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
X * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
X * SUCH DAMAGE.
X *
X *	@(#)ptyfs.h	8.9 (Berkeley) 5/14/95
X */
X
X/*
X * Copyright (c) 1993 Jan-Simon Pendry
X *
X * This code is derived from software contributed to Berkeley by
X * Jan-Simon Pendry.
X *
X * Redistribution and use in source and binary forms, with or without
X * modification, are permitted provided that the following conditions
X * are met:
X * 1. Redistributions of source code must retain the above copyright
X *    notice, this list of conditions and the following disclaimer.
X * 2. Redistributions in binary form must reproduce the above copyright
X *    notice, this list of conditions and the following disclaimer in the
X *    documentation and/or other materials provided with the distribution.
X * 3. All advertising materials mentioning features or use of this software
X *    must display the following acknowledgement:
X *	This product includes software developed by the University of
X *	California, Berkeley and its contributors.
X * 4. Neither the name of the University nor the names of its contributors
X *    may be used to endorse or promote products derived from this software
X *    without specific prior written permission.
X *
X * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
X * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
X * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
X * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
X * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
X * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
X * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
X * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
X * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
X * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
X * SUCH DAMAGE.
X *
X *	@(#)ptyfs.h	8.9 (Berkeley) 5/14/95
X */
X
X#ifdef _KERNEL
X/*
X * The different types of node in a ptyfs filesystem
X */
Xtypedef enum {
X	PTYFSpts,	/* The slave side of a pty */
X	PTYFSptc,	/* The controlling side of a pty */
X	PTYFSroot,	/* the filesystem root */
X} ptyfstype;
X
X/*
X * control data for the proc file system.
X */
Xstruct ptyfsnode {
X	LIST_ENTRY(ptyfsnode) ptyfs_hash;	/* hash chain */
X	struct vnode	*ptyfs_vnode;	/* vnode associated with this ptyfsnode */
X	ptyfstype	ptyfs_type;	/* type of ptyfs node */
X	int		ptyfs_pty;	/* the pty index */
X	u_long		ptyfs_fileno;	/* unique file id */
X	int		ptyfs_flag;	/* status flag for times */
X#define	PTYFS_ACCESS	1
X#define	PTYFS_MODIFY	2
X#define	PTYFS_CHANGE	4
X	/* Attribute information */
X	uid_t		ptyfs_uid;
X	gid_t		ptyfs_gid;
X	mode_t		ptyfs_mode;
X	int		ptyfs_flags;
X	struct timespec	ptyfs_ctime, ptyfs_mtime, ptyfs_atime, ptyfs_birthtime;
X};
X
X#endif /* _KERNEL */
X
X/*
X * Kernel stuff follows
X */
X#ifdef _KERNEL
X#define CNEQ(cnp, s, len) \
X	 ((cnp)->cn_namelen == (len) && \
X	  (memcmp((s), (cnp)->cn_nameptr, (len)) == 0))
X
X#define UIO_MX 32
X
X#define PTYFS_FILENO(pty, type) \
X    ((((int)type) << 30) | (pty + 1))
X
X/*
X * Convert between ptyfsnode vnode
X */
X#define VTOPTYFS(vp)	((struct ptyfsnode *)(vp)->v_data)
X#define PTYFSTOV(ptyfs)	((ptyfs)->ptyfs_vnode)
X
Xint ptyfs_freevp(struct vnode *);
Xint ptyfs_allocvp(struct mount *, struct vnode **, pid_t, ptyfstype,
X    struct proc *);
Xvoid ptyfs_revoke_vnodes(struct proc *, void *);
Xvoid ptyfs_hashinit(void);
Xvoid ptyfs_hashreinit(void);
Xvoid ptyfs_hashdone(void);
Xint ptyfs_getfp(struct ptyfsnode *, struct proc **, struct file **);
X
X/* functions to check whether or not files should be displayed */
Xint ptyfs_validfile(struct proc *, struct mount *);
Xint ptyfs_validfpregs(struct proc *, struct mount *);
Xint ptyfs_validregs(struct proc *, struct mount *);
Xint ptyfs_validmap(struct proc *, struct mount *);
X
Xextern int (**ptyfs_vnodeop_p)(void *);
Xextern struct vfsops ptyfs_vfsops;
X
Xint	ptyfs_root(struct mount *, struct vnode **);
X
X#ifdef SYSCTL_SETUP_PROTO
XSYSCTL_SETUP_PROTO(sysctl_vfs_ptyfs_setup);
X#endif /* SYSCTL_SETUP_PROTO */
X#endif /* _KERNEL */
END-of-sys/miscfs/ptyfs/ptyfs.h
echo x - sys/miscfs/ptyfs/ptyfs_subr.c
sed 's/^X//' >sys/miscfs/ptyfs/ptyfs_subr.c << 'END-of-sys/miscfs/ptyfs/ptyfs_subr.c'
X/*	$NetBSD: ptyfs_subr.c,v 1.62 2004/09/20 17:53:08 jdolecek Exp $	*/
X
X/*
X * Copyright (c) 1993
X *	The Regents of the University of California.  All rights reserved.
X *
X * This code is derived from software contributed to Berkeley by
X * Jan-Simon Pendry.
X *
X * Redistribution and use in source and binary forms, with or without
X * modification, are permitted provided that the following conditions
X * are met:
X * 1. Redistributions of source code must retain the above copyright
X *    notice, this list of conditions and the following disclaimer.
X * 2. Redistributions in binary form must reproduce the above copyright
X *    notice, this list of conditions and the following disclaimer in the
X *    documentation and/or other materials provided with the distribution.
X * 3. Neither the name of the University nor the names of its contributors
X *    may be used to endorse or promote products derived from this software
X *    without specific prior written permission.
X *
X * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
X * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
X * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
X * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
X * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
X * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
X * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
X * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
X * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
X * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
X * SUCH DAMAGE.
X *
X *	@(#)ptyfs_subr.c	8.6 (Berkeley) 5/14/95
X */
X
X/*
X * Copyright (c) 1994 Christopher G. Demetriou.  All rights reserved.
X * Copyright (c) 1993 Jan-Simon Pendry
X *
X * This code is derived from software contributed to Berkeley by
X * Jan-Simon Pendry.
X *
X * Redistribution and use in source and binary forms, with or without
X * modification, are permitted provided that the following conditions
X * are met:
X * 1. Redistributions of source code must retain the above copyright
X *    notice, this list of conditions and the following disclaimer.
X * 2. Redistributions in binary form must reproduce the above copyright
X *    notice, this list of conditions and the following disclaimer in the
X *    documentation and/or other materials provided with the distribution.
X * 3. All advertising materials mentioning features or use of this software
X *    must display the following acknowledgement:
X *	This product includes software developed by the University of
X *	California, Berkeley and its contributors.
X * 4. Neither the name of the University nor the names of its contributors
X *    may be used to endorse or promote products derived from this software
X *    without specific prior written permission.
X *
X * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
X * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
X * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
X * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
X * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
X * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
X * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
X * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
X * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
X * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
X * SUCH DAMAGE.
X *
X *	@(#)ptyfs_subr.c	8.6 (Berkeley) 5/14/95
X */
X
X#include <sys/cdefs.h>
X__KERNEL_RCSID(0, "$NetBSD: ptyfs_subr.c,v 1.62 2004/09/20 17:53:08 jdolecek Exp $");
X
X#include <sys/param.h>
X#include <sys/systm.h>
X#include <sys/time.h>
X#include <sys/kernel.h>
X#include <sys/vnode.h>
X#include <sys/malloc.h>
X#include <sys/stat.h>
X#include <sys/file.h>
X#include <sys/namei.h>
X#include <sys/filedesc.h>
X#include <sys/select.h>
X#include <sys/tty.h>
X#include <sys/pty.h>
X
X#include <miscfs/ptyfs/ptyfs.h>
X
Xstatic void ptyfs_getinfo(struct ptyfsnode *, struct proc *);
Xstatic void ptyfs_hashins(struct ptyfsnode *);
Xstatic void ptyfs_hashrem(struct ptyfsnode *);
Xstatic struct vnode *ptyfs_hashget(pid_t, ptyfstype, struct mount *);
X
XLIST_HEAD(ptyfs_hashhead, ptyfsnode) *ptyfs_hashtbl;
Xstatic u_long	ptyfs_ihash;	/* size of hash table - 1 */
X#define PTYHASH(pty)	((pty) & ptyfs_ihash)
X
Xstatic struct lock ptyfs_hashlock;
Xstatic struct simplelock ptyfs_hash_slock;
X
Xstatic void
Xptyfs_getinfo(struct ptyfsnode *ptyfs, struct proc *p)
X{
X	extern struct ptm_pty *ptyfs_save_ptm, ptm_ptyfspty;
X
X	if (ptyfs->ptyfs_type == PTYFSroot) {
X		ptyfs->ptyfs_mode = S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|
X		    S_IROTH|S_IXOTH;
X		goto out;
X	} else
X		ptyfs->ptyfs_mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|
X		    S_IROTH|S_IWOTH;
X
X	printf("saveptm %p\n", ptyfs_save_ptm);
X	if (ptyfs_save_ptm != NULL && ptyfs_save_ptm != &ptm_ptyfspty) {
X		int error;
X		struct nameidata nd;
X		char ttyname[64];
X		struct ucred *cred;
X		struct vattr va;
X		/*
X		 * We support traditional ptys, so we copy the info
X		 * from the inode
X		 */
X		if ((error = (*ptyfs_save_ptm->makename)(
X			ptyfs_save_ptm, ttyname, sizeof(ttyname),
X			ptyfs->ptyfs_pty, ptyfs->ptyfs_type == PTYFSpts ? 't'
X			: 'p')) != 0) {
X				printf("makename %d\n", error);
X				goto out;
X			}
X		NDINIT(&nd, LOOKUP, NOFOLLOW|LOCKLEAF, UIO_SYSSPACE, ttyname,
X		     p);
X		printf("ttyname %s\n", ttyname);
X		if ((error = namei(&nd)) != 0) {
X			printf("namei %s %d\n", ttyname, error);
X			goto out;
X		}
X		printf("getattr %s\n", ttyname);
X		cred = crget();
X		error = VOP_GETATTR(nd.ni_vp, &va, cred, p);
X		crfree(cred);
X		VOP_UNLOCK(nd.ni_vp, 0);
X		vrele(nd.ni_vp);
X		if (error) {
X			printf("getattr %d\n", error);
X			goto out;
X		}
X		ptyfs->ptyfs_uid = va.va_uid;
X		ptyfs->ptyfs_gid = va.va_gid;
X		ptyfs->ptyfs_mode = va.va_mode;
X		ptyfs->ptyfs_flags = va.va_flags;
X		ptyfs->ptyfs_birthtime = va.va_birthtime;
X		ptyfs->ptyfs_ctime = va.va_ctime;
X		ptyfs->ptyfs_mtime = va.va_mtime;
X		ptyfs->ptyfs_atime = va.va_atime;
X		return;
X	}
Xout:
X	ptyfs->ptyfs_uid = ptyfs->ptyfs_gid = 0;
X	TIMEVAL_TO_TIMESPEC(&time, &ptyfs->ptyfs_ctime);
X	ptyfs->ptyfs_birthtime = ptyfs->ptyfs_mtime =
X	    ptyfs->ptyfs_atime = ptyfs->ptyfs_ctime;
X	ptyfs->ptyfs_flags = 0;
X}
X
X
X/*
X * allocate a ptyfsnode/vnode pair.  the vnode is
X * referenced, and locked.
X *
X * the pid, ptyfs_type, and mount point uniquely
X * identify a ptyfsnode.  the mount point is needed
X * because someone might mount this filesystem
X * twice.
X *
X * all ptyfsnodes are maintained on a singly-linked
X * list.  new nodes are only allocated when they cannot
X * be found on this list.  entries on the list are
X * removed when the vfs reclaim entry is called.
X *
X * a single lock is kept for the entire list.  this is
X * needed because the getnewvnode() function can block
X * waiting for a vnode to become free, in which case there
X * may be more than one ptyess trying to get the same
X * vnode.  this lock is only taken if we are going to
X * call getnewvnode, since the kernel itself is single-threaded.
X *
X * if an entry is found on the list, then call vget() to
X * take a reference.  this is done because there may be
X * zero references to it and so it needs to removed from
X * the vnode free list.
X */
Xint
Xptyfs_allocvp(struct mount *mp, struct vnode **vpp, int pty,
X    ptyfstype ptyfs_type, struct proc *p)
X{
X	struct ptyfsnode *ptyfs;
X	struct vnode *vp;
X	int error;
X
X	do {
X		if ((*vpp = ptyfs_hashget(pty, ptyfs_type, mp)) != NULL)
X			return 0;
X	} while (lockmgr(&ptyfs_hashlock, LK_EXCLUSIVE|LK_SLEEPFAIL, 0));
X
X	if ((error = getnewvnode(VT_PTYFS, mp, ptyfs_vnodeop_p, &vp)) != 0) {
X		*vpp = NULL;
X		lockmgr(&ptyfs_hashlock, LK_RELEASE, NULL);
X		return error;
X	}
X
X	MALLOC(ptyfs, void *, sizeof(struct ptyfsnode), M_TEMP, M_WAITOK);
X	vp->v_data = ptyfs;
X
X	ptyfs->ptyfs_pty = pty;
X	ptyfs->ptyfs_type = ptyfs_type;
X	ptyfs->ptyfs_vnode = vp;
X	ptyfs->ptyfs_fileno = PTYFS_FILENO(pty, ptyfs_type);
X	ptyfs_getinfo(ptyfs, p);
X
X	switch (ptyfs_type) {
X	case PTYFSroot:	/* /pts = dr-xr-xr-x */
X		vp->v_type = VDIR;
X		vp->v_flag = VROOT;
X		break;
X
X	case PTYFSpts:	/* /pts/N = cxxxxxxxxx */
X	case PTYFSptc:	/* controlling side = cxxxxxxxxx */
X		vp->v_type = VCHR;
X		break;
X	default:
X		panic("ptyfs_allocvp");
X	}
X
X	ptyfs_hashins(ptyfs);
X	uvm_vnp_setsize(vp, 0);
X	lockmgr(&ptyfs_hashlock, LK_RELEASE, NULL);
X
X	*vpp = vp;
X	return 0;
X}
X
Xint
Xptyfs_freevp(struct vnode *vp)
X{
X	struct ptyfsnode *ptyfs = VTOPTYFS(vp);
X
X	ptyfs_hashrem(ptyfs);
X
X	FREE(vp->v_data, M_TEMP);
X	vp->v_data = 0;
X	return 0;
X}
X
X/*
X * Initialize ptyfsnode hash table.
X */
Xvoid
Xptyfs_hashinit(void)
X{
X	lockinit(&ptyfs_hashlock, PINOD, "ptyfs_hashlock", 0, 0);
X	ptyfs_hashtbl = hashinit(desiredvnodes / 4, HASH_LIST, M_UFSMNT,
X	    M_WAITOK, &ptyfs_ihash);
X	simple_lock_init(&ptyfs_hash_slock);
X}
X
Xvoid
Xptyfs_hashreinit(void)
X{
X	struct ptyfsnode *pp;
X	struct ptyfs_hashhead *oldhash, *hash;
X	u_long i, oldmask, mask, val;
X
X	hash = hashinit(desiredvnodes / 4, HASH_LIST, M_UFSMNT, M_WAITOK,
X	    &mask);
X
X	simple_lock(&ptyfs_hash_slock);
X	oldhash = ptyfs_hashtbl;
X	oldmask = ptyfs_ihash;
X	ptyfs_hashtbl = hash;
X	ptyfs_ihash = mask;
X	for (i = 0; i <= oldmask; i++) {
X		while ((pp = LIST_FIRST(&oldhash[i])) != NULL) {
X			LIST_REMOVE(pp, ptyfs_hash);
X			val = PTYHASH(pp->ptyfs_pty);
X			LIST_INSERT_HEAD(&hash[val], pp, ptyfs_hash);
X		}
X	}
X	simple_unlock(&ptyfs_hash_slock);
X	hashdone(oldhash, M_UFSMNT);
X}
X
X/*
X * Free ptyfsnode hash table.
X */
Xvoid
Xptyfs_hashdone(void)
X{
X	hashdone(ptyfs_hashtbl, M_UFSMNT);
X}
X
Xstruct vnode *
Xptyfs_hashget(pid, type, mp)
X	pid_t pid;
X	ptyfstype type;
X	struct mount *mp;
X{
X	struct ptyfs_hashhead *ppp;
X	struct ptyfsnode *pp;
X	struct vnode *vp;
X
Xloop:
X	simple_lock(&ptyfs_hash_slock);
X	ppp = &ptyfs_hashtbl[PTYHASH(pid)];
X	LIST_FOREACH(pp, ppp, ptyfs_hash) {
X		vp = PTYFSTOV(pp);
X		if (pid == pp->ptyfs_pty && pp->ptyfs_type == type &&
X		    vp->v_mount == mp) {
X			simple_lock(&vp->v_interlock);
X			simple_unlock(&ptyfs_hash_slock);
X			if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK))
X				goto loop;
X			return vp;
X		}
X	}
X	simple_unlock(&ptyfs_hash_slock);
X	return NULL;
X}
X
X/*
X * Insert the ptyfsnode into the hash table and lock it.
X */
Xstatic void
Xptyfs_hashins(pp)
X	struct ptyfsnode *pp;
X{
X	struct ptyfs_hashhead *ppp;
X
X	/* lock the ptyfsnode, then put it on the appropriate hash list */
X	lockmgr(&pp->ptyfs_vnode->v_lock, LK_EXCLUSIVE, (struct simplelock *)0);
X
X	simple_lock(&ptyfs_hash_slock);
X	ppp = &ptyfs_hashtbl[PTYHASH(pp->ptyfs_pty)];
X	LIST_INSERT_HEAD(ppp, pp, ptyfs_hash);
X	simple_unlock(&ptyfs_hash_slock);
X}
X
X/*
X * Remove the ptyfsnode from the hash table.
X */
Xstatic void
Xptyfs_hashrem(struct ptyfsnode *pp)
X{
X	simple_lock(&ptyfs_hash_slock);
X	LIST_REMOVE(pp, ptyfs_hash);
X	simple_unlock(&ptyfs_hash_slock);
X}
X
Xvoid
Xptyfs_revoke_vnodes(struct proc *p, void *arg)
X{
X	struct ptyfsnode *ptyfs, *pnext;
X	struct vnode *vp;
X	struct mount *mp = (struct mount *)arg;
X	struct ptyfs_hashhead *ppp;
X
X	if (!(p->p_flag & P_SUGID))
X		return;
X
X	ppp = &ptyfs_hashtbl[PTYHASH(p->p_pid)];
X	for (ptyfs = LIST_FIRST(ppp); ptyfs; ptyfs = pnext) {
X		vp = PTYFSTOV(ptyfs);
X		pnext = LIST_NEXT(ptyfs, ptyfs_hash);
X		if (vp->v_usecount > 0 && ptyfs->ptyfs_pty == p->p_pid &&
X		    vp->v_mount == mp)
X			VOP_REVOKE(vp, REVOKEALL);
X	}
X}
END-of-sys/miscfs/ptyfs/ptyfs_subr.c
echo x - sys/miscfs/ptyfs/ptyfs_vfsops.c
sed 's/^X//' >sys/miscfs/ptyfs/ptyfs_vfsops.c << 'END-of-sys/miscfs/ptyfs/ptyfs_vfsops.c'
X/*	$NetBSD: ptyfs_vfsops.c,v 1.64 2004/05/29 14:28:41 tron Exp $	*/
X
X/*
X * Copyright (c) 1992, 1993, 1995
X *	The Regents of the University of California.  All rights reserved.
X *
X * This code is derived from software donated to Berkeley by
X * Jan-Simon Pendry.
X *
X * Redistribution and use in source and binary forms, with or without
X * modification, are permitted provided that the following conditions
X * are met:
X * 1. Redistributions of source code must retain the above copyright
X *    notice, this list of conditions and the following disclaimer.
X * 2. Redistributions in binary form must reproduce the above copyright
X *    notice, this list of conditions and the following disclaimer in the
X *    documentation and/or other materials provided with the distribution.
X * 3. Neither the name of the University nor the names of its contributors
X *    may be used to endorse or promote products derived from this software
X *    without specific prior written permission.
X *
X * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
X * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
X * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
X * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
X * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
X * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
X * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
X * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
X * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
X * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
X * SUCH DAMAGE.
X *
X */
X
X/*
X * Kernel params Filesystem
X */
X
X#include <sys/cdefs.h>
X__KERNEL_RCSID(0, "$NetBSD: ptyfs_vfsops.c,v 1.64 2004/05/29 14:28:41 tron Exp $");
X
X#include <sys/param.h>
X#include <sys/systm.h>
X#include <sys/sysctl.h>
X#include <sys/conf.h>
X#include <sys/proc.h>
X#include <sys/vnode.h>
X#include <sys/mount.h>
X#include <sys/namei.h>
X#include <sys/dirent.h>
X#include <sys/malloc.h>
X#include <sys/syslog.h>
X#include <sys/select.h>
X#include <sys/tty.h>
X#include <sys/pty.h>
X
X#include <miscfs/specfs/specdev.h>
X#include <miscfs/ptyfs/ptyfs.h>
X
XMALLOC_DEFINE(M_PTYFSMNT, "ptyfs mount", "ptyfs mount structures");
X
Xvoid	ptyfs_init(void);
Xvoid	ptyfs_reinit(void);
Xvoid	ptyfs_done(void);
Xint	ptyfs_mount(struct mount *, const char *, void *, struct nameidata *,
X    struct proc *);
Xint	ptyfs_start(struct mount *, int, struct proc *);
Xint	ptyfs_unmount(struct mount *, int, struct proc *);
Xint	ptyfs_statvfs(struct mount *, struct statvfs *, struct proc *);
Xint	ptyfs_quotactl(struct mount *, int, uid_t, void *, struct proc *);
Xint	ptyfs_sync(struct mount *, int, struct ucred *, struct proc *);
Xint	ptyfs_vget(struct mount *, ino_t, struct vnode **);
Xint	ptyfs_fhtovp(struct mount *, struct fid *, struct vnode **);
Xint	ptyfs_checkexp(struct mount *, struct mbuf *, int *, struct ucred **);
Xint	ptyfs_vptofh(struct vnode *, struct fid *);
X
Xstatic int ptyfs__allocvp(struct ptm_pty *, struct proc *, struct vnode **,
X    dev_t, char);
Xstatic int ptyfs__makename(struct ptm_pty *, char *, size_t, dev_t, char);
X
X/*
X * ptm glue: When we mount, we make ptm point to us.
X */
Xstruct ptm_pty *ptyfs_save_ptm;
X
Xstruct ptm_pty ptm_ptyfspty = {
X	ptyfs__allocvp,
X	ptyfs__makename,
X	NULL
X};
X
Xstatic int
Xptyfs__makename(struct ptm_pty *pt, char *buf, size_t bufsiz, dev_t dev,
X    char ms)
X{
X	struct mount *mp = pt->arg;
X	size_t len;
X
X	switch (ms) {
X	case 'p':
X		/* We don't provide access to the master, should we? */
X		len = snprintf(buf, bufsiz, "/dev/null");
X		break;
X	case 't':
X		len = snprintf(buf, bufsiz, "%s/%d", mp->mnt_stat.f_mntonname,
X		    minor(dev));
X		break;
X	default:
X		return EINVAL;
X	}
X
X	return len >= bufsiz ? ENOSPC : 0;
X}
X
Xstatic int
X/*ARGSUSED*/
Xptyfs__allocvp(struct ptm_pty *pt, struct proc *p, struct vnode **vpp,
X    dev_t dev, char ms)
X{
X	struct mount *mp = pt->arg;
X	ptyfstype type;
X
X	switch (ms) {
X	case 'p':
X		type = PTYFSptc;
X		break;
X	case 't':
X		type = PTYFSpts;
X		break;
X	default:
X		return EINVAL;
X	}
X
X	return ptyfs_allocvp(mp, vpp, minor(dev), type, p);
X}
X
Xvoid
Xptyfs_init(void)
X{
X#ifdef _LKM
X	malloc_type_attach(M_PTYFSMNT);
X#endif
X	ptyfs_hashinit();
X}
X
Xvoid
Xptyfs_reinit(void)
X{
X	ptyfs_hashreinit();
X}
X
Xvoid
Xptyfs_done(void)
X{
X#ifdef _LKM
X	malloc_type_detach(M_PTYFSMNT);
X#endif
X	ptyfs_hashdone();
X}
X
X/*
X * Mount the Pseudo tty params filesystem
X */
Xint
Xptyfs_mount(struct mount *mp, const char *path, void *data, 
X    struct nameidata *ndp, struct proc *p)
X{
X	int error = 0;
X
X	if (UIO_MX & (UIO_MX - 1)) {
X		log(LOG_ERR, "ptyfs: invalid directory entry size");
X		return EINVAL;
X	}
X
X	if (mp->mnt_flag & MNT_GETARGS)
X		return 0;
X	/*
X	 * Update is a no-op
X	 */
X	if (mp->mnt_flag & MNT_UPDATE)
X		return EOPNOTSUPP;
X
X	mp->mnt_data = NULL;
X	mp->mnt_flag |= MNT_LOCAL;
X	vfs_getnewfsid(mp);
X
X	if ((error = set_statvfs_info(path, UIO_USERSPACE, "ptyfs",
X	    UIO_SYSSPACE, mp, p)) != 0) {
X		return error;
X	}
X
X	/* Point pty access to us */
X	if (ptyfs_save_ptm != NULL)
X		return EBUSY;
X
X	ptm_ptyfspty.arg = mp;
X	ptyfs_save_ptm = pty_sethandler(&ptm_ptyfspty);
X	return 0;
X}
X
X/*ARGSUSED*/
Xint
Xptyfs_start(struct mount *mp, int flags, struct proc *p)
X{
X	return 0;
X}
X
X/*ARGSUSED*/
Xint
Xptyfs_unmount(struct mount *mp, int mntflags, struct proc *p)
X{
X	int error;
X	int flags = 0;
X
X	if (mntflags & MNT_FORCE)
X		flags |= FORCECLOSE;
X
X	if ((error = vflush(mp, 0, flags)) != 0)
X		return (error);
X
X	/* Restore where pty access was pointing */
X	ptm_ptyfspty.arg = NULL;
X	(void)pty_sethandler(ptyfs_save_ptm);
X	ptyfs_save_ptm = NULL;
X	/*
X	 * Finally, throw away the ptyfs_mount structure
X	 */
X	return 0;
X}
X
Xint
Xptyfs_root(struct mount *mp, struct vnode **vpp)
X{
X	/* setup "." */
X	return ptyfs_allocvp(mp, vpp, 0, PTYFSroot, NULL);
X}
X
X/*ARGSUSED*/
Xint
Xptyfs_quotactl(struct mount *mp, int cmd, uid_t uid, void *arg, struct proc *p)
X{
X	return EOPNOTSUPP;
X}
X
X/*ARGSUSED*/
Xint
Xptyfs_statvfs(struct mount *mp, struct statvfs *sbp, struct proc *p)
X{
X	sbp->f_bsize = DEV_BSIZE;
X	sbp->f_frsize = DEV_BSIZE;
X	sbp->f_iosize = DEV_BSIZE;
X	sbp->f_blocks = 2;		/* 1K to keep df happy */
X	sbp->f_bfree = 0;
X	sbp->f_bavail = 0;
X	sbp->f_bresvd = 0;
X	sbp->f_files = 1024;	/* XXX lie */
X	sbp->f_ffree = 128;	/* XXX lie */
X	sbp->f_favail = 128;	/* XXX lie */
X	sbp->f_fresvd = 0;
X	sbp->f_namemax = MAXNAMLEN;
X	copy_statvfs_info(sbp, mp);
X	return 0;
X}
X
X/*ARGSUSED*/
Xint
Xptyfs_sync(struct mount *mp, int waitfor, struct ucred *uc, struct proc *p)
X{
X	return 0;
X}
X
X/*
X * Kernfs flat namespace lookup.
X * Currently unsupported.
X */
X/*ARGSUSED*/
Xint
Xptyfs_vget(struct mount *mp, ino_t ino, struct vnode **vpp)
X{
X	return EOPNOTSUPP;
X}
X
X/*ARGSUSED*/
Xint
Xptyfs_fhtovp(struct mount *mp, struct fid *fhp, struct vnode **vpp)
X{
X	return EOPNOTSUPP;
X}
X
X/*ARGSUSED*/
Xint
Xptyfs_checkexp(struct mount *mp, struct mbuf *mb, int *wh, struct ucred **anon)
X{
X	return EOPNOTSUPP;
X}
X
XSYSCTL_SETUP(sysctl_vfs_ptyfs_setup, "sysctl vfs.ptyfs subtree setup")
X{
X
X	sysctl_createv(clog, 0, NULL, NULL,
X		       CTLFLAG_PERMANENT,
X		       CTLTYPE_NODE, "vfs", NULL,
X		       NULL, 0, NULL, 0,
X		       CTL_VFS, CTL_EOL);
X	sysctl_createv(clog, 0, NULL, NULL,
X		       CTLFLAG_PERMANENT,
X		       CTLTYPE_NODE, "ptyfs",
X		       SYSCTL_DESCR("Pty file system"),
X		       NULL, 0, NULL, 0,
X		       CTL_VFS, 23, CTL_EOL);
X	/*
X	 * XXX the "23" above could be dynamic, thereby eliminating
X	 * one more instance of the "number to vfs" mapping problem,
X	 * but "23" is the order as taken from sys/mount.h
X	 */
X}
X
X
X/*ARGSUSED*/
Xint
Xptyfs_vptofh(struct vnode *vp, struct fid *fhp)
X{
X	return EOPNOTSUPP;
X}
X
Xextern const struct vnodeopv_desc ptyfs_vnodeop_opv_desc;
X
Xconst struct vnodeopv_desc * const ptyfs_vnodeopv_descs[] = {
X	&ptyfs_vnodeop_opv_desc,
X	NULL,
X};
X
Xstruct vfsops ptyfs_vfsops = {
X	MOUNT_PTYFS,
X	ptyfs_mount,
X	ptyfs_start,
X	ptyfs_unmount,
X	ptyfs_root,
X	ptyfs_quotactl,
X	ptyfs_statvfs,
X	ptyfs_sync,
X	ptyfs_vget,
X	ptyfs_fhtovp,
X	ptyfs_vptofh,
X	ptyfs_init,
X	ptyfs_reinit,
X	ptyfs_done,
X	NULL,
X	NULL,				/* vfs_mountroot */
X	ptyfs_checkexp,
X	(int (*)(struct mount *, struct vnode *, struct timespec *))eopnotsupp,
X	ptyfs_vnodeopv_descs,
X};
END-of-sys/miscfs/ptyfs/ptyfs_vfsops.c
echo x - sys/miscfs/ptyfs/ptyfs_vnops.c
sed 's/^X//' >sys/miscfs/ptyfs/ptyfs_vnops.c << 'END-of-sys/miscfs/ptyfs/ptyfs_vnops.c'
X/*	$NetBSD: ptyfs_vnops.c,v 1.113 2004/04/29 16:10:55 jrf Exp $	*/
X
X/*
X * Copyright (c) 1993, 1995
X *	The Regents of the University of California.  All rights reserved.
X *
X * This code is derived from software contributed to Berkeley by
X * Jan-Simon Pendry.
X *
X * Redistribution and use in source and binary forms, with or without
X * modification, are permitted provided that the following conditions
X * are met:
X * 1. Redistributions of source code must retain the above copyright
X *    notice, this list of conditions and the following disclaimer.
X * 2. Redistributions in binary form must reproduce the above copyright
X *    notice, this list of conditions and the following disclaimer in the
X *    documentation and/or other materials provided with the distribution.
X * 3. Neither the name of the University nor the names of its contributors
X *    may be used to endorse or promote products derived from this software
X *    without specific prior written permission.
X *
X * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
X * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
X * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
X * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
X * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
X * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
X * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
X * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
X * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
X * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
X * SUCH DAMAGE.
X *
X *	@(#)procfs_vnops.c	8.18 (Berkeley) 5/21/95
X */
X
X/*
X * Copyright (c) 1993 Jan-Simon Pendry
X *
X * This code is derived from software contributed to Berkeley by
X * Jan-Simon Pendry.
X *
X * Redistribution and use in source and binary forms, with or without
X * modification, are permitted provided that the following conditions
X * are met:
X * 1. Redistributions of source code must retain the above copyright
X *    notice, this list of conditions and the following disclaimer.
X * 2. Redistributions in binary form must reproduce the above copyright
X *    notice, this list of conditions and the following disclaimer in the
X *    documentation and/or other materials provided with the distribution.
X * 3. All advertising materials mentioning features or use of this software
X *    must display the following acknowledgement:
X *	This product includes software developed by the University of
X *	California, Berkeley and its contributors.
X * 4. Neither the name of the University nor the names of its contributors
X *    may be used to endorse or promote products derived from this software
X *    without specific prior written permission.
X *
X * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
X * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
X * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
X * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
X * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
X * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
X * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
X * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
X * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
X * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
X * SUCH DAMAGE.
X *
X *	@(#)procfs_vnops.c	8.18 (Berkeley) 5/21/95
X */
X
X/*
X * ptyfs vnode interface
X */
X
X#include <sys/cdefs.h>
X__KERNEL_RCSID(0, "$NetBSD: ptyfs_vnops.c,v 1.113 2004/04/29 16:10:55 jrf Exp $");
X
X#include <sys/param.h>
X#include <sys/systm.h>
X#include <sys/time.h>
X#include <sys/kernel.h>
X#include <sys/file.h>
X#include <sys/filedesc.h>
X#include <sys/proc.h>
X#include <sys/vnode.h>
X#include <sys/namei.h>
X#include <sys/malloc.h>
X#include <sys/mount.h>
X#include <sys/select.h>
X#include <sys/dirent.h>
X#include <sys/resourcevar.h>
X#include <sys/stat.h>
X#include <sys/conf.h>
X#include <sys/tty.h>
X#include <sys/pty.h>
X
X#include <uvm/uvm_extern.h>	/* for PAGE_SIZE */
X
X#include <machine/reg.h>
X
X#include <miscfs/genfs/genfs.h>
X#include <miscfs/ptyfs/ptyfs.h>
X
X/*
X * Vnode Operations.
X *
X */
X
Xint	ptyfs_lookup	(void *);
X#define	ptyfs_create	genfs_eopnotsupp
X#define	ptyfs_mknod	genfs_eopnotsupp
Xint	ptyfs_open	(void *);
Xint	ptyfs_close	(void *);
Xint	ptyfs_access	(void *);
Xint	ptyfs_getattr	(void *);
Xint	ptyfs_setattr	(void *);
Xint	ptyfs_read	(void *);
Xint	ptyfs_write	(void *);
X#define	ptyfs_fcntl	genfs_fcntl
Xint	ptyfs_ioctl	(void *);
Xint	ptyfs_poll	(void *);
Xint	ptyfs_kqfilter	(void *);
X#define ptyfs_revoke	genfs_revoke
X#define	ptyfs_mmap	genfs_eopnotsupp
X#define	ptyfs_fsync	genfs_nullop
X#define	ptyfs_seek	genfs_nullop
X#define	ptyfs_remove	genfs_eopnotsupp
X#define	ptyfs_link	genfs_abortop
X#define	ptyfs_rename	genfs_eopnotsupp
X#define	ptyfs_mkdir	genfs_eopnotsupp
X#define	ptyfs_rmdir	genfs_eopnotsupp
X#define	ptyfs_symlink	genfs_abortop
Xint	ptyfs_readdir	(void *);
X#define	ptyfs_readlink	genfs_eopnotsupp
X#define	ptyfs_abortop	genfs_abortop
Xint	ptyfs_inactive	(void *);
Xint	ptyfs_reclaim	(void *);
X#define	ptyfs_lock	genfs_lock
X#define	ptyfs_unlock	genfs_unlock
X#define	ptyfs_bmap	genfs_badop
X#define	ptyfs_strategy	genfs_badop
Xint	ptyfs_print	(void *);
Xint	ptyfs_pathconf	(void *);
X#define	ptyfs_islocked	genfs_islocked
X#define	ptyfs_advlock	genfs_einval
X#define	ptyfs_blkatoff	genfs_eopnotsupp
X#define	ptyfs_valloc	genfs_eopnotsupp
X#define	ptyfs_vfree	genfs_nullop
X#define	ptyfs_truncate	genfs_eopnotsupp
Xint	ptyfs_update	(void *);
X#define	ptyfs_bwrite	genfs_eopnotsupp
X#define ptyfs_putpages	genfs_null_putpages
X
Xstatic int ptyfs_chown(struct vnode *, uid_t, gid_t, struct ucred *,
X    struct proc *);
Xstatic int ptyfs_chmod(struct vnode *, mode_t, struct ucred *, struct proc *);
Xstatic void ptyfs_time(struct ptyfsnode *, struct timespec *,
X    struct timespec *);
Xstatic int atoi(const char *, size_t);
Xstatic u_int digits(u_int);
X
Xextern const struct cdevsw pts_cdevsw, ptc_cdevsw;
X
X/*
X * ptyfs vnode operations.
X */
Xint (**ptyfs_vnodeop_p)(void *);
Xconst struct vnodeopv_entry_desc ptyfs_vnodeop_entries[] = {
X	{ &vop_default_desc, vn_default_error },
X	{ &vop_lookup_desc, ptyfs_lookup },		/* lookup */
X	{ &vop_create_desc, ptyfs_create },		/* create */
X	{ &vop_mknod_desc, ptyfs_mknod },		/* mknod */
X	{ &vop_open_desc, ptyfs_open },			/* open */
X	{ &vop_close_desc, ptyfs_close },		/* close */
X	{ &vop_access_desc, ptyfs_access },		/* access */
X	{ &vop_getattr_desc, ptyfs_getattr },		/* getattr */
X	{ &vop_setattr_desc, ptyfs_setattr },		/* setattr */
X	{ &vop_read_desc, ptyfs_read },			/* read */
X	{ &vop_write_desc, ptyfs_write },		/* write */
X	{ &vop_ioctl_desc, ptyfs_ioctl },		/* ioctl */
X	{ &vop_fcntl_desc, ptyfs_fcntl },		/* fcntl */
X	{ &vop_poll_desc, ptyfs_poll },			/* poll */
X	{ &vop_kqfilter_desc, ptyfs_kqfilter },		/* kqfilter */
X	{ &vop_revoke_desc, ptyfs_revoke },		/* revoke */
X	{ &vop_mmap_desc, ptyfs_mmap },			/* mmap */
X	{ &vop_fsync_desc, ptyfs_fsync },		/* fsync */
X	{ &vop_seek_desc, ptyfs_seek },			/* seek */
X	{ &vop_remove_desc, ptyfs_remove },		/* remove */
X	{ &vop_link_desc, ptyfs_link },			/* link */
X	{ &vop_rename_desc, ptyfs_rename },		/* rename */
X	{ &vop_mkdir_desc, ptyfs_mkdir },		/* mkdir */
X	{ &vop_rmdir_desc, ptyfs_rmdir },		/* rmdir */
X	{ &vop_symlink_desc, ptyfs_symlink },		/* symlink */
X	{ &vop_readdir_desc, ptyfs_readdir },		/* readdir */
X	{ &vop_readlink_desc, ptyfs_readlink },		/* readlink */
X	{ &vop_abortop_desc, ptyfs_abortop },		/* abortop */
X	{ &vop_inactive_desc, ptyfs_inactive },		/* inactive */
X	{ &vop_reclaim_desc, ptyfs_reclaim },		/* reclaim */
X	{ &vop_lock_desc, ptyfs_lock },			/* lock */
X	{ &vop_unlock_desc, ptyfs_unlock },		/* unlock */
X	{ &vop_bmap_desc, ptyfs_bmap },			/* bmap */
X	{ &vop_strategy_desc, ptyfs_strategy },		/* strategy */
X	{ &vop_print_desc, ptyfs_print },		/* print */
X	{ &vop_islocked_desc, ptyfs_islocked },		/* islocked */
X	{ &vop_pathconf_desc, ptyfs_pathconf },		/* pathconf */
X	{ &vop_advlock_desc, ptyfs_advlock },		/* advlock */
X	{ &vop_blkatoff_desc, ptyfs_blkatoff },		/* blkatoff */
X	{ &vop_valloc_desc, ptyfs_valloc },		/* valloc */
X	{ &vop_vfree_desc, ptyfs_vfree },		/* vfree */
X	{ &vop_truncate_desc, ptyfs_truncate },		/* truncate */
X	{ &vop_update_desc, ptyfs_update },		/* update */
X	{ &vop_bwrite_desc, ptyfs_bwrite },		/* bwrite */
X	{ &vop_putpages_desc, ptyfs_putpages },		/* putpages */
X	{ NULL, NULL }
X};
Xconst struct vnodeopv_desc ptyfs_vnodeop_opv_desc =
X	{ &ptyfs_vnodeop_p, ptyfs_vnodeop_entries };
X
X#define PTY_MAKEDEV(pt)	pty_makedev((pt)->ptyfs_type == PTYFSpts ? 't' : 'p', \
X    (pt)->ptyfs_pty)
X/*
X * _inactive is called when the ptyfsnode
X * is vrele'd and the reference count goes
X * to zero.  (vp) will be on the vnode free
X * list, so to get it back vget() must be
X * used.
X *
X * for ptyfs, check if the process is still
X * alive and if it isn't then just throw away
X * the vnode by calling vgone().  this may
X * be overkill and a waste of time since the
X * chances are that the process will still be
X * there and PFIND is not free.
X *
X * (vp) is locked on entry, but must be unlocked on exit.
X */
Xint
Xptyfs_inactive(void *v)
X{
X	struct vop_inactive_args /* {
X		struct vnode *a_vp;
X		struct proc *a_p;
X	} */ *ap = v;
X	struct ptyfsnode *ptyfs = VTOPTYFS(ap->a_vp);
X
X	VOP_UNLOCK(ap->a_vp, 0);
X	if (pty_isfree(ptyfs->ptyfs_pty, 1))
X		vgone(ap->a_vp);
X
X	return 0;
X}
X
X/*
X * _reclaim is called when getnewvnode()
X * wants to make use of an entry on the vnode
X * free list.  at this time the filesystem needs
X * to free any private data and remove the node
X * from any private lists.
X */
Xint
Xptyfs_reclaim(void *v)
X{
X	struct vop_reclaim_args /* {
X		struct vnode *a_vp;
X	} */ *ap = v;
X
X	return ptyfs_freevp(ap->a_vp);
X}
X
X/*
X * Return POSIX pathconf information applicable to special devices.
X */
Xint
Xptyfs_pathconf(void *v)
X{
X	struct vop_pathconf_args /* {
X		struct vnode *a_vp;
X		int a_name;
X		register_t *a_retval;
X	} */ *ap = v;
X
X	switch (ap->a_name) {
X	case _PC_LINK_MAX:
X		*ap->a_retval = LINK_MAX;
X		return 0;
X	case _PC_MAX_CANON:
X		*ap->a_retval = MAX_CANON;
X		return 0;
X	case _PC_MAX_INPUT:
X		*ap->a_retval = MAX_INPUT;
X		return 0;
X	case _PC_PIPE_BUF:
X		*ap->a_retval = PIPE_BUF;
X		return 0;
X	case _PC_CHOWN_RESTRICTED:
X		*ap->a_retval = 1;
X		return 0;
X	case _PC_VDISABLE:
X		*ap->a_retval = _POSIX_VDISABLE;
X		return 0;
X	case _PC_SYNC_IO:
X		*ap->a_retval = 1;
X		return 0;
X	default:
X		return EINVAL;
X	}
X}
X
X/*
X * _print is used for debugging.
X * just print a readable description
X * of (vp).
X */
Xint
Xptyfs_print(void *v)
X{
X	struct vop_print_args /* {
X		struct vnode *a_vp;
X	} */ *ap = v;
X	struct ptyfsnode *ptyfs = VTOPTYFS(ap->a_vp);
X
X	printf("tag VT_PTYFS, type %d, pty %d\n",
X	    ptyfs->ptyfs_type, ptyfs->ptyfs_pty);
X	return 0;
X}
X
X/*
X * Invent attributes for ptyfsnode (vp) and store
X * them in (vap).
X * Directories lengths are returned as zero since
X * any real length would require the genuine size
X * to be computed, and nothing cares anyway.
X *
X * this is relatively minimal for ptyfs.
X */
Xint
Xptyfs_getattr(void *v)
X{
X	struct vop_getattr_args /* {
X		struct vnode *a_vp;
X		struct vattr *a_vap;
X		struct ucred *a_cred;
X		struct proc *a_p;
X	} */ *ap = v;
X	struct ptyfsnode *ptyfs = VTOPTYFS(ap->a_vp);
X	struct vattr *vap = ap->a_vap;
X
X	/* start by zeroing out the attributes */
X	VATTR_NULL(vap);
X
X	/* next do all the common fields */
X	vap->va_type = ap->a_vp->v_type;
X	vap->va_fileid = ptyfs->ptyfs_fileno;
X	vap->va_gen = 0;
X	vap->va_flags = 0;
X	vap->va_nlink = 1;
X	vap->va_blocksize = PAGE_SIZE;
X
X	vap->va_atime = ptyfs->ptyfs_atime;
X	vap->va_mtime = ptyfs->ptyfs_mtime;
X	vap->va_ctime = ptyfs->ptyfs_ctime;
X	vap->va_birthtime = ptyfs->ptyfs_birthtime;
X	vap->va_mode = ptyfs->ptyfs_mode;
X	vap->va_flags = ptyfs->ptyfs_flags;
X	vap->va_uid = ptyfs->ptyfs_uid;
X	vap->va_gid = ptyfs->ptyfs_gid;
X
X	switch (ptyfs->ptyfs_type) {
X	case PTYFSpts:
X	case PTYFSptc:
X		if (pty_isfree(ptyfs->ptyfs_pty, 1))
X			return ENOENT;
X		vap->va_bytes = vap->va_size = digits(ptyfs->ptyfs_pty);
X		vap->va_rdev = PTY_MAKEDEV(ptyfs);
X		break;
X	case PTYFSroot:
X		vap->va_rdev = 0;
X		vap->va_bytes = vap->va_size = DEV_BSIZE;
X		break;
X
X	default:
X		return EOPNOTSUPP;
X	}
X
X	return 0;
X}
X
X/*ARGSUSED*/
Xint
Xptyfs_setattr(void *v)
X{
X	struct vop_setattr_args /* {
X		struct vnodeop_desc *a_desc;
X		struct vnode *a_vp;
X		struct vattr *a_vap;
X		struct ucred *a_cred;
X		struct proc *a_p;
X	} */ *ap = v;
X	struct vnode *vp = ap->a_vp;
X	struct ptyfsnode *ptyfs = VTOPTYFS(vp);
X	struct vattr *vap = ap->a_vap;
X	struct ucred *cred = ap->a_cred;
X	struct proc *p = ap->a_p;
X	int error = 0;
X
X	if (vap->va_size != VNOVAL) {
X 		switch (ptyfs->ptyfs_type) {
X 		case PTYFSroot:
X 			return EISDIR;
X 		case PTYFSpts:
X 		case PTYFSptc:
X			break;
X		default:
X			return EINVAL;
X		}
X	}
X
X	if (vap->va_flags != VNOVAL) {
X		if (vp->v_mount->mnt_flag & MNT_RDONLY)
X			return EROFS;
X		if (cred->cr_uid != ptyfs->ptyfs_uid &&
X		    (error = suser(cred, &p->p_acflag)) != 0)
X			return error;
X		if (cred->cr_uid == 0) {
X			if ((ptyfs->ptyfs_flags & (SF_IMMUTABLE | SF_APPEND)) &&
X			    securelevel > 0)
X				return EPERM;
X			/* Snapshot flag cannot be set or cleared */
X			if ((vap->va_flags & SF_SNAPSHOT) != 
X			    (ptyfs->ptyfs_flags & SF_SNAPSHOT))
X				return EPERM;
X			ptyfs->ptyfs_flags = vap->va_flags;
X		} else {
X			if ((ptyfs->ptyfs_flags & (SF_IMMUTABLE | SF_APPEND)) ||
X			    (vap->va_flags & UF_SETTABLE) != vap->va_flags)
X				return EPERM;
X			if ((ptyfs->ptyfs_flags & SF_SETTABLE) !=
X			    (vap->va_flags & SF_SETTABLE))
X				return EPERM;
X			ptyfs->ptyfs_flags &= SF_SETTABLE;
X			ptyfs->ptyfs_flags |= (vap->va_flags & UF_SETTABLE);
X		}
X		ptyfs->ptyfs_flag |= PTYFS_CHANGE;
X		if (vap->va_flags & (IMMUTABLE | APPEND))
X			return 0;
X	}
X	if (ptyfs->ptyfs_flags & (IMMUTABLE | APPEND))
X		return EPERM;
X	/*
X	 * Go through the fields and update iff not VNOVAL.
X	 */
X	if (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL) {
X		if (vp->v_mount->mnt_flag & MNT_RDONLY)
X			return EROFS;
X		if (ptyfs->ptyfs_type == PTYFSroot)
X			return EPERM;
X		error = ptyfs_chown(vp, vap->va_uid, vap->va_gid, cred, p);
X		if (error)
X			return error;
X	}
X
X	if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL ||
X	    vap->va_birthtime.tv_sec != VNOVAL) {
X		if (vp->v_mount->mnt_flag & MNT_RDONLY)
X			return EROFS;
X		if ((ptyfs->ptyfs_flags & SF_SNAPSHOT) != 0)
X			return EPERM;
X		if (cred->cr_uid != ptyfs->ptyfs_uid &&
X		    (error = suser(cred, &p->p_acflag)) &&
X		    ((vap->va_vaflags & VA_UTIMES_NULL) == 0 || 
X		    (error = VOP_ACCESS(vp, VWRITE, cred, p)) != 0))
X			return (error);
X		if (vap->va_atime.tv_sec != VNOVAL)
X			if (!(vp->v_mount->mnt_flag & MNT_NOATIME))
X				ptyfs->ptyfs_flag |= PTYFS_ACCESS;
X		if (vap->va_mtime.tv_sec != VNOVAL)
X			ptyfs->ptyfs_flag |= PTYFS_CHANGE | PTYFS_MODIFY;
X		if (vap->va_birthtime.tv_sec != VNOVAL)
X			ptyfs->ptyfs_birthtime = vap->va_birthtime;
X		ptyfs->ptyfs_flag |= PTYFS_CHANGE;
X		error = VOP_UPDATE(vp, &vap->va_atime, &vap->va_mtime, 0);
X		if (error)
X			return error;
X	}
X	error = 0;
X	if (vap->va_mode != (mode_t)VNOVAL) {
X		if (vp->v_mount->mnt_flag & MNT_RDONLY)
X			return EROFS;
X		if (ptyfs->ptyfs_type == PTYFSroot)
X			return EPERM;
X		if ((ptyfs->ptyfs_flags & SF_SNAPSHOT) != 0 &&
X		    (vap->va_mode & (S_IXUSR | S_IWUSR | S_IXGRP | S_IWGRP |
X		     S_IXOTH | S_IWOTH)))
X			return EPERM;
X		error = ptyfs_chmod(vp, vap->va_mode, cred, p);
X	}
X	VN_KNOTE(vp, NOTE_ATTRIB);
X	return error;
X}
X
X/*
X * Change the mode on a file.
X * Inode must be locked before calling.
X */
Xstatic int
Xptyfs_chmod(struct vnode *vp, mode_t mode, struct ucred *cred, struct proc *p)
X{
X	struct ptyfsnode *ptyfs = VTOPTYFS(vp);
X	int		error;
X
X	if (cred->cr_uid != ptyfs->ptyfs_uid &&
X	    (error = suser(cred, &p->p_acflag)) != 0)
X		return error;
X	if (cred->cr_uid) {
X		if (mode & S_ISTXT)
X			return EFTYPE;
X		if (!groupmember(ptyfs->ptyfs_gid, cred))
X			return EPERM;
X	}
X	ptyfs->ptyfs_mode &= ~ALLPERMS;
X	ptyfs->ptyfs_mode |= (mode & ALLPERMS);
X	return 0;
X}
X
X/*
X * Perform chown operation on inode ip;
X * inode must be locked prior to call.
X */
Xstatic int
Xptyfs_chown(struct vnode *vp, uid_t uid, gid_t gid, struct ucred *cred,
X    struct proc *p)
X{
X	struct ptyfsnode *ptyfs = VTOPTYFS(vp);
X	int		error = 0;
X
X	if (uid == (uid_t)VNOVAL)
X		uid = ptyfs->ptyfs_uid;
X	if (gid == (gid_t)VNOVAL)
X		gid = ptyfs->ptyfs_gid;
X	/*
X	 * If we don't own the file, are trying to change the owner
X	 * of the file, or are not a member of the target group,
X	 * the caller's credentials must imply super-user privilege
X	 * or the call fails.
X	 */
X	if ((cred->cr_uid != ptyfs->ptyfs_uid || uid != ptyfs->ptyfs_uid ||
X	    (gid != ptyfs->ptyfs_gid &&
X	     !(cred->cr_gid == gid || groupmember((gid_t)gid, cred)))) &&
X	    ((error = suser(cred, &p->p_acflag)) != 0))
X		return error;
X
X	ptyfs->ptyfs_gid = gid;
X	ptyfs->ptyfs_uid = uid;
X	return 0;
X}
X
X/*
X * implement access checking.
X *
X * actually, the check for super-user is slightly
X * broken since it will allow read access to write-only
X * objects.  this doesn't cause any particular trouble
X * but does mean that the i/o entry points need to check
X * that the operation really does make sense.
X */
Xint
Xptyfs_access(void *v)
X{
X	struct vop_access_args /* {
X		struct vnode *a_vp;
X		int a_mode;
X		struct ucred *a_cred;
X		struct proc *a_p;
X	} */ *ap = v;
X	struct vattr va;
X	int error;
X
X	if ((error = VOP_GETATTR(ap->a_vp, &va, ap->a_cred, ap->a_p)) != 0)
X		return error;
X
X	return vaccess(va.va_type, va.va_mode,
X	    va.va_uid, va.va_gid, ap->a_mode, ap->a_cred);
X}
X
X/*
X * lookup.  this is incredibly complicated in the
X * general case, however for most pseudo-filesystems
X * very little needs to be done.
X *
X * Locking isn't hard here, just poorly documented.
X *
X * If we're looking up ".", just vref the parent & return it. 
X *
X * If we're looking up "..", unlock the parent, and lock "..". If everything
X * went ok, and we're on the last component and the caller requested the
X * parent locked, try to re-lock the parent. We do this to prevent lock
X * races.
X *
X * For anything else, get the needed node. Then unlock the parent if not
X * the last component or not LOCKPARENT (i.e. if we wouldn't re-lock the
X * parent in the .. case).
X *
X * We try to exit with the parent locked in error cases.
X */
Xint
Xptyfs_lookup(void *v)
X{
X	struct vop_lookup_args /* {
X		struct vnode * a_dvp;
X		struct vnode ** a_vpp;
X		struct componentname * a_cnp;
X	} */ *ap = v;
X	struct componentname *cnp = ap->a_cnp;
X	struct vnode **vpp = ap->a_vpp;
X	struct vnode *dvp = ap->a_dvp;
X	const char *pname = cnp->cn_nameptr;
X	struct ptyfsnode *ptyfs;
X	int pty, error, wantpunlock;
X
X	*vpp = NULL;
X	cnp->cn_flags &= ~PDIRUNLOCK;
X
X	if (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)
X		return EROFS;
X
X	if (cnp->cn_namelen == 1 && *pname == '.') {
X		*vpp = dvp;
X		VREF(dvp);
X		return 0;
X	}
X
X	wantpunlock = ~cnp->cn_flags & (LOCKPARENT | ISLASTCN);
X	ptyfs = VTOPTYFS(dvp);
X	switch (ptyfs->ptyfs_type) {
X	case PTYFSroot:
X		/*
X		 * Shouldn't get here with .. in the root node.
X		 */
X		if (cnp->cn_flags & ISDOTDOT) 
X			return EIO;
X
X		pty = atoi(pname, cnp->cn_namelen);
X
X		if (pty < 0 || pty >= npty || pty_isfree(pty, 1))
X			break;
X
X		error = ptyfs_allocvp(dvp->v_mount, vpp, pty, PTYFSpts,
X		    curproc);
X		if (error == 0 && wantpunlock) {
X			VOP_UNLOCK(dvp, 0);
X			cnp->cn_flags |= PDIRUNLOCK;
X		}
X		return error;
X
X	default:
X		return ENOTDIR;
X	}
X
X	return cnp->cn_nameiop == LOOKUP ? ENOENT : EROFS;
X}
X
X/*
X * readdir returns directory entries from ptyfsnode (vp).
X *
X * the strategy here with ptyfs is to generate a single
X * directory entry at a time (struct dirent) and then
X * copy that out to userland using uiomove.  a more efficent
X * though more complex implementation, would try to minimize
X * the number of calls to uiomove().  for ptyfs, this is
X * hardly worth the added code complexity.
X *
X * this should just be done through read()
X */
Xint
Xptyfs_readdir(void *v)
X{
X	struct vop_readdir_args /* {
X		struct vnode *a_vp;
X		struct uio *a_uio;
X		struct ucred *a_cred;
X		int *a_eofflag;
X		off_t **a_cookies;
X		int *a_ncookies;
X	} */ *ap = v;
X	struct uio *uio = ap->a_uio;
X	struct dirent d;
X	struct ptyfsnode *ptyfs;
X	off_t i;
X	int error;
X	off_t *cookies = NULL;
X	int ncookies;
X	struct vnode *vp;
X	int nc = 0;
X
X	vp = ap->a_vp;
X	ptyfs = VTOPTYFS(vp);
X
X	if (uio->uio_resid < UIO_MX)
X		return EINVAL;
X	if (uio->uio_offset < 0)
X		return EINVAL;
X
X	error = 0;
X	i = uio->uio_offset;
X	(void)memset(&d, 0, sizeof(d));
X	d.d_reclen = UIO_MX;
X	ncookies = uio->uio_resid / UIO_MX;
X
X	switch (ptyfs->ptyfs_type) {
X	case PTYFSroot: /* root */
X
X		if (i >= npty)
X			return 0;
X
X		if (ap->a_ncookies) {
X			ncookies = min(ncookies, (npty + 2 - i));
X			cookies = malloc(ncookies * sizeof (off_t),
X			    M_TEMP, M_WAITOK);
X			*ap->a_cookies = cookies;
X		}
X
X		for (; i < 2; i++) {
X			switch (i) {
X			case 0:		/* `.' */
X			case 1:		/* `..' */
X				d.d_fileno = PTYFS_FILENO(0, PTYFSroot);
X				d.d_namlen = i + 1;
X				(void)memcpy(d.d_name, "..", d.d_namlen);
X				d.d_name[i + 1] = '\0';
X				d.d_type = DT_DIR;
X				break;
X			}
X			if ((error = uiomove(&d, UIO_MX, uio)) != 0)
X				break;
X			if (cookies)
X				*cookies++ = i + 1;
X			nc++;
X		}
X		if (error) {
X			ncookies = nc;
X			break;
X		}
X		for (; uio->uio_resid >= UIO_MX && i < npty; i++) {
X			/* check for used ptys */
X			if (pty_isfree(i - 2, 1))
X				continue;
X
X			d.d_fileno = PTYFS_FILENO(i - 2, PTYFSpts);
X			d.d_namlen = snprintf(d.d_name, sizeof(d.d_name),
X			    "%lld", (long long)(i - 2));
X			d.d_type = DT_CHR;
X			if ((error = uiomove(&d, UIO_MX, uio)) != 0)
X				break;
X			if (cookies)
X				*cookies++ = i + 1;
X			nc++;
X		}
X		ncookies = nc;
X		break;
X
X	default:
X		error = ENOTDIR;
X		break;
X	}
X
X	if (ap->a_ncookies) {
X		if (error) {
X			if (cookies)
X				free(*ap->a_cookies, M_TEMP);
X			*ap->a_ncookies = 0;
X			*ap->a_cookies = NULL;
X		} else
X			*ap->a_ncookies = ncookies;
X	}
X	uio->uio_offset = i;
X	return error;
X}
X
Xint
Xptyfs_open(void *v)
X{
X	struct vop_open_args /* {
X		struct vnode *a_vp;
X		int  a_mode;
X		struct ucred *a_cred;
X		struct proc *a_p;
X	} */ *ap = v;
X	struct vnode *vp = ap->a_vp;
X	struct ptyfsnode *pt = VTOPTYFS(vp);
X
X	switch (pt->ptyfs_type) {
X	case PTYFSpts:
X		return (*pts_cdevsw.d_open)(
X		    PTY_MAKEDEV(pt), ap->a_mode, 0, ap->a_p);
X	case PTYFSptc:
X		return (*ptc_cdevsw.d_open)(
X		    PTY_MAKEDEV(pt), ap->a_mode, 0, ap->a_p);
X	default:
X		return 0;
X	}
X
X}
X
Xint
Xptyfs_close(void *v)
X{
X	struct vop_close_args /* {
X		struct vnode *a_vp;
X		int  a_fflag;
X		struct ucred *a_cred;
X		struct proc *a_p;
X	} */ *ap = v;
X	struct vnode *vp = ap->a_vp;
X	struct ptyfsnode *pt = VTOPTYFS(vp);
X
X	pt->ptyfs_flag |= PTYFS_CHANGE|PTYFS_ACCESS;
X	switch (pt->ptyfs_type) {
X	case PTYFSpts:
X		return (*pts_cdevsw.d_close)(
X		    PTY_MAKEDEV(pt), ap->a_fflag, 0, ap->a_p);
X	case PTYFSptc:
X		return (*ptc_cdevsw.d_close)(
X		    PTY_MAKEDEV(pt), ap->a_fflag, 0, ap->a_p);
X	default:
X		return 0;
X	}
X
X}
X
Xint
Xptyfs_read(void *v)
X{
X	struct vop_read_args /* {
X		struct vnode *a_vp;
X		struct uio *a_uio;
X		int  a_ioflag;
X		struct ucred *a_cred;
X	} */ *ap = v;
X	struct vnode *vp = ap->a_vp;
X	struct ptyfsnode *pt = VTOPTYFS(vp);
X	int error;
X
X	pt->ptyfs_flag |= PTYFS_ACCESS;
X	switch (pt->ptyfs_type) {
X	case PTYFSpts:
X		VOP_UNLOCK(vp, 0);
X		error = (*pts_cdevsw.d_read)(
X		    PTY_MAKEDEV(pt), ap->a_uio, ap->a_ioflag);
X		vn_lock(vp, LK_RETRY|LK_EXCLUSIVE);
X		return error;
X	case PTYFSptc:
X		VOP_UNLOCK(vp, 0);
X		error = (*ptc_cdevsw.d_read)(
X		    PTY_MAKEDEV(pt), ap->a_uio, ap->a_ioflag);
X		vn_lock(vp, LK_RETRY|LK_EXCLUSIVE);
X		return error;
X	default:
X		return EOPNOTSUPP;
X	}
X}
X
Xint
Xptyfs_write(void *v)
X{
X	struct vop_write_args /* {
X		struct vnode *a_vp;
X		struct uio *a_uio;
X		int  a_ioflag;
X		struct ucred *a_cred;
X	} */ *ap = v;
X	int error;
X	struct vnode *vp = ap->a_vp;
X	struct ptyfsnode *pt = VTOPTYFS(vp);
X
X	pt->ptyfs_flag |= PTYFS_MODIFY;
X	switch (pt->ptyfs_type) {
X	case PTYFSpts:
X		VOP_UNLOCK(vp, 0);
X		error = (*pts_cdevsw.d_write)(
X		    PTY_MAKEDEV(pt), ap->a_uio, ap->a_ioflag);
X		vn_lock(vp, LK_RETRY|LK_EXCLUSIVE);
X		return error;
X	case PTYFSptc:
X		VOP_UNLOCK(vp, 0);
X		error = (*ptc_cdevsw.d_write)(
X		    PTY_MAKEDEV(pt), ap->a_uio, ap->a_ioflag);
X		vn_lock(vp, LK_RETRY|LK_EXCLUSIVE);
X		return error;
X	default:
X		return EOPNOTSUPP;
X	}
X}
X
Xint
Xptyfs_ioctl(void *v)
X{
X	struct vop_ioctl_args /* {
X		struct vnode *a_vp;
X		u_long a_command;
X		void *a_data;
X		int  a_fflag;
X		struct ucred *a_cred;
X		struct proc *a_p;
X	} */ *ap = v;
X	struct vnode *vp = ap->a_vp;
X	struct ptyfsnode *pt = VTOPTYFS(vp);
X
X	switch (pt->ptyfs_type) {
X	case PTYFSpts:
X		return (*pts_cdevsw.d_ioctl)(
X		    PTY_MAKEDEV(pt), ap->a_command,
X		    ap->a_data, ap->a_fflag, ap->a_p);
X	case PTYFSptc:
X		return (*ptc_cdevsw.d_ioctl)(
X		    PTY_MAKEDEV(pt), ap->a_command,
X		    ap->a_data, ap->a_fflag, ap->a_p);
X	default:
X		return EOPNOTSUPP;
X	}
X}
X
Xint
Xptyfs_poll(void *v)
X{
X	struct vop_poll_args /* {
X		struct vnode *a_vp;
X		int a_events;
X		struct proc *a_p;
X	} */ *ap = v;
X	struct vnode *vp = ap->a_vp;
X	struct ptyfsnode *pt = VTOPTYFS(vp);
X
X	switch (pt->ptyfs_type) {
X	case PTYFSpts:
X		return (*pts_cdevsw.d_poll)(PTY_MAKEDEV(pt),
X		    ap->a_events, ap->a_p);
X	case PTYFSptc:
X		return (*ptc_cdevsw.d_poll)(PTY_MAKEDEV(pt),
X		    ap->a_events, ap->a_p);
X	default:
X		return genfs_poll(v);
X	}
X}
X
Xint
Xptyfs_kqfilter(void *v)
X{
X	struct vop_kqfilter_args /* {
X		struct vnode *a_vp;
X		struct knote *a_kn;
X	} */ *ap = v;
X	struct vnode *vp = ap->a_vp;
X	struct ptyfsnode *pt = VTOPTYFS(vp);
X
X	switch (pt->ptyfs_type) {
X	case PTYFSpts:
X		return (*pts_cdevsw.d_kqfilter)(PTY_MAKEDEV(pt),
X		    ap->a_kn);
X	case PTYFSptc:
X		return (*ptc_cdevsw.d_kqfilter)(PTY_MAKEDEV(pt),
X		    ap->a_kn);
X	default:
X		return genfs_kqfilter(v);
X	}
X}
X
Xint
Xptyfs_update(v)
X	void *v;
X{
X	struct vop_update_args /* {
X		struct vnode *a_vp;
X		struct timespec *a_access;
X		struct timespec *a_modify;
X		int a_flags;
X	} */ *ap = v;
X	struct ptyfsnode *ptyfs = VTOPTYFS(ap->a_vp);
X	struct timespec ts;
X
X	if (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY)
X		return 0;
X
X	TIMEVAL_TO_TIMESPEC(&time, &ts);
X	if (ap->a_access == NULL)
X		ap->a_access = &ts;
X	if (ap->a_modify == NULL)
X		ap->a_modify = &ts;
X	ptyfs_time(ptyfs, ap->a_access, ap->a_modify);
X	return 0;
X}
X
Xstatic void
Xptyfs_time(struct ptyfsnode *ptyfs, struct timespec *atime,
X    struct timespec *mtime)
X{
X	if (ptyfs->ptyfs_flag & PTYFS_MODIFY) {
X		ptyfs->ptyfs_mtime = *mtime;
X		ptyfs->ptyfs_atime = *atime;
X	} else if (ptyfs->ptyfs_flag & PTYFS_ACCESS)
X		ptyfs->ptyfs_atime = *atime;
X	if (ptyfs->ptyfs_flag & PTYFS_CHANGE)
X		ptyfs->ptyfs_ctime = *atime;
X	ptyfs->ptyfs_flag = 0;
X}
X	
X/*
X * convert decimal ascii to int
X */
Xstatic int
Xatoi(const char *b, size_t len)
X{
X	int p = 0;
X
X	while (len--) {
X		char c = *b++;
X		if (c < '0' || c > '9')
X			return -1;
X		p = 10 * p + (c - '0');
X	}
X
X	return p;
X}
X
X/*
X * Return the number of decimal digits
X */
Xstatic u_int
Xdigits(u_int i)
X{
X	u_int d;
X	for (d = 1; i != 0; d++)
X		i /= 10;
X	return d;
X}
END-of-sys/miscfs/ptyfs/ptyfs_vnops.c
echo x - sys/sys/pty.h
sed 's/^X//' >sys/sys/pty.h << 'END-of-sys/sys/pty.h'
X/*	$NetBSD$	*/
X
X/*-
X * Copyright (c) 2004 The NetBSD Foundation, Inc.
X * All rights reserved.
X *
X * This code is derived from software contributed to The NetBSD Foundation
X * by Christos Zoulas.
X *
X * Redistribution and use in source and binary forms, with or without
X * modification, are permitted provided that the following conditions
X * are met:
X * 1. Redistributions of source code must retain the above copyright
X *    notice, this list of conditions and the following disclaimer.
X * 2. Redistributions in binary form must reproduce the above copyright
X *    notice, this list of conditions and the following disclaimer in the
X *    documentation and/or other materials provided with the distribution.
X * 3. All advertising materials mentioning features or use of this software
X *    must display the following acknowledgement:
X *        This product includes software developed by the NetBSD
X *        Foundation, Inc. and its contributors.
X * 4. Neither the name of The NetBSD Foundation nor the names of its
X *    contributors may be used to endorse or promote products derived
X *    from this software without specific prior written permission.
X *
X * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
X * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
X * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
X * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
X * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
X * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
X * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
X * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
X * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
X * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
X * POSSIBILITY OF SUCH DAMAGE.
X */
X#ifndef _SYS_PTY_H_
X#define _SYS_PTY_H_
X
Xint pty_isfree(int, int);
X
X#ifndef NO_DEV_PTM
Xvoid ptmattach(int);
Xint pty_fill_ptmget(dev_t, int, int, void *);
Xint pty_grant_slave(struct proc *, dev_t);
Xint pty_check(int);
Xdev_t pty_makedev(char, int);
Xint pty_vn_open(struct vnode *, struct proc *);
Xstruct ptm_pty *pty_sethandler(struct ptm_pty *);
X#endif
X
Xstruct ptm_pty {
X	int (*allocvp)(struct ptm_pty *, struct proc *, struct vnode **, dev_t,
X	    char); 
X	int (*makename)(struct ptm_pty *, char *, size_t, dev_t, char);
X	void *arg;
X};
X
Xextern int npty;
X
X#ifdef COMPAT_BSDPTY
Xextern struct ptm_pty ptm_bsdpty;
X#endif
X
X#endif /* _SYS_PTY_H_ */
END-of-sys/sys/pty.h
exit