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) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
  23  */
  24 
  25 #include <sys/conf.h>
  26 #include <sys/stat.h>
  27 #include <sys/file.h>
  28 #include <sys/types.h>
  29 #include <sys/pathname.h>
  30 #include <sys/proc.h>
  31 #include <sys/mode.h>
  32 #include <sys/vnode.h>
  33 #include <sys/ddi.h>
  34 #include <sys/sunddi.h>
  35 #include <sys/sunldi.h>
  36 #include <sys/uio.h>
  37 #include <sys/attr.h>
  38 #include <sys/acl.h>
  39 #include <sys/fs/zut.h>
  40 
  41 ldi_ident_t zut_li = NULL;
  42 dev_info_t *zut_dip;
  43 
  44 static int
  45 zut_open_dir(char *path, vnode_t *startvp, cred_t *cr, int flags,
  46     pathname_t *realpn, vnode_t **dvn)
  47 {
  48         pathname_t pn;
  49         vnode_t *vp;
  50         vnode_t *rootvp;
  51         proc_t *p = curproc;
  52         int error;
  53 
  54         pn_alloc(&pn);
  55         (void) strlcpy(pn.pn_buf, path, MAXPATHLEN);
  56         pn.pn_pathlen = strlen(path);
  57 
  58         mutex_enter(&p->p_lock); /* for u_rdir and u_cdir */
  59         if ((rootvp = PTOU(p)->u_rdir) == NULL)
  60                 rootvp = rootdir;
  61         else if (rootvp != rootdir)     /* no need to VN_HOLD rootdir */
  62                 VN_HOLD(rootvp);
  63 
  64         if (pn.pn_path[0] == '/') {
  65                 vp = rootvp;
  66         } else {
  67                 vp = (startvp == NULL) ? PTOU(p)->u_cdir : startvp;
  68         }
  69         VN_HOLD(vp);
  70         mutex_exit(&p->p_lock);
  71 
  72         /*
  73          * Skip over leading slashes
  74          */
  75         while (pn.pn_path[0] == '/') {
  76                 pn.pn_path++;
  77                 pn.pn_pathlen--;
  78         }
  79 
  80         error = lookuppnvp(&pn, realpn, flags | FOLLOW, NULL,
  81             dvn, rootvp, vp, cr);
  82 
  83         /*
  84          * If we lack read access to the directory, we should error out.
  85          */
  86         if (!error) {
  87                 if (vfs_has_feature((*dvn)->v_vfsp, VFSFT_ACEMASKONACCESS)) {
  88                         error = VOP_ACCESS(*dvn, ACE_LIST_DIRECTORY,
  89                             V_ACE_MASK, cr, NULL);
  90                 } else {
  91                         error = VOP_ACCESS(*dvn, VREAD, 0, cr, NULL);
  92                 }
  93         }
  94 
  95         pn_free(&pn);
  96 
  97         return (error);
  98 }
  99 
 100 static int
 101 zut_readdir(intptr_t arg, cred_t *cr, int iflag, int *rvalp)
 102 {
 103         zut_readdir_t *zr;
 104         struct iovec aiov;
 105         struct uio auio;
 106         vnode_t *dvn = NULL;
 107         vnode_t *fvn = NULL;
 108         char *kbuf;
 109         int flags = 0;
 110         int error, rc;
 111 
 112         zr = kmem_zalloc(sizeof (zut_readdir_t), KM_SLEEP);
 113         error = ddi_copyin((void *)arg, zr, sizeof (zut_readdir_t), iflag);
 114         if (error)
 115                 goto zutr_bail;
 116 
 117         kbuf = kmem_zalloc(zr->zr_buflen, KM_SLEEP);
 118 
 119         zr->zr_retcode = zut_open_dir(zr->zr_dir, NULL, cr, flags, NULL, &dvn);
 120         if (zr->zr_retcode)
 121                 goto zutr_done;
 122 
 123         if (zr->zr_reqflags & ZUT_XATTR) {
 124                 vattr_t vattr;
 125 
 126                 zr->zr_retcode = VOP_LOOKUP(dvn, zr->zr_file, &fvn,
 127                     NULL, flags, NULL, cr, NULL, NULL, NULL);
 128                 VN_RELE(dvn);
 129                 dvn = NULL;
 130                 if (zr->zr_retcode)
 131                         goto zutr_done;
 132 
 133                 /*
 134                  * In order to access hidden attribute directory the
 135                  * user must have appropriate read access and be able
 136                  * to stat() the file
 137                  */
 138                 if (vfs_has_feature(fvn->v_vfsp, VFSFT_ACEMASKONACCESS)) {
 139                         zr->zr_retcode = VOP_ACCESS(fvn, ACE_READ_NAMED_ATTRS,
 140                             V_ACE_MASK, cr, NULL);
 141                 } else {
 142                         zr->zr_retcode = VOP_ACCESS(fvn, VREAD, 0, cr, NULL);
 143                 }
 144                 if (zr->zr_retcode)
 145                         goto zutr_done;
 146 
 147                 vattr.va_mask = AT_ALL;
 148                 zr->zr_retcode = VOP_GETATTR(fvn, &vattr, 0, cr, NULL);
 149                 if (zr->zr_retcode)
 150                         goto zutr_done;
 151 
 152                 zr->zr_retcode = VOP_LOOKUP(fvn, "", &dvn, NULL,
 153                     flags | LOOKUP_XATTR, NULL, cr, NULL, NULL, NULL);
 154                 VN_RELE(fvn);
 155                 if (zr->zr_retcode)
 156                         goto zutr_done;
 157         }
 158 
 159         aiov.iov_base = kbuf;
 160         aiov.iov_len = zr->zr_buflen;
 161         auio.uio_iov = &aiov;
 162         auio.uio_iovcnt = 1;
 163         auio.uio_loffset = zr->zr_loffset;
 164         auio.uio_segflg = UIO_SYSSPACE;
 165         auio.uio_resid = zr->zr_buflen;
 166         auio.uio_fmode = 0;
 167         auio.uio_extflg = UIO_COPY_CACHED;
 168 
 169         if (zr->zr_reqflags & ZUT_EXTRDDIR)
 170                 flags |= V_RDDIR_ENTFLAGS;
 171         if (zr->zr_reqflags & ZUT_ACCFILTER)
 172                 flags |= V_RDDIR_ACCFILTER;
 173 
 174         (void) VOP_RWLOCK(dvn, V_WRITELOCK_FALSE, NULL);
 175         zr->zr_retcode = VOP_READDIR(dvn, &auio, cr, &zr->zr_eof,
 176             NULL, flags);
 177         VOP_RWUNLOCK(dvn, V_WRITELOCK_FALSE, NULL);
 178         VN_RELE(dvn);
 179 
 180         zr->zr_bytes = aiov.iov_base - kbuf;
 181         zr->zr_loffset = auio.uio_loffset;
 182 
 183         error = ddi_copyout(kbuf, (void *)(uintptr_t)zr->zr_buf,
 184             zr->zr_buflen, iflag);
 185 
 186 zutr_done:
 187         kmem_free(kbuf, zr->zr_buflen);
 188         rc = ddi_copyout(zr, (void *)arg, sizeof (zut_readdir_t), iflag);
 189         if (error == 0)
 190                 error = rc;
 191 
 192 zutr_bail:
 193         kmem_free(zr, sizeof (zut_readdir_t));
 194         if (rvalp)
 195                 *rvalp = error;
 196         return (error);
 197 }
 198 
 199 static int
 200 zut_stat64(vnode_t *vp, struct stat64 *sb, uint64_t *xvs, int flag, cred_t *cr)
 201 {
 202         xoptattr_t *xoap = NULL;
 203         xvattr_t xv = {{ 0 }};
 204         int error;
 205 
 206         xva_init(&xv);
 207 
 208         XVA_SET_REQ(&xv, XAT_ARCHIVE);
 209         XVA_SET_REQ(&xv, XAT_SYSTEM);
 210         XVA_SET_REQ(&xv, XAT_READONLY);
 211         XVA_SET_REQ(&xv, XAT_HIDDEN);
 212         XVA_SET_REQ(&xv, XAT_NOUNLINK);
 213         XVA_SET_REQ(&xv, XAT_IMMUTABLE);
 214         XVA_SET_REQ(&xv, XAT_APPENDONLY);
 215         XVA_SET_REQ(&xv, XAT_NODUMP);
 216         XVA_SET_REQ(&xv, XAT_OPAQUE);
 217         XVA_SET_REQ(&xv, XAT_AV_QUARANTINED);
 218         XVA_SET_REQ(&xv, XAT_AV_MODIFIED);
 219         XVA_SET_REQ(&xv, XAT_REPARSE);
 220         XVA_SET_REQ(&xv, XAT_OFFLINE);
 221         XVA_SET_REQ(&xv, XAT_SPARSE);
 222 
 223         xv.xva_vattr.va_mask |= AT_STAT | AT_NBLOCKS | AT_BLKSIZE | AT_SIZE;
 224         if (error = VOP_GETATTR(vp, &xv.xva_vattr, flag, cr, NULL))
 225                 return (error);
 226 
 227         bzero(sb, sizeof (sb));
 228         sb->st_dev = xv.xva_vattr.va_fsid;
 229         sb->st_ino = xv.xva_vattr.va_nodeid;
 230         sb->st_mode = VTTOIF(xv.xva_vattr.va_type) | xv.xva_vattr.va_mode;
 231         sb->st_nlink = xv.xva_vattr.va_nlink;
 232         sb->st_uid = xv.xva_vattr.va_uid;
 233         sb->st_gid = xv.xva_vattr.va_gid;
 234         sb->st_rdev = xv.xva_vattr.va_rdev;
 235         sb->st_size = xv.xva_vattr.va_size;
 236         sb->st_atim = xv.xva_vattr.va_atime;
 237         sb->st_mtim = xv.xva_vattr.va_mtime;
 238         sb->st_ctim = xv.xva_vattr.va_ctime;
 239         sb->st_blksize = xv.xva_vattr.va_blksize;
 240         sb->st_blocks = xv.xva_vattr.va_nblocks;
 241         sb->st_fstype[0] = 0;
 242 
 243         if ((xoap = xva_getxoptattr(&xv)) == NULL)
 244                 return (0);
 245 
 246         if (XVA_ISSET_RTN(&xv, XAT_ARCHIVE) && xoap->xoa_archive)
 247                 *xvs |= (1 << F_ARCHIVE);
 248         if (XVA_ISSET_RTN(&xv, XAT_SYSTEM) && xoap->xoa_system)
 249                 *xvs |= (1 << F_SYSTEM);
 250         if (XVA_ISSET_RTN(&xv, XAT_READONLY) && xoap->xoa_readonly)
 251                 *xvs |= (1 << F_READONLY);
 252         if (XVA_ISSET_RTN(&xv, XAT_HIDDEN) && xoap->xoa_hidden)
 253                 *xvs |= (1 << F_HIDDEN);
 254         if (XVA_ISSET_RTN(&xv, XAT_NOUNLINK) && xoap->xoa_nounlink)
 255                 *xvs |= (1 << F_NOUNLINK);
 256         if (XVA_ISSET_RTN(&xv, XAT_IMMUTABLE) && xoap->xoa_immutable)
 257                 *xvs |= (1 << F_IMMUTABLE);
 258         if (XVA_ISSET_RTN(&xv, XAT_APPENDONLY) && xoap->xoa_appendonly)
 259                 *xvs |= (1 << F_APPENDONLY);
 260         if (XVA_ISSET_RTN(&xv, XAT_NODUMP) && xoap->xoa_nodump)
 261                 *xvs |= (1 << F_NODUMP);
 262         if (XVA_ISSET_RTN(&xv, XAT_OPAQUE) && xoap->xoa_opaque)
 263                 *xvs |= (1 << F_OPAQUE);
 264         if (XVA_ISSET_RTN(&xv, XAT_AV_QUARANTINED) && xoap->xoa_av_quarantined)
 265                 *xvs |= (1 << F_AV_QUARANTINED);
 266         if (XVA_ISSET_RTN(&xv, XAT_AV_MODIFIED) && xoap->xoa_av_modified)
 267                 *xvs |= (1 << F_AV_MODIFIED);
 268         if (XVA_ISSET_RTN(&xv, XAT_REPARSE) && xoap->xoa_reparse)
 269                 *xvs |= (1 << F_REPARSE);
 270         if (XVA_ISSET_RTN(&xv, XAT_OFFLINE) && xoap->xoa_offline)
 271                 *xvs |= (1 << F_OFFLINE);
 272         if (XVA_ISSET_RTN(&xv, XAT_SPARSE) && xoap->xoa_sparse)
 273                 *xvs |= (1 << F_SPARSE);
 274 
 275         return (0);
 276 }
 277 
 278 /*ARGSUSED*/
 279 static int
 280 zut_lookup(intptr_t arg, cred_t *cr, int iflag, int *rvalp)
 281 {
 282         zut_lookup_t *zl;
 283         pathname_t rpn;
 284         vnode_t *dvn = NULL;
 285         vnode_t *fvn = NULL;
 286         vnode_t *xdvn = NULL;
 287         vnode_t *xfvn = NULL;
 288         vnode_t *release = NULL;
 289         int flags = 0;
 290         int error, rc;
 291 
 292         zl = kmem_zalloc(sizeof (zut_lookup_t), KM_SLEEP);
 293 
 294         error = ddi_copyin((void *)arg, zl, sizeof (zut_lookup_t), iflag);
 295         if (error)
 296                 goto zutl_bail;
 297 
 298         pn_alloc(&rpn);
 299         bzero(rpn.pn_buf, MAXPATHLEN);
 300 
 301         zl->zl_retcode = zut_open_dir(zl->zl_dir, NULL, cr, flags, &rpn, &dvn);
 302         if (zl->zl_retcode)
 303                 goto zutl_done;
 304 
 305         if (zl->zl_reqflags & ZUT_IGNORECASE)
 306                 flags |= FIGNORECASE;
 307 
 308         zl->zl_retcode = VOP_LOOKUP(dvn, zl->zl_file, &fvn, NULL, flags, NULL,
 309             cr, NULL, &zl->zl_deflags, &rpn);
 310         if (zl->zl_retcode)
 311                 goto zutl_done;
 312 
 313         release = fvn;
 314 
 315         if (zl->zl_reqflags & ZUT_XATTR) {
 316                 vattr_t vattr;
 317 
 318                 /*
 319                  * In order to access hidden attribute directory the
 320                  * user must have appropriate read access and be able
 321                  * to stat() the file
 322                  */
 323                 if (vfs_has_feature(fvn->v_vfsp, VFSFT_ACEMASKONACCESS)) {
 324                         zl->zl_retcode = VOP_ACCESS(fvn, ACE_READ_NAMED_ATTRS,
 325                             V_ACE_MASK, cr, NULL);
 326                 } else {
 327                         zl->zl_retcode = VOP_ACCESS(fvn, VREAD, 0, cr, NULL);
 328                 }
 329                 if (zl->zl_retcode)
 330                         goto zutl_done;
 331 
 332                 vattr.va_mask = AT_ALL;
 333                 zl->zl_retcode = VOP_GETATTR(fvn, &vattr, 0, cr, NULL);
 334                 if (zl->zl_retcode)
 335                         goto zutl_done;
 336 
 337                 zl->zl_retcode = VOP_LOOKUP(fvn, "", &xdvn, NULL,
 338                     flags | LOOKUP_XATTR, NULL, cr, NULL, NULL, NULL);
 339                 if (zl->zl_retcode)
 340                         goto zutl_done;
 341                 VN_RELE(fvn);
 342                 release = xdvn;
 343 
 344                 zl->zl_retcode = VOP_LOOKUP(xdvn, zl->zl_xfile, &xfvn,
 345                     NULL, flags, NULL, cr, NULL, &zl->zl_deflags, &rpn);
 346                 if (zl->zl_retcode)
 347                         goto zutl_done;
 348                 VN_RELE(xdvn);
 349                 release = xfvn;
 350         }
 351 
 352         if (zl->zl_reqflags & ZUT_GETSTAT) {
 353                 zl->zl_retcode = zut_stat64(release,
 354                     &zl->zl_statbuf, &zl->zl_xvattrs, 0, cr);
 355         }
 356 
 357 zutl_done:
 358         (void) strlcpy(zl->zl_real, rpn.pn_path, MAXPATHLEN);
 359 
 360         rc = ddi_copyout(zl, (void *)arg, sizeof (zut_lookup_t), iflag);
 361         if (error == 0)
 362                 error = rc;
 363 
 364         if (release)
 365                 VN_RELE(release);
 366         if (dvn)
 367                 VN_RELE(dvn);
 368         pn_free(&rpn);
 369 
 370 zutl_bail:
 371         kmem_free(zl, sizeof (zut_lookup_t));
 372         if (rvalp)
 373                 *rvalp = error;
 374         return (error);
 375 }
 376 
 377 /*ARGSUSED*/
 378 static int
 379 zut_ioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *cr, int *rvalp)
 380 {
 381         int error;
 382 
 383         if (getminor(dev) != 0)
 384                 return (ENXIO);
 385 
 386         if (cmd <= ZUT_IOC_MIN_CMD || cmd >= ZUT_IOC_MAX_CMD)
 387                 return (EINVAL);
 388 
 389         switch (cmd) {
 390         case ZUT_IOC_LOOKUP:
 391                 error = zut_lookup(arg, cr, flag, rvalp);
 392                 break;
 393         case ZUT_IOC_READDIR:
 394                 error = zut_readdir(arg, cr, flag, rvalp);
 395         default:
 396                 break;
 397         }
 398 
 399         return (error);
 400 }
 401 
 402 static int
 403 zut_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
 404 {
 405         if (cmd != DDI_ATTACH)
 406                 return (DDI_FAILURE);
 407 
 408         if (ddi_create_minor_node(dip, "zut", S_IFCHR, 0,
 409             DDI_PSEUDO, 0) == DDI_FAILURE)
 410                 return (DDI_FAILURE);
 411 
 412         zut_dip = dip;
 413 
 414         ddi_report_dev(dip);
 415 
 416         return (DDI_SUCCESS);
 417 }
 418 
 419 static int
 420 zut_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
 421 {
 422         if (cmd != DDI_DETACH)
 423                 return (DDI_FAILURE);
 424 
 425         zut_dip = NULL;
 426 
 427         ddi_prop_remove_all(dip);
 428         ddi_remove_minor_node(dip, NULL);
 429 
 430         return (DDI_SUCCESS);
 431 }
 432 
 433 /*ARGSUSED*/
 434 static int
 435 zut_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
 436 {
 437         switch (infocmd) {
 438         case DDI_INFO_DEVT2DEVINFO:
 439                 *result = zut_dip;
 440                 return (DDI_SUCCESS);
 441 
 442         case DDI_INFO_DEVT2INSTANCE:
 443                 *result = (void *)0;
 444                 return (DDI_SUCCESS);
 445         }
 446 
 447         return (DDI_FAILURE);
 448 }
 449 
 450 /*ARGSUSED*/
 451 int
 452 zut_open(dev_t *devp, int flag, int otyp, cred_t *cr)
 453 {
 454         minor_t minor = getminor(*devp);
 455 
 456         if (minor == 0)                 /* This is the control device */
 457                 return (0);
 458 
 459         return (ENXIO);
 460 }
 461 
 462 /*ARGSUSED*/
 463 int
 464 zut_close(dev_t dev, int flag, int otyp, cred_t *cr)
 465 {
 466         minor_t minor = getminor(dev);
 467 
 468         if (minor == 0)         /* This is the control device */
 469                 return (0);
 470 
 471         return (ENXIO);
 472 }
 473 
 474 /*
 475  * /dev/zut is the control node, i.e. minor 0.
 476  *
 477  * There are no other minor nodes, and /dev/zut basically does nothing
 478  * other than serve up ioctls.
 479  */
 480 static struct cb_ops zut_cb_ops = {
 481         zut_open,       /* open */
 482         zut_close,      /* close */
 483         nodev,          /* strategy */
 484         nodev,          /* print */
 485         nodev,          /* dump */
 486         nodev,          /* read */
 487         nodev,          /* write */
 488         zut_ioctl,      /* ioctl */
 489         nodev,          /* devmap */
 490         nodev,          /* mmap */
 491         nodev,          /* segmap */
 492         nochpoll,       /* poll */
 493         ddi_prop_op,    /* prop_op */
 494         NULL,           /* streamtab */
 495         D_NEW | D_MP | D_64BIT,         /* Driver compatibility flag */
 496         CB_REV,         /* version */
 497         nodev,          /* async read */
 498         nodev,          /* async write */
 499 };
 500 
 501 static struct dev_ops zut_dev_ops = {
 502         DEVO_REV,       /* version */
 503         0,              /* refcnt */
 504         zut_info,       /* info */
 505         nulldev,        /* identify */
 506         nulldev,        /* probe */
 507         zut_attach,     /* attach */
 508         zut_detach,     /* detach */
 509         nodev,          /* reset */
 510         &zut_cb_ops,        /* driver operations */
 511         NULL            /* no bus operations */
 512 };
 513 
 514 static struct modldrv zut_modldrv = {
 515         &mod_driverops, "ZFS unit test " ZUT_VERSION_STRING,
 516             &zut_dev_ops
 517 };
 518 
 519 static struct modlinkage modlinkage = {
 520         MODREV_1,
 521         {   (void *)&zut_modldrv,
 522             NULL }
 523 };
 524 
 525 int
 526 _init(void)
 527 {
 528         int error;
 529 
 530         if ((error = mod_install(&modlinkage)) != 0) {
 531                 return (error);
 532         }
 533 
 534         error = ldi_ident_from_mod(&modlinkage, &zut_li);
 535         ASSERT(error == 0);
 536 
 537         return (0);
 538 }
 539 
 540 int
 541 _fini(void)
 542 {
 543         int error;
 544 
 545         if ((error = mod_remove(&modlinkage)) != 0)
 546                 return (error);
 547 
 548         ldi_ident_release(zut_li);
 549         zut_li = NULL;
 550 
 551         return (error);
 552 }
 553 
 554 int
 555 _info(struct modinfo *modinfop)
 556 {
 557         return (mod_info(&modlinkage, modinfop));
 558 }