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