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 2008 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 
  26 #include <sys/types.h>
  27 #include <sys/param.h>
  28 #include <sys/time.h>
  29 #include <sys/cred.h>
  30 #include <sys/vfs.h>
  31 #include <sys/vfs_opreg.h>
  32 #include <sys/gfs.h>
  33 #include <sys/vnode.h>
  34 #include <sys/systm.h>
  35 #include <sys/errno.h>
  36 #include <sys/sysmacros.h>
  37 #include <fs/fs_subr.h>
  38 #include <sys/contract.h>
  39 #include <sys/contract_impl.h>
  40 #include <sys/ctfs.h>
  41 #include <sys/ctfs_impl.h>
  42 #include <sys/file.h>
  43 #include <sys/model.h>
  44 
  45 /*
  46  * CTFS routines for the /system/contract/<type>/template vnode.
  47  */
  48 
  49 /*
  50  * ctfs_create_tmplnode
  51  *
  52  * Creates a new template and tdirnode, and returns the tdirnode.
  53  */
  54 vnode_t *
  55 ctfs_create_tmplnode(vnode_t *pvp)
  56 {
  57         vnode_t *vp;
  58         ctfs_tmplnode_t *tmplnode;
  59 
  60         ASSERT(gfs_file_index(pvp) < ct_ntypes);
  61 
  62         vp = gfs_file_create(sizeof (ctfs_tmplnode_t), pvp, ctfs_ops_tmpl);
  63         tmplnode = vp->v_data;
  64         tmplnode->ctfs_tmn_tmpl =
  65             ct_types[gfs_file_index(pvp)]->ct_type_default();
  66 
  67         return (vp);
  68 }
  69 
  70 /*
  71  * ctfs_tmpl_open - VOP_OPEN entry point
  72  *
  73  * Just ensures the right mode bits are set.
  74  */
  75 /* ARGSUSED */
  76 static int
  77 ctfs_tmpl_open(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ct)
  78 {
  79         if (flag != (FREAD | FWRITE | FOFFMAX))
  80                 return (EINVAL);
  81 
  82         return (0);
  83 }
  84 
  85 /*
  86  * ctfs_tmpl_getattr - VOP_GETATTR entry point
  87  */
  88 /* ARGSUSED */
  89 static int
  90 ctfs_tmpl_getattr(
  91         vnode_t *vp,
  92         vattr_t *vap,
  93         int flags,
  94         cred_t *cr,
  95         caller_context_t *ct)
  96 {
  97         vap->va_type = VREG;
  98         vap->va_mode = 0666;
  99         vap->va_nlink = 1;
 100         vap->va_size = 0;
 101         vap->va_ctime.tv_sec = vp->v_vfsp->vfs_mtime;
 102         vap->va_ctime.tv_nsec = 0;
 103         vap->va_atime = vap->va_mtime = vap->va_ctime;
 104         ctfs_common_getattr(vp, vap);
 105 
 106         return (0);
 107 }
 108 
 109 /*
 110  * ctfs_tmpl_ioctl - VOP_IOCTL entry point
 111  *
 112  * All the ct_tmpl_*(3contract) interfaces point here.
 113  */
 114 /* ARGSUSED */
 115 static int
 116 ctfs_tmpl_ioctl(
 117         vnode_t *vp,
 118         int cmd,
 119         intptr_t arg,
 120         int flag,
 121         cred_t *cr,
 122         int *rvalp,
 123         caller_context_t *ct)
 124 {
 125         ctfs_tmplnode_t *tmplnode = vp->v_data;
 126         ct_kparam_t kparam;
 127         ct_param_t *param = &kparam.param;
 128         ctid_t ctid;
 129         int error;
 130 
 131         switch (cmd) {
 132         case CT_TACTIVATE:
 133                 ASSERT(tmplnode->ctfs_tmn_tmpl != NULL);
 134                 ctmpl_activate(tmplnode->ctfs_tmn_tmpl);
 135                 break;
 136         case CT_TCLEAR:
 137                 ASSERT(tmplnode->ctfs_tmn_tmpl != NULL);
 138                 ctmpl_clear(tmplnode->ctfs_tmn_tmpl);
 139                 break;
 140         case CT_TCREATE:
 141                 ASSERT(tmplnode->ctfs_tmn_tmpl != NULL);
 142                 error = ctmpl_create(tmplnode->ctfs_tmn_tmpl, &ctid);
 143                 if (error)
 144                         return (error);
 145                 *rvalp = ctid;
 146                 break;
 147         case CT_TSET:
 148                 error = ctparam_copyin((void *)arg, &kparam, flag, cmd);
 149                 if (error != 0)
 150                         return (error);
 151                 error = ctmpl_set(tmplnode->ctfs_tmn_tmpl, &kparam, cr);
 152                 kmem_free(kparam.ctpm_kbuf, param->ctpm_size);
 153 
 154                 return (error);
 155         case CT_TGET:
 156                 error = ctparam_copyin((void *)arg, &kparam, flag, cmd);
 157                 if (error != 0)
 158                         return (error);
 159                 error = ctmpl_get(tmplnode->ctfs_tmn_tmpl, &kparam);
 160                 if (error != 0) {
 161                         kmem_free(kparam.ctpm_kbuf, param->ctpm_size);
 162                 } else {
 163                         error = ctparam_copyout(&kparam, (void *)arg, flag);
 164                 }
 165 
 166                 return (error);
 167         default:
 168                 return (EINVAL);
 169         }
 170 
 171         return (0);
 172 }
 173 
 174 /*
 175  * ctfs_tmpl_inactive - VOP_INACTIVE entry point
 176  */
 177 /* ARGSUSED */
 178 static void
 179 ctfs_tmpl_inactive(vnode_t *vp, cred_t *cr, caller_context_t *ct)
 180 {
 181         ctfs_tmplnode_t *tmplnode;
 182 
 183         if ((tmplnode = gfs_file_inactive(vp)) != NULL) {
 184                 ctmpl_free(tmplnode->ctfs_tmn_tmpl);
 185                 kmem_free(tmplnode, sizeof (ctfs_tmplnode_t));
 186         }
 187 }
 188 
 189 const fs_operation_def_t ctfs_tops_tmpl[] = {
 190         { VOPNAME_OPEN,         { .vop_open = ctfs_tmpl_open } },
 191         { VOPNAME_CLOSE,        { .vop_close = ctfs_close } },
 192         { VOPNAME_IOCTL,        { .vop_ioctl = ctfs_tmpl_ioctl } },
 193         { VOPNAME_GETATTR,      { .vop_getattr = ctfs_tmpl_getattr } },
 194         { VOPNAME_ACCESS,       { .vop_access = ctfs_access_readwrite } },
 195         { VOPNAME_READDIR,      { .error = fs_notdir } },
 196         { VOPNAME_LOOKUP,       { .error = fs_notdir } },
 197         { VOPNAME_INACTIVE,     { .vop_inactive = ctfs_tmpl_inactive } },
 198         { NULL,                 { NULL } }
 199 };