1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate /* 30*0Sstevel@tonic-gate * Syscall to write out the instance number data structures to 31*0Sstevel@tonic-gate * stable storage. 32*0Sstevel@tonic-gate */ 33*0Sstevel@tonic-gate 34*0Sstevel@tonic-gate #include <sys/types.h> 35*0Sstevel@tonic-gate #include <sys/errno.h> 36*0Sstevel@tonic-gate #include <sys/t_lock.h> 37*0Sstevel@tonic-gate #include <sys/modctl.h> 38*0Sstevel@tonic-gate #include <sys/systm.h> 39*0Sstevel@tonic-gate #include <sys/syscall.h> 40*0Sstevel@tonic-gate #include <sys/vfs.h> 41*0Sstevel@tonic-gate #include <sys/vnode.h> 42*0Sstevel@tonic-gate #include <sys/cred.h> 43*0Sstevel@tonic-gate #include <sys/file.h> 44*0Sstevel@tonic-gate #include <sys/cmn_err.h> 45*0Sstevel@tonic-gate #include <sys/kmem.h> 46*0Sstevel@tonic-gate #include <sys/cladm.h> 47*0Sstevel@tonic-gate #include <sys/sunddi.h> 48*0Sstevel@tonic-gate #include <sys/dditypes.h> 49*0Sstevel@tonic-gate #include <sys/instance.h> 50*0Sstevel@tonic-gate #include <sys/debug.h> 51*0Sstevel@tonic-gate #include <sys/policy.h> 52*0Sstevel@tonic-gate 53*0Sstevel@tonic-gate /* 54*0Sstevel@tonic-gate * Userland sees: 55*0Sstevel@tonic-gate * 56*0Sstevel@tonic-gate * int inst_sync(pathname, flags); 57*0Sstevel@tonic-gate * 58*0Sstevel@tonic-gate * Returns zero if instance number information was successfully 59*0Sstevel@tonic-gate * written to 'pathname', -1 plus error code in errno otherwise. 60*0Sstevel@tonic-gate * 61*0Sstevel@tonic-gate * POC notes: 62*0Sstevel@tonic-gate * 63*0Sstevel@tonic-gate * - This could be done as a case of the modctl(2) system call 64*0Sstevel@tonic-gate * though the ability to have it load and unload would disappear. 65*0Sstevel@tonic-gate * 66*0Sstevel@tonic-gate * - Currently, flags are not interpreted. 67*0Sstevel@tonic-gate * 68*0Sstevel@tonic-gate * - Maybe we should pass through two filenames - one to create, 69*0Sstevel@tonic-gate * and the other as the 'final' target i.e. do the rename of 70*0Sstevel@tonic-gate * /etc/instance.new -> /etc/instance in the kernel. 71*0Sstevel@tonic-gate */ 72*0Sstevel@tonic-gate 73*0Sstevel@tonic-gate static int in_sync_sys(char *pathname, uint_t flags); 74*0Sstevel@tonic-gate 75*0Sstevel@tonic-gate static struct sysent in_sync_sysent = { 76*0Sstevel@tonic-gate 2, /* number of arguments */ 77*0Sstevel@tonic-gate SE_ARGC | SE_32RVAL1, /* c-style calling, 32-bit return value */ 78*0Sstevel@tonic-gate in_sync_sys, /* the handler */ 79*0Sstevel@tonic-gate (krwlock_t *)0 /* rw lock allocated/used by framework */ 80*0Sstevel@tonic-gate }; 81*0Sstevel@tonic-gate 82*0Sstevel@tonic-gate static struct modlsys modlsys = { 83*0Sstevel@tonic-gate &mod_syscallops, "instance binding syscall", &in_sync_sysent 84*0Sstevel@tonic-gate }; 85*0Sstevel@tonic-gate 86*0Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 87*0Sstevel@tonic-gate static struct modlsys modlsys32 = { 88*0Sstevel@tonic-gate &mod_syscallops32, "32-bit instance binding syscall", &in_sync_sysent 89*0Sstevel@tonic-gate }; 90*0Sstevel@tonic-gate #endif 91*0Sstevel@tonic-gate 92*0Sstevel@tonic-gate static struct modlinkage modlinkage = { 93*0Sstevel@tonic-gate MODREV_1, 94*0Sstevel@tonic-gate &modlsys, 95*0Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 96*0Sstevel@tonic-gate &modlsys32, 97*0Sstevel@tonic-gate #endif 98*0Sstevel@tonic-gate NULL 99*0Sstevel@tonic-gate }; 100*0Sstevel@tonic-gate 101*0Sstevel@tonic-gate int 102*0Sstevel@tonic-gate _init(void) 103*0Sstevel@tonic-gate { 104*0Sstevel@tonic-gate return (mod_install(&modlinkage)); 105*0Sstevel@tonic-gate } 106*0Sstevel@tonic-gate 107*0Sstevel@tonic-gate int 108*0Sstevel@tonic-gate _info(struct modinfo *modinfop) 109*0Sstevel@tonic-gate { 110*0Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 111*0Sstevel@tonic-gate } 112*0Sstevel@tonic-gate 113*0Sstevel@tonic-gate int 114*0Sstevel@tonic-gate _fini(void) 115*0Sstevel@tonic-gate { 116*0Sstevel@tonic-gate return (mod_remove(&modlinkage)); 117*0Sstevel@tonic-gate } 118*0Sstevel@tonic-gate 119*0Sstevel@tonic-gate static int in_write_instance(struct vnode *vp); 120*0Sstevel@tonic-gate 121*0Sstevel@tonic-gate /*ARGSUSED1*/ 122*0Sstevel@tonic-gate static int 123*0Sstevel@tonic-gate in_sync_sys(char *pathname, uint_t flags) 124*0Sstevel@tonic-gate { 125*0Sstevel@tonic-gate struct vnode *vp; 126*0Sstevel@tonic-gate int error; 127*0Sstevel@tonic-gate 128*0Sstevel@tonic-gate /* 129*0Sstevel@tonic-gate * We must have sufficient privilege to do this, since we lock critical 130*0Sstevel@tonic-gate * data structures whilst we're doing it .. 131*0Sstevel@tonic-gate */ 132*0Sstevel@tonic-gate if ((error = secpolicy_sys_devices(CRED())) != 0) 133*0Sstevel@tonic-gate return (set_errno(error)); 134*0Sstevel@tonic-gate 135*0Sstevel@tonic-gate /* 136*0Sstevel@tonic-gate * Only one process is allowed to get the state of the instance 137*0Sstevel@tonic-gate * number assignments on the system at any given time. 138*0Sstevel@tonic-gate */ 139*0Sstevel@tonic-gate e_ddi_enter_instance(); 140*0Sstevel@tonic-gate 141*0Sstevel@tonic-gate if (e_ddi_instance_is_clean()) { 142*0Sstevel@tonic-gate error = EALREADY; 143*0Sstevel@tonic-gate goto end; 144*0Sstevel@tonic-gate } 145*0Sstevel@tonic-gate 146*0Sstevel@tonic-gate /* 147*0Sstevel@tonic-gate * Create an instance file for writing, giving it a mode that 148*0Sstevel@tonic-gate * will only permit reading. Note that we refuse to overwrite 149*0Sstevel@tonic-gate * an existing file. 150*0Sstevel@tonic-gate */ 151*0Sstevel@tonic-gate if ((error = vn_open(pathname, UIO_USERSPACE, 152*0Sstevel@tonic-gate FCREAT, 0444, &vp, CRCREAT, 0)) != 0) { 153*0Sstevel@tonic-gate if (error == EISDIR) 154*0Sstevel@tonic-gate error = EACCES; /* SVID compliance? */ 155*0Sstevel@tonic-gate goto end; 156*0Sstevel@tonic-gate } 157*0Sstevel@tonic-gate 158*0Sstevel@tonic-gate /* 159*0Sstevel@tonic-gate * So far so good. We're singly threaded, the vnode is beckoning 160*0Sstevel@tonic-gate * so let's get on with it. Any error, and we just give up and 161*0Sstevel@tonic-gate * hand the first error we get back to userland. 162*0Sstevel@tonic-gate */ 163*0Sstevel@tonic-gate error = in_write_instance(vp); 164*0Sstevel@tonic-gate 165*0Sstevel@tonic-gate /* 166*0Sstevel@tonic-gate * If there was any sort of error, we deliberately go and 167*0Sstevel@tonic-gate * remove the file we just created so that any attempts to 168*0Sstevel@tonic-gate * use it will quickly fail. 169*0Sstevel@tonic-gate */ 170*0Sstevel@tonic-gate if (error) 171*0Sstevel@tonic-gate (void) vn_remove(pathname, UIO_USERSPACE, RMFILE); 172*0Sstevel@tonic-gate else 173*0Sstevel@tonic-gate e_ddi_instance_set_clean(); 174*0Sstevel@tonic-gate end: 175*0Sstevel@tonic-gate e_ddi_exit_instance(); 176*0Sstevel@tonic-gate return (error ? set_errno(error) : 0); 177*0Sstevel@tonic-gate } 178*0Sstevel@tonic-gate 179*0Sstevel@tonic-gate /* 180*0Sstevel@tonic-gate * At the risk of reinventing stdio .. 181*0Sstevel@tonic-gate */ 182*0Sstevel@tonic-gate #define FBUFSIZE 512 183*0Sstevel@tonic-gate 184*0Sstevel@tonic-gate typedef struct _File { 185*0Sstevel@tonic-gate char *ptr; 186*0Sstevel@tonic-gate int count; 187*0Sstevel@tonic-gate char buf[FBUFSIZE]; 188*0Sstevel@tonic-gate vnode_t *vp; 189*0Sstevel@tonic-gate offset_t voffset; 190*0Sstevel@tonic-gate } File; 191*0Sstevel@tonic-gate 192*0Sstevel@tonic-gate static int 193*0Sstevel@tonic-gate in_write(struct vnode *vp, offset_t *vo, caddr_t buf, int count) 194*0Sstevel@tonic-gate { 195*0Sstevel@tonic-gate int error; 196*0Sstevel@tonic-gate ssize_t resid; 197*0Sstevel@tonic-gate rlim64_t rlimit = *vo + count + 1; 198*0Sstevel@tonic-gate 199*0Sstevel@tonic-gate error = vn_rdwr(UIO_WRITE, vp, buf, count, *vo, 200*0Sstevel@tonic-gate UIO_SYSSPACE, 0, rlimit, CRED(), &resid); 201*0Sstevel@tonic-gate 202*0Sstevel@tonic-gate *vo += (offset_t)(count - resid); 203*0Sstevel@tonic-gate 204*0Sstevel@tonic-gate return (error); 205*0Sstevel@tonic-gate } 206*0Sstevel@tonic-gate 207*0Sstevel@tonic-gate static File * 208*0Sstevel@tonic-gate in_fvpopen(struct vnode *vp) 209*0Sstevel@tonic-gate { 210*0Sstevel@tonic-gate File *fp; 211*0Sstevel@tonic-gate 212*0Sstevel@tonic-gate fp = kmem_zalloc(sizeof (File), KM_SLEEP); 213*0Sstevel@tonic-gate fp->vp = vp; 214*0Sstevel@tonic-gate fp->ptr = fp->buf; 215*0Sstevel@tonic-gate 216*0Sstevel@tonic-gate return (fp); 217*0Sstevel@tonic-gate } 218*0Sstevel@tonic-gate 219*0Sstevel@tonic-gate static int 220*0Sstevel@tonic-gate in_fclose(File *fp) 221*0Sstevel@tonic-gate { 222*0Sstevel@tonic-gate int error; 223*0Sstevel@tonic-gate 224*0Sstevel@tonic-gate error = VOP_CLOSE(fp->vp, FCREAT, 1, (offset_t)0, CRED()); 225*0Sstevel@tonic-gate VN_RELE(fp->vp); 226*0Sstevel@tonic-gate kmem_free(fp, sizeof (File)); 227*0Sstevel@tonic-gate return (error); 228*0Sstevel@tonic-gate } 229*0Sstevel@tonic-gate 230*0Sstevel@tonic-gate static int 231*0Sstevel@tonic-gate in_fflush(File *fp) 232*0Sstevel@tonic-gate { 233*0Sstevel@tonic-gate int error = 0; 234*0Sstevel@tonic-gate 235*0Sstevel@tonic-gate if (fp->count) 236*0Sstevel@tonic-gate error = in_write(fp->vp, &fp->voffset, fp->buf, fp->count); 237*0Sstevel@tonic-gate if (error == 0) 238*0Sstevel@tonic-gate error = VOP_FSYNC(fp->vp, FSYNC, CRED()); 239*0Sstevel@tonic-gate return (error); 240*0Sstevel@tonic-gate } 241*0Sstevel@tonic-gate 242*0Sstevel@tonic-gate static int 243*0Sstevel@tonic-gate in_fputs(File *fp, char *buf) 244*0Sstevel@tonic-gate { 245*0Sstevel@tonic-gate int error = 0; 246*0Sstevel@tonic-gate 247*0Sstevel@tonic-gate while (*buf) { 248*0Sstevel@tonic-gate *fp->ptr++ = *buf++; 249*0Sstevel@tonic-gate if (++fp->count == FBUFSIZE) { 250*0Sstevel@tonic-gate error = in_write(fp->vp, &fp->voffset, fp->buf, 251*0Sstevel@tonic-gate fp->count); 252*0Sstevel@tonic-gate if (error) 253*0Sstevel@tonic-gate break; 254*0Sstevel@tonic-gate fp->count = 0; 255*0Sstevel@tonic-gate fp->ptr = fp->buf; 256*0Sstevel@tonic-gate } 257*0Sstevel@tonic-gate } 258*0Sstevel@tonic-gate 259*0Sstevel@tonic-gate return (error); 260*0Sstevel@tonic-gate } 261*0Sstevel@tonic-gate 262*0Sstevel@tonic-gate /* 263*0Sstevel@tonic-gate * External linkage 264*0Sstevel@tonic-gate */ 265*0Sstevel@tonic-gate static File *in_fp; 266*0Sstevel@tonic-gate 267*0Sstevel@tonic-gate /* 268*0Sstevel@tonic-gate * XXX what is the maximum length of the name of a driver? Must be maximum 269*0Sstevel@tonic-gate * XXX file name length (find the correct constant and substitute for this one 270*0Sstevel@tonic-gate */ 271*0Sstevel@tonic-gate #define DRVNAMELEN (1 + 256) 272*0Sstevel@tonic-gate static char linebuffer[MAXPATHLEN + 1 + 1 + 1 + 1 + 10 + 1 + DRVNAMELEN]; 273*0Sstevel@tonic-gate 274*0Sstevel@tonic-gate /* 275*0Sstevel@tonic-gate * XXX Maybe we should just write 'in_fprintf' instead .. 276*0Sstevel@tonic-gate */ 277*0Sstevel@tonic-gate static int 278*0Sstevel@tonic-gate in_walktree(in_node_t *np, char *this) 279*0Sstevel@tonic-gate { 280*0Sstevel@tonic-gate char *next; 281*0Sstevel@tonic-gate int error = 0; 282*0Sstevel@tonic-gate in_drv_t *dp; 283*0Sstevel@tonic-gate 284*0Sstevel@tonic-gate for (error = 0; np; np = np->in_sibling) { 285*0Sstevel@tonic-gate 286*0Sstevel@tonic-gate if (np->in_unit_addr[0] == '\0') 287*0Sstevel@tonic-gate (void) sprintf(this, "/%s", np->in_node_name); 288*0Sstevel@tonic-gate else 289*0Sstevel@tonic-gate (void) sprintf(this, "/%s@%s", np->in_node_name, 290*0Sstevel@tonic-gate np->in_unit_addr); 291*0Sstevel@tonic-gate next = this + strlen(this); 292*0Sstevel@tonic-gate 293*0Sstevel@tonic-gate ASSERT(np->in_drivers); 294*0Sstevel@tonic-gate 295*0Sstevel@tonic-gate for (dp = np->in_drivers; dp; dp = dp->ind_next_drv) { 296*0Sstevel@tonic-gate uint_t inst_val = dp->ind_instance; 297*0Sstevel@tonic-gate 298*0Sstevel@tonic-gate /* 299*0Sstevel@tonic-gate * Flushing IN_PROVISIONAL could result in duplicate 300*0Sstevel@tonic-gate * instances 301*0Sstevel@tonic-gate * Flushing IN_UNKNOWN results in instance -1 302*0Sstevel@tonic-gate */ 303*0Sstevel@tonic-gate if (dp->ind_state != IN_PERMANENT) 304*0Sstevel@tonic-gate continue; 305*0Sstevel@tonic-gate 306*0Sstevel@tonic-gate (void) sprintf(next, "\" %d \"%s\"\n", inst_val, 307*0Sstevel@tonic-gate dp->ind_driver_name); 308*0Sstevel@tonic-gate if (error = in_fputs(in_fp, linebuffer)) 309*0Sstevel@tonic-gate return (error); 310*0Sstevel@tonic-gate } 311*0Sstevel@tonic-gate 312*0Sstevel@tonic-gate if (np->in_child) 313*0Sstevel@tonic-gate if (error = in_walktree(np->in_child, next)) 314*0Sstevel@tonic-gate break; 315*0Sstevel@tonic-gate } 316*0Sstevel@tonic-gate return (error); 317*0Sstevel@tonic-gate } 318*0Sstevel@tonic-gate 319*0Sstevel@tonic-gate 320*0Sstevel@tonic-gate /* 321*0Sstevel@tonic-gate * Walk the instance tree, writing out what we find. 322*0Sstevel@tonic-gate * 323*0Sstevel@tonic-gate * There's some fairly nasty sharing of buffers in this 324*0Sstevel@tonic-gate * bit of code, so be careful out there when you're 325*0Sstevel@tonic-gate * rewriting it .. 326*0Sstevel@tonic-gate */ 327*0Sstevel@tonic-gate static int 328*0Sstevel@tonic-gate in_write_instance(struct vnode *vp) 329*0Sstevel@tonic-gate { 330*0Sstevel@tonic-gate int error; 331*0Sstevel@tonic-gate char *cp; 332*0Sstevel@tonic-gate 333*0Sstevel@tonic-gate in_fp = in_fvpopen(vp); 334*0Sstevel@tonic-gate 335*0Sstevel@tonic-gate /* 336*0Sstevel@tonic-gate * Place a bossy comment at the beginning of the file. 337*0Sstevel@tonic-gate */ 338*0Sstevel@tonic-gate error = in_fputs(in_fp, 339*0Sstevel@tonic-gate "#\n#\tCaution! This file contains critical kernel state\n#\n"); 340*0Sstevel@tonic-gate 341*0Sstevel@tonic-gate if (error == 0) { 342*0Sstevel@tonic-gate in_node_t *root = e_ddi_instance_root(); 343*0Sstevel@tonic-gate cp = linebuffer; 344*0Sstevel@tonic-gate *cp++ = '\"'; 345*0Sstevel@tonic-gate error = in_walktree(root->in_child, cp); 346*0Sstevel@tonic-gate } 347*0Sstevel@tonic-gate 348*0Sstevel@tonic-gate if (error == 0) { 349*0Sstevel@tonic-gate if ((error = in_fflush(in_fp)) == 0) 350*0Sstevel@tonic-gate error = in_fclose(in_fp); 351*0Sstevel@tonic-gate } else 352*0Sstevel@tonic-gate (void) in_fclose(in_fp); 353*0Sstevel@tonic-gate 354*0Sstevel@tonic-gate return (error); 355*0Sstevel@tonic-gate } 356