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