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