facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai/*
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * CDDL HEADER START
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai *
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * The contents of this file are subject to the terms of the
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * Common Development and Distribution License (the "License").
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * You may not use this file except in compliance with the License.
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai *
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * or http://www.opensolaris.org/os/licensing.
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * See the License for the specific language governing permissions
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * and limitations under the License.
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai *
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * When distributing Covered Code, include this CDDL HEADER in each
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * If applicable, add the following below this CDDL HEADER, with the
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * fields enclosed by brackets "[]" replaced with your own identifying
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * information: Portions Copyright [yyyy] [name of copyright owner]
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai *
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * CDDL HEADER END
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai */
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai/*
aac43a5f8f51bcc570ff0ae9fad0380daf839ad9jg * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * Use is subject to license terms.
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai */
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai/*
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * vnode ops for the /dev/pts directory
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * The lookup is based on the internal pty table. We also
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * override readdir in order to delete pts nodes no longer
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * in use.
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai */
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai#include <sys/types.h>
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai#include <sys/param.h>
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai#include <sys/sysmacros.h>
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai#include <sys/sunndi.h>
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai#include <fs/fs_subr.h>
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai#include <sys/fs/dv_node.h>
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai#include <sys/fs/sdev_impl.h>
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai#include <sys/policy.h>
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai#include <sys/ptms.h>
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai#include <sys/stat.h>
aa59c4cb15a6ac5d4e585dadf7a055b580abf579rsb#include <sys/vfs_opreg.h>
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai#define DEVPTS_UID_DEFAULT 0
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai#define DEVPTS_GID_DEFAULT 3
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai#define DEVPTS_DEVMODE_DEFAULT (0620)
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai#define isdigit(ch) ((ch) >= '0' && (ch) <= '9')
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllaistatic vattr_t devpts_vattr = {
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai AT_TYPE|AT_MODE|AT_UID|AT_GID, /* va_mask */
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai VCHR, /* va_type */
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai S_IFCHR | DEVPTS_DEVMODE_DEFAULT, /* va_mode */
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai DEVPTS_UID_DEFAULT, /* va_uid */
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai DEVPTS_GID_DEFAULT, /* va_gid */
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai 0 /* 0 hereafter */
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai};
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllaistruct vnodeops *devpts_vnodeops;
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllaistruct vnodeops *
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllaidevpts_getvnodeops(void)
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai{
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai return (devpts_vnodeops);
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai}
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai/*
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * Convert string to minor number. Some care must be taken
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * as we are processing user input. Catch cases like
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * /dev/pts/4foo and /dev/pts/-1
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai */
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllaistatic int
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllaidevpts_strtol(const char *nm, minor_t *mp)
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai{
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai long uminor = 0;
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai char *endptr = NULL;
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai if (nm == NULL || !isdigit(*nm))
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai return (EINVAL);
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai *mp = 0;
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai if (ddi_strtol(nm, &endptr, 10, &uminor) != 0 ||
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai *endptr != '\0' || uminor < 0) {
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai return (EINVAL);
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai }
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai
bc1009abdd0a493796645bd983c1601396c09a5fjg *mp = (minor_t)uminor;
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai return (0);
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai}
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai/*
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * Check if a pts sdev_node is still valid - i.e. it represents a current pty.
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * This serves two purposes
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * - only valid pts nodes are returned during lookup() and readdir().
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * - since pts sdev_nodes are not actively destroyed when a pty goes
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * away, we use the validator to do deferred cleanup i.e. when such
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * nodes are encountered during subsequent lookup() and readdir().
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai */
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai/*ARGSUSED*/
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllaiint
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllaidevpts_validate(struct sdev_node *dv)
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai{
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai minor_t min;
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai uid_t uid;
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai gid_t gid;
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai timestruc_t now;
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai char *nm = dv->sdev_name;
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai ASSERT(dv->sdev_state == SDEV_READY);
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai /* validate only READY nodes */
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai if (dv->sdev_state != SDEV_READY) {
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai sdcmn_err(("dev fs: skipping: node not ready %s(%p)",
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai nm, (void *)dv));
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai return (SDEV_VTOR_SKIP);
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai }
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai if (devpts_strtol(nm, &min) != 0) {
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai sdcmn_err7(("devpts_validate: not a valid minor: %s\n", nm));
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai return (SDEV_VTOR_INVALID);
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai }
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai /*
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * Check if pts driver is attached
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai */
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai if (ptms_slave_attached() == (major_t)-1) {
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai sdcmn_err7(("devpts_validate: slave not attached\n"));
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai return (SDEV_VTOR_INVALID);
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai }
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai if (ptms_minor_valid(min, &uid, &gid) == 0) {
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai if (ptms_minor_exists(min)) {
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai sdcmn_err7(("devpts_validate: valid in different zone "
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai "%s\n", nm));
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai return (SDEV_VTOR_SKIP);
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai } else {
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai sdcmn_err7(("devpts_validate: %s not valid pty\n",
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai nm));
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai return (SDEV_VTOR_INVALID);
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai }
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai }
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai ASSERT(dv->sdev_attr);
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai if (dv->sdev_attr->va_uid != uid || dv->sdev_attr->va_gid != gid) {
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai dv->sdev_attr->va_uid = uid;
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai dv->sdev_attr->va_gid = gid;
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai gethrestime(&now);
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai dv->sdev_attr->va_atime = now;
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai dv->sdev_attr->va_mtime = now;
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai dv->sdev_attr->va_ctime = now;
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai sdcmn_err7(("devpts_validate: update uid/gid/times%s\n", nm));
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai }
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai return (SDEV_VTOR_VALID);
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai}
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai/*
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * This callback is invoked from devname_lookup_func() to create
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * a pts entry when the node is not found in the cache.
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai */
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai/*ARGSUSED*/
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllaistatic int
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllaidevpts_create_rvp(struct sdev_node *ddv, char *nm,
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai void **arg, cred_t *cred, void *whatever, char *whichever)
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai{
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai minor_t min;
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai major_t maj;
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai uid_t uid;
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai gid_t gid;
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai timestruc_t now;
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai struct vattr *vap = (struct vattr *)arg;
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai if (devpts_strtol(nm, &min) != 0) {
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai sdcmn_err7(("devpts_create_rvp: not a valid minor: %s\n", nm));
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai return (-1);
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai }
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai /*
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * Check if pts driver is attached and if it is
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * get the major number.
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai */
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai maj = ptms_slave_attached();
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai if (maj == (major_t)-1) {
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai sdcmn_err7(("devpts_create_rvp: slave not attached\n"));
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai return (-1);
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai }
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai /*
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * Only allow creation of ptys allocated to our zone
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai */
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai if (!ptms_minor_valid(min, &uid, &gid)) {
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai sdcmn_err7(("devpts_create_rvp: %s not valid pty"
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai "or not valid in this zone\n", nm));
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai return (-1);
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai }
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai /*
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * This is a valid pty (at least at this point in time).
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * Create the node by setting the attribute. The rest
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * is taken care of by devname_lookup_func().
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai */
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai *vap = devpts_vattr;
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai vap->va_rdev = makedevice(maj, min);
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai vap->va_uid = uid;
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai vap->va_gid = gid;
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai gethrestime(&now);
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai vap->va_atime = now;
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai vap->va_mtime = now;
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai vap->va_ctime = now;
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai return (0);
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai}
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai/*
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * Clean pts sdev_nodes that are no longer valid.
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai */
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllaistatic void
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllaidevpts_prunedir(struct sdev_node *ddv)
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai{
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai struct vnode *vp;
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai struct sdev_node *dv, *next = NULL;
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai int (*vtor)(struct sdev_node *) = NULL;
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai ASSERT(ddv->sdev_flags & SDEV_VTOR);
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai vtor = (int (*)(struct sdev_node *))sdev_get_vtor(ddv);
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai ASSERT(vtor);
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai if (rw_tryupgrade(&ddv->sdev_contents) == NULL) {
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai rw_exit(&ddv->sdev_contents);
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai rw_enter(&ddv->sdev_contents, RW_WRITER);
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai }
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai
aac43a5f8f51bcc570ff0ae9fad0380daf839ad9jg for (dv = SDEV_FIRST_ENTRY(ddv); dv; dv = next) {
aac43a5f8f51bcc570ff0ae9fad0380daf839ad9jg next = SDEV_NEXT_ENTRY(ddv, dv);
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai /* validate and prune only ready nodes */
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai if (dv->sdev_state != SDEV_READY)
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai continue;
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai switch (vtor(dv)) {
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai case SDEV_VTOR_VALID:
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai case SDEV_VTOR_SKIP:
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai continue;
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai case SDEV_VTOR_INVALID:
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk case SDEV_VTOR_STALE:
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai sdcmn_err7(("prunedir: destroy invalid "
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai "node: %s(%p)\n", dv->sdev_name, (void *)dv));
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai break;
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai }
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai vp = SDEVTOV(dv);
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai if (vp->v_count > 0)
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai continue;
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai SDEV_HOLD(dv);
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai /* remove the cache node */
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai (void) sdev_cache_update(ddv, &dv, dv->sdev_name,
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai SDEV_CACHE_DELETE);
9e5aa9d8a21f8efa8ba9c9e4a0aa6edc66d07eb2Robert Mustacchi SDEV_RELE(dv);
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai }
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai rw_downgrade(&ddv->sdev_contents);
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai}
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai/*
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * Lookup for /dev/pts directory
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * If the entry does not exist, the devpts_create_rvp() callback
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * is invoked to create it. Nodes do not persist across reboot.
49e92448e558772c002444c0d92e7a31d529d046vikram *
49e92448e558772c002444c0d92e7a31d529d046vikram * There is a potential denial of service here via
49e92448e558772c002444c0d92e7a31d529d046vikram * fattach on top of a /dev/pts node - any permission changes
49e92448e558772c002444c0d92e7a31d529d046vikram * applied to the node, apply to the fattached file and not
49e92448e558772c002444c0d92e7a31d529d046vikram * to the underlying pts node. As a result when the previous
49e92448e558772c002444c0d92e7a31d529d046vikram * user fdetaches, the pts node is still owned by the previous
49e92448e558772c002444c0d92e7a31d529d046vikram * owner. To prevent this we don't allow fattach() on top of a pts
49e92448e558772c002444c0d92e7a31d529d046vikram * node. This is done by a modification in the namefs filesystem
49e92448e558772c002444c0d92e7a31d529d046vikram * where we check if the underlying node has the /dev/pts vnodeops.
49e92448e558772c002444c0d92e7a31d529d046vikram * We do this via VOP_REALVP() on the underlying specfs node.
49e92448e558772c002444c0d92e7a31d529d046vikram * sdev_nodes currently don't have a realvp. If a realvp is ever
49e92448e558772c002444c0d92e7a31d529d046vikram * created for sdev_nodes, then VOP_REALVP() will return the
49e92448e558772c002444c0d92e7a31d529d046vikram * actual realvp (possibly a ufs vnode). This will defeat the check
49e92448e558772c002444c0d92e7a31d529d046vikram * in namefs code which checks if VOP_REALVP() returns a devpts
49e92448e558772c002444c0d92e7a31d529d046vikram * node. We add an ASSERT here in /dev/pts lookup() to check for
49e92448e558772c002444c0d92e7a31d529d046vikram * this condition. If sdev_nodes ever get a VOP_REALVP() entry point,
49e92448e558772c002444c0d92e7a31d529d046vikram * change the code in the namefs filesystem code (in nm_mount()) to
49e92448e558772c002444c0d92e7a31d529d046vikram * access the realvp of the specfs node directly instead of using
49e92448e558772c002444c0d92e7a31d529d046vikram * VOP_REALVP().
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai */
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai/*ARGSUSED3*/
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllaistatic int
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllaidevpts_lookup(struct vnode *dvp, char *nm, struct vnode **vpp,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw struct pathname *pnp, int flags, struct vnode *rdir, struct cred *cred,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw caller_context_t *ct, int *direntflags, pathname_t *realpnp)
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai{
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai struct sdev_node *sdvp = VTOSDEV(dvp);
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai struct sdev_node *dv;
49e92448e558772c002444c0d92e7a31d529d046vikram struct vnode *rvp = NULL;
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai int error;
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai error = devname_lookup_func(sdvp, nm, vpp, cred, devpts_create_rvp,
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai SDEV_VATTR);
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai if (error == 0) {
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai switch ((*vpp)->v_type) {
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai case VCHR:
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai dv = VTOSDEV(VTOS(*vpp)->s_realvp);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw ASSERT(VOP_REALVP(SDEVTOV(dv), &rvp, NULL) == ENOSYS);
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai break;
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai case VDIR:
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai dv = VTOSDEV(*vpp);
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai break;
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai default:
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai cmn_err(CE_PANIC, "devpts_lookup: Unsupported node "
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai "type: %p: %d", (void *)(*vpp), (*vpp)->v_type);
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai break;
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai }
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai ASSERT(SDEV_HELD(dv));
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai }
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai return (error);
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai}
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai/*
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * We allow create to find existing nodes
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * - if the node doesn't exist - EROFS
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * - creating an existing dir read-only succeeds, otherwise EISDIR
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * - exclusive creates fail - EEXIST
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai */
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai/*ARGSUSED2*/
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllaistatic int
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllaidevpts_create(struct vnode *dvp, char *nm, struct vattr *vap, vcexcl_t excl,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw int mode, struct vnode **vpp, struct cred *cred, int flag,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw caller_context_t *ct, vsecattr_t *vsecp)
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai{
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai int error;
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai struct vnode *vp;
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai *vpp = NULL;
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw error = devpts_lookup(dvp, nm, &vp, NULL, 0, NULL, cred, ct, NULL,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw NULL);
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai if (error == 0) {
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai if (excl == EXCL)
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai error = EEXIST;
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai else if (vp->v_type == VDIR && (mode & VWRITE))
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai error = EISDIR;
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai else
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw error = VOP_ACCESS(vp, mode, 0, cred, ct);
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai if (error) {
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai VN_RELE(vp);
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai } else
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai *vpp = vp;
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai } else if (error == ENOENT) {
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai error = EROFS;
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai }
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai return (error);
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai}
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai/*
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * Display all instantiated pts (slave) device nodes.
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * A /dev/pts entry will be created only after the first lookup of the slave
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * device succeeds.
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw/*ARGSUSED4*/
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllaistatic int
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllaidevpts_readdir(struct vnode *dvp, struct uio *uiop, struct cred *cred,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw int *eofp, caller_context_t *ct, int flags)
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai{
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai struct sdev_node *sdvp = VTOSDEV(dvp);
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai if (uiop->uio_offset == 0) {
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai devpts_prunedir(sdvp);
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai }
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai return (devname_readdir_func(dvp, uiop, cred, eofp, 0));
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai}
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllaistatic int
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllaidevpts_set_id(struct sdev_node *dv, struct vattr *vap, int protocol)
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai{
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai ASSERT((protocol & AT_UID) || (protocol & AT_GID));
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai ptms_set_owner(getminor(SDEVTOV(dv)->v_rdev),
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai vap->va_uid, vap->va_gid);
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai return (0);
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai}
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai
cbcfaf83d8f1bf6aa00c793903a55685cac2c548jg/*ARGSUSED4*/
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllaistatic int
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllaidevpts_setattr(struct vnode *vp, struct vattr *vap, int flags,
cbcfaf83d8f1bf6aa00c793903a55685cac2c548jg struct cred *cred, caller_context_t *ctp)
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai{
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai ASSERT((vp->v_type == VCHR) || (vp->v_type == VDIR));
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai return (devname_setattr_func(vp, vap, flags, cred,
aac43a5f8f51bcc570ff0ae9fad0380daf839ad9jg devpts_set_id, AT_UID|AT_GID));
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai}
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai
49e92448e558772c002444c0d92e7a31d529d046vikram
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai/*
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * We override lookup and readdir to build entries based on the
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * in kernel pty table. Also override setattr/setsecattr to
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * avoid persisting permissions.
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai */
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllaiconst fs_operation_def_t devpts_vnodeops_tbl[] = {
aa59c4cb15a6ac5d4e585dadf7a055b580abf579rsb VOPNAME_READDIR, { .vop_readdir = devpts_readdir },
aa59c4cb15a6ac5d4e585dadf7a055b580abf579rsb VOPNAME_LOOKUP, { .vop_lookup = devpts_lookup },
aa59c4cb15a6ac5d4e585dadf7a055b580abf579rsb VOPNAME_CREATE, { .vop_create = devpts_create },
aa59c4cb15a6ac5d4e585dadf7a055b580abf579rsb VOPNAME_SETATTR, { .vop_setattr = devpts_setattr },
aa59c4cb15a6ac5d4e585dadf7a055b580abf579rsb VOPNAME_REMOVE, { .error = fs_nosys },
aa59c4cb15a6ac5d4e585dadf7a055b580abf579rsb VOPNAME_MKDIR, { .error = fs_nosys },
aa59c4cb15a6ac5d4e585dadf7a055b580abf579rsb VOPNAME_RMDIR, { .error = fs_nosys },
aa59c4cb15a6ac5d4e585dadf7a055b580abf579rsb VOPNAME_SYMLINK, { .error = fs_nosys },
aa59c4cb15a6ac5d4e585dadf7a055b580abf579rsb VOPNAME_SETSECATTR, { .error = fs_nosys },
aa59c4cb15a6ac5d4e585dadf7a055b580abf579rsb NULL, NULL
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai};