/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* The lookup is based on the internal pty table. We also
* override readdir in order to delete pts nodes no longer
* in use.
*/
#include <sys/sysmacros.h>
#include <sys/vfs_opreg.h>
#define DEVPTS_UID_DEFAULT 0
VCHR, /* va_type */
DEVPTS_UID_DEFAULT, /* va_uid */
DEVPTS_GID_DEFAULT, /* va_gid */
0 /* 0 hereafter */
};
struct vnodeops *
devpts_getvnodeops(void)
{
return (devpts_vnodeops);
}
/*
* Convert string to minor number. Some care must be taken
* as we are processing user input. Catch cases like
*/
static int
{
long uminor = 0;
return (EINVAL);
*mp = 0;
return (EINVAL);
}
return (0);
}
/*
* Check if a pts sdev_node is still valid - i.e. it represents a current pty.
* This serves two purposes
* - only valid pts nodes are returned during lookup() and readdir().
* - since pts sdev_nodes are not actively destroyed when a pty goes
* away, we use the validator to do deferred cleanup i.e. when such
* nodes are encountered during subsequent lookup() and readdir().
*/
/*ARGSUSED*/
int
{
/* validate only READY nodes */
sdcmn_err(("dev fs: skipping: node not ready %s(%p)",
return (SDEV_VTOR_SKIP);
}
return (SDEV_VTOR_INVALID);
}
/*
* Check if pts driver is attached
*/
sdcmn_err7(("devpts_validate: slave not attached\n"));
return (SDEV_VTOR_INVALID);
}
if (ptms_minor_exists(min)) {
sdcmn_err7(("devpts_validate: valid in different zone "
"%s\n", nm));
return (SDEV_VTOR_SKIP);
} else {
sdcmn_err7(("devpts_validate: %s not valid pty\n",
nm));
return (SDEV_VTOR_INVALID);
}
}
gethrestime(&now);
}
return (SDEV_VTOR_VALID);
}
/*
* This callback is invoked from devname_lookup_func() to create
* a pts entry when the node is not found in the cache.
*/
/*ARGSUSED*/
static int
{
return (-1);
}
/*
* Check if pts driver is attached and if it is
* get the major number.
*/
maj = ptms_slave_attached();
sdcmn_err7(("devpts_create_rvp: slave not attached\n"));
return (-1);
}
/*
* Only allow creation of ptys allocated to our zone
*/
sdcmn_err7(("devpts_create_rvp: %s not valid pty"
"or not valid in this zone\n", nm));
return (-1);
}
/*
* This is a valid pty (at least at this point in time).
* Create the node by setting the attribute. The rest
* is taken care of by devname_lookup_func().
*/
*vap = devpts_vattr;
gethrestime(&now);
return (0);
}
/*
* Clean pts sdev_nodes that are no longer valid.
*/
static void
{
}
/* validate and prune only ready nodes */
continue;
case SDEV_VTOR_VALID:
case SDEV_VTOR_SKIP:
continue;
case SDEV_VTOR_INVALID:
case SDEV_VTOR_STALE:
sdcmn_err7(("prunedir: destroy invalid "
break;
}
continue;
/* remove the cache node */
}
}
/*
* If the entry does not exist, the devpts_create_rvp() callback
* is invoked to create it. Nodes do not persist across reboot.
*
* There is a potential denial of service here via
* applied to the node, apply to the fattached file and not
* to the underlying pts node. As a result when the previous
* user fdetaches, the pts node is still owned by the previous
* owner. To prevent this we don't allow fattach() on top of a pts
* node. This is done by a modification in the namefs filesystem
* We do this via VOP_REALVP() on the underlying specfs node.
* sdev_nodes currently don't have a realvp. If a realvp is ever
* created for sdev_nodes, then VOP_REALVP() will return the
* actual realvp (possibly a ufs vnode). This will defeat the check
* in namefs code which checks if VOP_REALVP() returns a devpts
* this condition. If sdev_nodes ever get a VOP_REALVP() entry point,
* change the code in the namefs filesystem code (in nm_mount()) to
* access the realvp of the specfs node directly instead of using
* VOP_REALVP().
*/
/*ARGSUSED3*/
static int
{
int error;
if (error == 0) {
case VCHR:
break;
case VDIR:
break;
default:
break;
}
}
return (error);
}
/*
* We allow create to find existing nodes
* - if the node doesn't exist - EROFS
* - creating an existing dir read-only succeeds, otherwise EISDIR
* - exclusive creates fail - EEXIST
*/
/*ARGSUSED2*/
static int
{
int error;
NULL);
if (error == 0) {
else
if (error) {
} else
}
return (error);
}
/*
* Display all instantiated pts (slave) device nodes.
* device succeeds.
*/
/*ARGSUSED4*/
static int
{
if (uiop->uio_offset == 0) {
}
}
static int
{
return (0);
}
/*ARGSUSED4*/
static int
{
}
/*
* We override lookup and readdir to build entries based on the
* in kernel pty table. Also override setattr/setsecattr to
* avoid persisting permissions.
*/
};