1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
  23  */
  24 
  25 /*
  26  * vnode ops for the /dev/vt directory
  27  */
  28 
  29 #include <sys/types.h>
  30 #include <sys/param.h>
  31 #include <sys/sysmacros.h>
  32 #include <sys/sunndi.h>
  33 #include <fs/fs_subr.h>
  34 #include <sys/fs/dv_node.h>
  35 #include <sys/fs/sdev_impl.h>
  36 #include <sys/policy.h>
  37 #include <sys/stat.h>
  38 #include <sys/vfs_opreg.h>
  39 #include <sys/tty.h>
  40 #include <sys/vt_impl.h>
  41 #include <sys/note.h>
  42 
  43 #define DEVVT_UID_DEFAULT       SDEV_UID_DEFAULT
  44 #define DEVVT_GID_DEFAULT       (0)
  45 #define DEVVT_DEVMODE_DEFAULT   (0600)
  46 #define DEVVT_ACTIVE_NAME       "active"
  47 #define DEVVT_CONSUSER_NAME     "console_user"
  48 
  49 #define isdigit(ch)     ((ch) >= '0' && (ch) <= '9')
  50 
  51 /* attributes for VT nodes */
  52 static vattr_t devvt_vattr = {
  53         AT_TYPE|AT_MODE|AT_UID|AT_GID,          /* va_mask */
  54         VCHR,                                   /* va_type */
  55         S_IFCHR | DEVVT_DEVMODE_DEFAULT,        /* va_mode */
  56         DEVVT_UID_DEFAULT,                      /* va_uid */
  57         DEVVT_GID_DEFAULT,                      /* va_gid */
  58         0                                       /* 0 hereafter */
  59 };
  60 
  61 struct vnodeops         *devvt_vnodeops;
  62 
  63 struct vnodeops *
  64 devvt_getvnodeops(void)
  65 {
  66         return (devvt_vnodeops);
  67 }
  68 
  69 static int
  70 devvt_str2minor(const char *nm, minor_t *mp)
  71 {
  72         long uminor = 0;
  73         char *endptr = NULL;
  74 
  75         if (nm == NULL || !isdigit(*nm))
  76                 return (EINVAL);
  77 
  78         *mp = 0;
  79         if (ddi_strtol(nm, &endptr, 10, &uminor) != 0 ||
  80             *endptr != '\0' || uminor < 0) {
  81                 return (EINVAL);
  82         }
  83 
  84         *mp = (minor_t)uminor;
  85         return (0);
  86 }
  87 
  88 /*
  89  * Validate that a node is up-to-date and correct.
  90  * A validator may not update the node state or
  91  * contents as a read lock permits entry by
  92  * multiple threads.
  93  */
  94 int
  95 devvt_validate(struct sdev_node *dv)
  96 {
  97         minor_t min;
  98         char *nm = dv->sdev_name;
  99         int rval;
 100 
 101         ASSERT(dv->sdev_state == SDEV_READY);
 102         ASSERT(RW_LOCK_HELD(&(dv->sdev_dotdot)->sdev_contents));
 103 
 104         /* validate only READY nodes */
 105         if (dv->sdev_state != SDEV_READY) {
 106                 sdcmn_err(("dev fs: skipping: node not ready %s(%p)",
 107                     nm, (void *)dv));
 108                 return (SDEV_VTOR_SKIP);
 109         }
 110 
 111         if (vt_wc_attached() == (major_t)-1)
 112                 return (SDEV_VTOR_INVALID);
 113 
 114         if (strcmp(nm, DEVVT_ACTIVE_NAME) == 0) {
 115                 char *link = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
 116                 (void) vt_getactive(link, MAXPATHLEN);
 117                 rval = (strcmp(link, dv->sdev_symlink) == 0) ?
 118                     SDEV_VTOR_VALID : SDEV_VTOR_STALE;
 119                 kmem_free(link, MAXPATHLEN);
 120                 return (rval);
 121         }
 122 
 123         if (strcmp(nm, DEVVT_CONSUSER_NAME) == 0) {
 124                 char *link = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
 125                 (void) vt_getconsuser(link, MAXPATHLEN);
 126                 rval = (strcmp(link, dv->sdev_symlink) == 0) ?
 127                     SDEV_VTOR_VALID : SDEV_VTOR_STALE;
 128                 kmem_free(link, MAXPATHLEN);
 129                 return (rval);
 130         }
 131 
 132         if (devvt_str2minor(nm, &min) != 0) {
 133                 return (SDEV_VTOR_INVALID);
 134         }
 135 
 136         if (vt_minor_valid(min) == B_FALSE)
 137                 return (SDEV_VTOR_INVALID);
 138 
 139         return (SDEV_VTOR_VALID);
 140 }
 141 
 142 /*
 143  * This callback is invoked from devname_lookup_func() to create
 144  * a entry when the node is not found in the cache.
 145  */
 146 /*ARGSUSED*/
 147 static int
 148 devvt_create_rvp(struct sdev_node *ddv, char *nm,
 149     void **arg, cred_t *cred, void *whatever, char *whichever)
 150 {
 151         minor_t min;
 152         major_t maj;
 153         struct vattr *vap = (struct vattr *)arg;
 154 
 155         if ((maj = vt_wc_attached()) == (major_t)-1)
 156                 return (SDEV_VTOR_INVALID);
 157 
 158         if (strcmp(nm, DEVVT_ACTIVE_NAME) == 0) {
 159                 (void) vt_getactive((char *)*arg, MAXPATHLEN);
 160                 return (0);
 161         }
 162 
 163         if (strcmp(nm, DEVVT_CONSUSER_NAME) == 0) {
 164                 (void) vt_getconsuser((char *)*arg, MAXPATHLEN);
 165                 return (0);
 166         }
 167         if (devvt_str2minor(nm, &min) != 0)
 168                 return (-1);
 169 
 170         if (vt_minor_valid(min) == B_FALSE)
 171                 return (-1);
 172 
 173         *vap = devvt_vattr;
 174         vap->va_rdev = makedevice(maj, min);
 175 
 176         return (0);
 177 }
 178 
 179 /*ARGSUSED3*/
 180 static int
 181 devvt_lookup(struct vnode *dvp, char *nm, struct vnode **vpp,
 182     struct pathname *pnp, int flags, struct vnode *rdir, struct cred *cred,
 183     caller_context_t *ct, int *direntflags, pathname_t *realpnp)
 184 {
 185         struct sdev_node *sdvp = VTOSDEV(dvp);
 186         struct sdev_node *dv;
 187         struct vnode *rvp = NULL;
 188         int type, error;
 189 
 190         if ((strcmp(nm, DEVVT_ACTIVE_NAME) == 0) ||
 191             (strcmp(nm, DEVVT_CONSUSER_NAME) == 0)) {
 192                 type = SDEV_VLINK;
 193         } else {
 194                 type = SDEV_VATTR;
 195         }
 196 
 197         error = devname_lookup_func(sdvp, nm, vpp, cred,
 198             devvt_create_rvp, type);
 199 
 200         if (error == 0) {
 201                 switch ((*vpp)->v_type) {
 202                 case VCHR:
 203                         dv = VTOSDEV(VTOS(*vpp)->s_realvp);
 204                         ASSERT(VOP_REALVP(SDEVTOV(dv), &rvp, NULL) == ENOSYS);
 205                         break;
 206                 case VDIR:
 207                 case VLNK:
 208                         dv = VTOSDEV(*vpp);
 209                         break;
 210                 default:
 211                         cmn_err(CE_PANIC, "devvt_lookup: Unsupported node "
 212                             "type: %p: %d", (void *)(*vpp), (*vpp)->v_type);
 213                         break;
 214                 }
 215                 ASSERT(SDEV_HELD(dv));
 216         }
 217 
 218         return (error);
 219 }
 220 
 221 static void
 222 devvt_create_snode(struct sdev_node *ddv, char *nm, struct cred *cred, int type)
 223 {
 224         int error;
 225         struct sdev_node *sdv = NULL;
 226         struct vattr vattr;
 227         struct vattr *vap = &vattr;
 228         major_t maj;
 229         minor_t min;
 230 
 231         ASSERT(RW_WRITE_HELD(&ddv->sdev_contents));
 232 
 233         if ((maj = vt_wc_attached()) == (major_t)-1)
 234                 return;
 235 
 236         if (strcmp(nm, DEVVT_ACTIVE_NAME) != 0 &&
 237             strcmp(nm, DEVVT_CONSUSER_NAME) != 0 &&
 238             devvt_str2minor(nm, &min) != 0)
 239                 return;
 240 
 241         error = sdev_mknode(ddv, nm, &sdv, NULL, NULL, NULL, cred, SDEV_INIT);
 242         if (error || !sdv) {
 243                 return;
 244         }
 245 
 246         mutex_enter(&sdv->sdev_lookup_lock);
 247         SDEV_BLOCK_OTHERS(sdv, SDEV_LOOKUP);
 248         mutex_exit(&sdv->sdev_lookup_lock);
 249 
 250         if (type & SDEV_VATTR) {
 251                 *vap = devvt_vattr;
 252                 vap->va_rdev = makedevice(maj, min);
 253                 error = sdev_mknode(ddv, nm, &sdv, vap, NULL,
 254                     NULL, cred, SDEV_READY);
 255         } else if (type & SDEV_VLINK) {
 256                 char *link = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
 257 
 258                 (void) vt_getactive(link, MAXPATHLEN);
 259                 *vap = sdev_vattr_lnk;
 260                 vap->va_size = strlen(link);
 261                 error = sdev_mknode(ddv, nm, &sdv, vap, NULL,
 262                     (void *)link, cred, SDEV_READY);
 263 
 264                 kmem_free(link, MAXPATHLEN);
 265         }
 266 
 267         if (error != 0) {
 268                 SDEV_RELE(sdv);
 269                 return;
 270         }
 271 
 272         mutex_enter(&sdv->sdev_lookup_lock);
 273         SDEV_UNBLOCK_OTHERS(sdv, SDEV_LOOKUP);
 274         mutex_exit(&sdv->sdev_lookup_lock);
 275 
 276 }
 277 
 278 static void
 279 devvt_rebuild_stale_link(struct sdev_node *ddv, struct sdev_node *dv)
 280 {
 281         char *link;
 282 
 283         ASSERT(RW_WRITE_HELD(&ddv->sdev_contents));
 284 
 285         ASSERT((strcmp(dv->sdev_name, DEVVT_ACTIVE_NAME) == 0) ||
 286             (strcmp(dv->sdev_name, DEVVT_CONSUSER_NAME) == 0));
 287 
 288         link = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
 289         if (strcmp(dv->sdev_name, DEVVT_ACTIVE_NAME) == 0) {
 290                 (void) vt_getactive(link, MAXPATHLEN);
 291         } else if (strcmp(dv->sdev_name, DEVVT_CONSUSER_NAME) == 0) {
 292                 (void) vt_getconsuser(link, MAXPATHLEN);
 293         }
 294 
 295         if (strcmp(link, dv->sdev_symlink) != 0) {
 296                 strfree(dv->sdev_symlink);
 297                 dv->sdev_symlink = strdup(link);
 298                 dv->sdev_attr->va_size = strlen(link);
 299         }
 300         kmem_free(link, MAXPATHLEN);
 301 }
 302 
 303 /*
 304  * First step in refreshing directory contents.
 305  * Remove each invalid entry and rebuild the link
 306  * reference for each stale entry.
 307  */
 308 static void
 309 devvt_prunedir(struct sdev_node *ddv)
 310 {
 311         struct vnode *vp;
 312         struct sdev_node *dv, *next = NULL;
 313         int (*vtor)(struct sdev_node *) = NULL;
 314 
 315         ASSERT(ddv->sdev_flags & SDEV_VTOR);
 316 
 317         vtor = (int (*)(struct sdev_node *))sdev_get_vtor(ddv);
 318         ASSERT(vtor);
 319 
 320         for (dv = SDEV_FIRST_ENTRY(ddv); dv; dv = next) {
 321                 next = SDEV_NEXT_ENTRY(ddv, dv);
 322 
 323                 switch (vtor(dv)) {
 324                 case SDEV_VTOR_VALID:
 325                         break;
 326                 case SDEV_VTOR_SKIP:
 327                         break;
 328                 case SDEV_VTOR_INVALID:
 329                         vp = SDEVTOV(dv);
 330                         if (vp->v_count != 0)
 331                                 break;
 332                         /* remove the cached node */
 333                         SDEV_HOLD(dv);
 334                         (void) sdev_cache_update(ddv, &dv,
 335                             dv->sdev_name, SDEV_CACHE_DELETE);
 336                         SDEV_RELE(dv);
 337                         break;
 338                 case SDEV_VTOR_STALE:
 339                         devvt_rebuild_stale_link(ddv, dv);
 340                         break;
 341                 }
 342         }
 343 }
 344 
 345 static void
 346 devvt_cleandir(struct vnode *dvp, struct cred *cred)
 347 {
 348         struct sdev_node *sdvp = VTOSDEV(dvp);
 349         struct sdev_node *dv, *next = NULL;
 350         int min, cnt;
 351         char found = 0;
 352 
 353         mutex_enter(&vc_lock);
 354         cnt = VC_INSTANCES_COUNT;
 355         mutex_exit(&vc_lock);
 356 
 357         if (rw_tryupgrade(&sdvp->sdev_contents) == NULL) {
 358                 rw_exit(&sdvp->sdev_contents);
 359                 rw_enter(&sdvp->sdev_contents, RW_WRITER);
 360         }
 361 
 362         /* 1.  prune invalid nodes and rebuild stale symlinks */
 363         devvt_prunedir(sdvp);
 364 
 365         /* 2. create missing nodes */
 366         for (min = 0; min < cnt; min++) {
 367                 char nm[16];
 368 
 369                 if (vt_minor_valid(min) == B_FALSE)
 370                         continue;
 371 
 372                 (void) snprintf(nm, sizeof (nm), "%d", min);
 373                 found = 0;
 374                 for (dv = SDEV_FIRST_ENTRY(sdvp); dv; dv = next) {
 375                         next = SDEV_NEXT_ENTRY(sdvp, dv);
 376 
 377                         /* validate only ready nodes */
 378                         if (dv->sdev_state != SDEV_READY)
 379                                 continue;
 380                         if (strcmp(nm, dv->sdev_name) == 0) {
 381                                 found = 1;
 382                                 break;
 383                         }
 384                 }
 385                 if (!found) {
 386                         devvt_create_snode(sdvp, nm, cred, SDEV_VATTR);
 387                 }
 388         }
 389 
 390         /* 3. create active link node and console user link node */
 391         found = 0;
 392         for (dv = SDEV_FIRST_ENTRY(sdvp); dv; dv = next) {
 393                 next = SDEV_NEXT_ENTRY(sdvp, dv);
 394 
 395                 /* validate only ready nodes */
 396                 if (dv->sdev_state != SDEV_READY)
 397                         continue;
 398                 if ((strcmp(dv->sdev_name, DEVVT_ACTIVE_NAME) == NULL))
 399                         found |= 0x01;
 400                 if ((strcmp(dv->sdev_name, DEVVT_CONSUSER_NAME) == NULL))
 401                         found |= 0x02;
 402 
 403                 if ((found & 0x01) && (found & 0x02))
 404                         break;
 405         }
 406         if (!(found & 0x01))
 407                 devvt_create_snode(sdvp, DEVVT_ACTIVE_NAME, cred, SDEV_VLINK);
 408         if (!(found & 0x02))
 409                 devvt_create_snode(sdvp, DEVVT_CONSUSER_NAME, cred, SDEV_VLINK);
 410 
 411         rw_downgrade(&sdvp->sdev_contents);
 412 }
 413 
 414 /*ARGSUSED4*/
 415 static int
 416 devvt_readdir(struct vnode *dvp, struct uio *uiop, struct cred *cred,
 417     int *eofp, caller_context_t *ct, int flags)
 418 {
 419         if (uiop->uio_offset == 0) {
 420                 devvt_cleandir(dvp, cred);
 421         }
 422 
 423         return (devname_readdir_func(dvp, uiop, cred, eofp, 0));
 424 }
 425 
 426 /*
 427  * We allow create to find existing nodes
 428  *      - if the node doesn't exist - EROFS
 429  *      - creating an existing dir read-only succeeds, otherwise EISDIR
 430  *      - exclusive creates fail - EEXIST
 431  */
 432 /*ARGSUSED2*/
 433 static int
 434 devvt_create(struct vnode *dvp, char *nm, struct vattr *vap, vcexcl_t excl,
 435     int mode, struct vnode **vpp, struct cred *cred, int flag,
 436     caller_context_t *ct, vsecattr_t *vsecp)
 437 {
 438         int error;
 439         struct vnode *vp;
 440 
 441         *vpp = NULL;
 442 
 443         if ((error = devvt_lookup(dvp, nm, &vp, NULL, 0, NULL, cred, ct, NULL,
 444             NULL)) != 0) {
 445                 if (error == ENOENT)
 446                         error = EROFS;
 447                 return (error);
 448         }
 449 
 450         if (excl == EXCL)
 451                 error = EEXIST;
 452         else if (vp->v_type == VDIR && (mode & VWRITE))
 453                 error = EISDIR;
 454         else
 455                 error = VOP_ACCESS(vp, mode, 0, cred, ct);
 456 
 457         if (error) {
 458                 VN_RELE(vp);
 459         } else
 460                 *vpp = vp;
 461 
 462         return (error);
 463 }
 464 
 465 const fs_operation_def_t devvt_vnodeops_tbl[] = {
 466         VOPNAME_READDIR,        { .vop_readdir = devvt_readdir },
 467         VOPNAME_LOOKUP,         { .vop_lookup = devvt_lookup },
 468         VOPNAME_CREATE,         { .vop_create = devvt_create },
 469         VOPNAME_REMOVE,         { .error = fs_nosys },
 470         VOPNAME_MKDIR,          { .error = fs_nosys },
 471         VOPNAME_RMDIR,          { .error = fs_nosys },
 472         VOPNAME_SYMLINK,        { .error = fs_nosys },
 473         VOPNAME_SETSECATTR,     { .error = fs_nosys },
 474         NULL,                   NULL
 475 };