17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5da6c28aaSamw * Common Development and Distribution License (the "License"). 6da6c28aaSamw * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22*94c894bbSVikram Hegde * Copyright (c) 1992, 2010, Oracle and/or its affiliates. All rights reserved. 237c478bd9Sstevel@tonic-gate */ 247c478bd9Sstevel@tonic-gate 257c478bd9Sstevel@tonic-gate /* 267c478bd9Sstevel@tonic-gate * Syscall to write out the instance number data structures to 277c478bd9Sstevel@tonic-gate * stable storage. 287c478bd9Sstevel@tonic-gate */ 297c478bd9Sstevel@tonic-gate 307c478bd9Sstevel@tonic-gate #include <sys/types.h> 317c478bd9Sstevel@tonic-gate #include <sys/errno.h> 327c478bd9Sstevel@tonic-gate #include <sys/t_lock.h> 337c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 347c478bd9Sstevel@tonic-gate #include <sys/systm.h> 357c478bd9Sstevel@tonic-gate #include <sys/syscall.h> 367c478bd9Sstevel@tonic-gate #include <sys/vfs.h> 377c478bd9Sstevel@tonic-gate #include <sys/vnode.h> 387c478bd9Sstevel@tonic-gate #include <sys/cred.h> 397c478bd9Sstevel@tonic-gate #include <sys/file.h> 407c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 417c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 427c478bd9Sstevel@tonic-gate #include <sys/cladm.h> 437c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 447c478bd9Sstevel@tonic-gate #include <sys/dditypes.h> 457c478bd9Sstevel@tonic-gate #include <sys/instance.h> 467c478bd9Sstevel@tonic-gate #include <sys/debug.h> 477c478bd9Sstevel@tonic-gate #include <sys/policy.h> 487c478bd9Sstevel@tonic-gate 497c478bd9Sstevel@tonic-gate /* 507c478bd9Sstevel@tonic-gate * Userland sees: 517c478bd9Sstevel@tonic-gate * 527c478bd9Sstevel@tonic-gate * int inst_sync(pathname, flags); 537c478bd9Sstevel@tonic-gate * 547c478bd9Sstevel@tonic-gate * Returns zero if instance number information was successfully 557c478bd9Sstevel@tonic-gate * written to 'pathname', -1 plus error code in errno otherwise. 567c478bd9Sstevel@tonic-gate * 577c478bd9Sstevel@tonic-gate * POC notes: 587c478bd9Sstevel@tonic-gate * 597c478bd9Sstevel@tonic-gate * - This could be done as a case of the modctl(2) system call 607c478bd9Sstevel@tonic-gate * though the ability to have it load and unload would disappear. 617c478bd9Sstevel@tonic-gate * 620a653502Swroche * - 'flags' have either of two meanings: 630a653502Swroche * INST_SYNC_IF_REQUIRED 'pathname' will be written if there 640a653502Swroche * has been a change in the kernel's 650a653502Swroche * internal view of instance number 660a653502Swroche * information 670a653502Swroche * INST_SYNC_ALWAYS 'pathname' will be written even if 680a653502Swroche * the kernel's view hasn't changed. 697c478bd9Sstevel@tonic-gate * 707c478bd9Sstevel@tonic-gate * - Maybe we should pass through two filenames - one to create, 717c478bd9Sstevel@tonic-gate * and the other as the 'final' target i.e. do the rename of 727c478bd9Sstevel@tonic-gate * /etc/instance.new -> /etc/instance in the kernel. 737c478bd9Sstevel@tonic-gate */ 747c478bd9Sstevel@tonic-gate 757c478bd9Sstevel@tonic-gate static int in_sync_sys(char *pathname, uint_t flags); 767c478bd9Sstevel@tonic-gate 777c478bd9Sstevel@tonic-gate static struct sysent in_sync_sysent = { 787c478bd9Sstevel@tonic-gate 2, /* number of arguments */ 797c478bd9Sstevel@tonic-gate SE_ARGC | SE_32RVAL1, /* c-style calling, 32-bit return value */ 807c478bd9Sstevel@tonic-gate in_sync_sys, /* the handler */ 817c478bd9Sstevel@tonic-gate (krwlock_t *)0 /* rw lock allocated/used by framework */ 827c478bd9Sstevel@tonic-gate }; 837c478bd9Sstevel@tonic-gate 847c478bd9Sstevel@tonic-gate static struct modlsys modlsys = { 857c478bd9Sstevel@tonic-gate &mod_syscallops, "instance binding syscall", &in_sync_sysent 867c478bd9Sstevel@tonic-gate }; 877c478bd9Sstevel@tonic-gate 887c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 897c478bd9Sstevel@tonic-gate static struct modlsys modlsys32 = { 907c478bd9Sstevel@tonic-gate &mod_syscallops32, "32-bit instance binding syscall", &in_sync_sysent 917c478bd9Sstevel@tonic-gate }; 927c478bd9Sstevel@tonic-gate #endif 937c478bd9Sstevel@tonic-gate 947c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = { 957c478bd9Sstevel@tonic-gate MODREV_1, 967c478bd9Sstevel@tonic-gate &modlsys, 977c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 987c478bd9Sstevel@tonic-gate &modlsys32, 997c478bd9Sstevel@tonic-gate #endif 1007c478bd9Sstevel@tonic-gate NULL 1017c478bd9Sstevel@tonic-gate }; 1027c478bd9Sstevel@tonic-gate 1037c478bd9Sstevel@tonic-gate int 1047c478bd9Sstevel@tonic-gate _init(void) 1057c478bd9Sstevel@tonic-gate { 1067c478bd9Sstevel@tonic-gate return (mod_install(&modlinkage)); 1077c478bd9Sstevel@tonic-gate } 1087c478bd9Sstevel@tonic-gate 1097c478bd9Sstevel@tonic-gate int 1107c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop) 1117c478bd9Sstevel@tonic-gate { 1127c478bd9Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 1137c478bd9Sstevel@tonic-gate } 1147c478bd9Sstevel@tonic-gate 1157c478bd9Sstevel@tonic-gate int 1167c478bd9Sstevel@tonic-gate _fini(void) 1177c478bd9Sstevel@tonic-gate { 1187c478bd9Sstevel@tonic-gate return (mod_remove(&modlinkage)); 1197c478bd9Sstevel@tonic-gate } 1207c478bd9Sstevel@tonic-gate 1217c478bd9Sstevel@tonic-gate static int in_write_instance(struct vnode *vp); 1227c478bd9Sstevel@tonic-gate 123*94c894bbSVikram Hegde static int inst_sync_disable = 0; 124*94c894bbSVikram Hegde 1257c478bd9Sstevel@tonic-gate static int 1267c478bd9Sstevel@tonic-gate in_sync_sys(char *pathname, uint_t flags) 1277c478bd9Sstevel@tonic-gate { 1287c478bd9Sstevel@tonic-gate struct vnode *vp; 1297c478bd9Sstevel@tonic-gate int error; 1307c478bd9Sstevel@tonic-gate 131*94c894bbSVikram Hegde /* For debugging/testing */ 132*94c894bbSVikram Hegde if (inst_sync_disable) 133*94c894bbSVikram Hegde return (0); 134*94c894bbSVikram Hegde 1357c478bd9Sstevel@tonic-gate /* 1367c478bd9Sstevel@tonic-gate * We must have sufficient privilege to do this, since we lock critical 1377c478bd9Sstevel@tonic-gate * data structures whilst we're doing it .. 1387c478bd9Sstevel@tonic-gate */ 1397c478bd9Sstevel@tonic-gate if ((error = secpolicy_sys_devices(CRED())) != 0) 1407c478bd9Sstevel@tonic-gate return (set_errno(error)); 1417c478bd9Sstevel@tonic-gate 1420a653502Swroche if (flags != INST_SYNC_ALWAYS && flags != INST_SYNC_IF_REQUIRED) 1430a653502Swroche return (set_errno(EINVAL)); 1440a653502Swroche 1457c478bd9Sstevel@tonic-gate /* 1467c478bd9Sstevel@tonic-gate * Only one process is allowed to get the state of the instance 1477c478bd9Sstevel@tonic-gate * number assignments on the system at any given time. 1487c478bd9Sstevel@tonic-gate */ 1497c478bd9Sstevel@tonic-gate e_ddi_enter_instance(); 1507c478bd9Sstevel@tonic-gate 1510a653502Swroche /* 1520a653502Swroche * Recreate the instance file only if the device tree has changed 1530a653502Swroche * or if the caller explicitly requests so. 1540a653502Swroche */ 1550a653502Swroche if (e_ddi_instance_is_clean() && flags != INST_SYNC_ALWAYS) { 1567c478bd9Sstevel@tonic-gate error = EALREADY; 1577c478bd9Sstevel@tonic-gate goto end; 1587c478bd9Sstevel@tonic-gate } 1597c478bd9Sstevel@tonic-gate 1607c478bd9Sstevel@tonic-gate /* 1617c478bd9Sstevel@tonic-gate * Create an instance file for writing, giving it a mode that 1627c478bd9Sstevel@tonic-gate * will only permit reading. Note that we refuse to overwrite 1637c478bd9Sstevel@tonic-gate * an existing file. 1647c478bd9Sstevel@tonic-gate */ 1657c478bd9Sstevel@tonic-gate if ((error = vn_open(pathname, UIO_USERSPACE, 1667c478bd9Sstevel@tonic-gate FCREAT, 0444, &vp, CRCREAT, 0)) != 0) { 1677c478bd9Sstevel@tonic-gate if (error == EISDIR) 1687c478bd9Sstevel@tonic-gate error = EACCES; /* SVID compliance? */ 1697c478bd9Sstevel@tonic-gate goto end; 1707c478bd9Sstevel@tonic-gate } 1717c478bd9Sstevel@tonic-gate 1727c478bd9Sstevel@tonic-gate /* 1737c478bd9Sstevel@tonic-gate * So far so good. We're singly threaded, the vnode is beckoning 1747c478bd9Sstevel@tonic-gate * so let's get on with it. Any error, and we just give up and 1757c478bd9Sstevel@tonic-gate * hand the first error we get back to userland. 1767c478bd9Sstevel@tonic-gate */ 1777c478bd9Sstevel@tonic-gate error = in_write_instance(vp); 1787c478bd9Sstevel@tonic-gate 1797c478bd9Sstevel@tonic-gate /* 1807c478bd9Sstevel@tonic-gate * If there was any sort of error, we deliberately go and 1817c478bd9Sstevel@tonic-gate * remove the file we just created so that any attempts to 1827c478bd9Sstevel@tonic-gate * use it will quickly fail. 1837c478bd9Sstevel@tonic-gate */ 1847c478bd9Sstevel@tonic-gate if (error) 1857c478bd9Sstevel@tonic-gate (void) vn_remove(pathname, UIO_USERSPACE, RMFILE); 1867c478bd9Sstevel@tonic-gate else 1877c478bd9Sstevel@tonic-gate e_ddi_instance_set_clean(); 1887c478bd9Sstevel@tonic-gate end: 1897c478bd9Sstevel@tonic-gate e_ddi_exit_instance(); 1907c478bd9Sstevel@tonic-gate return (error ? set_errno(error) : 0); 1917c478bd9Sstevel@tonic-gate } 1927c478bd9Sstevel@tonic-gate 1937c478bd9Sstevel@tonic-gate /* 1947c478bd9Sstevel@tonic-gate * At the risk of reinventing stdio .. 1957c478bd9Sstevel@tonic-gate */ 1967c478bd9Sstevel@tonic-gate #define FBUFSIZE 512 1977c478bd9Sstevel@tonic-gate 1987c478bd9Sstevel@tonic-gate typedef struct _File { 1997c478bd9Sstevel@tonic-gate char *ptr; 2007c478bd9Sstevel@tonic-gate int count; 2017c478bd9Sstevel@tonic-gate char buf[FBUFSIZE]; 2027c478bd9Sstevel@tonic-gate vnode_t *vp; 2037c478bd9Sstevel@tonic-gate offset_t voffset; 2047c478bd9Sstevel@tonic-gate } File; 2057c478bd9Sstevel@tonic-gate 2067c478bd9Sstevel@tonic-gate static int 2077c478bd9Sstevel@tonic-gate in_write(struct vnode *vp, offset_t *vo, caddr_t buf, int count) 2087c478bd9Sstevel@tonic-gate { 2097c478bd9Sstevel@tonic-gate int error; 2107c478bd9Sstevel@tonic-gate ssize_t resid; 2117c478bd9Sstevel@tonic-gate rlim64_t rlimit = *vo + count + 1; 2127c478bd9Sstevel@tonic-gate 2137c478bd9Sstevel@tonic-gate error = vn_rdwr(UIO_WRITE, vp, buf, count, *vo, 2147c478bd9Sstevel@tonic-gate UIO_SYSSPACE, 0, rlimit, CRED(), &resid); 2157c478bd9Sstevel@tonic-gate 2167c478bd9Sstevel@tonic-gate *vo += (offset_t)(count - resid); 2177c478bd9Sstevel@tonic-gate 2187c478bd9Sstevel@tonic-gate return (error); 2197c478bd9Sstevel@tonic-gate } 2207c478bd9Sstevel@tonic-gate 2217c478bd9Sstevel@tonic-gate static File * 2227c478bd9Sstevel@tonic-gate in_fvpopen(struct vnode *vp) 2237c478bd9Sstevel@tonic-gate { 2247c478bd9Sstevel@tonic-gate File *fp; 2257c478bd9Sstevel@tonic-gate 2267c478bd9Sstevel@tonic-gate fp = kmem_zalloc(sizeof (File), KM_SLEEP); 2277c478bd9Sstevel@tonic-gate fp->vp = vp; 2287c478bd9Sstevel@tonic-gate fp->ptr = fp->buf; 2297c478bd9Sstevel@tonic-gate 2307c478bd9Sstevel@tonic-gate return (fp); 2317c478bd9Sstevel@tonic-gate } 2327c478bd9Sstevel@tonic-gate 2337c478bd9Sstevel@tonic-gate static int 2347c478bd9Sstevel@tonic-gate in_fclose(File *fp) 2357c478bd9Sstevel@tonic-gate { 2367c478bd9Sstevel@tonic-gate int error; 2377c478bd9Sstevel@tonic-gate 238da6c28aaSamw error = VOP_CLOSE(fp->vp, FCREAT, 1, (offset_t)0, CRED(), NULL); 2397c478bd9Sstevel@tonic-gate VN_RELE(fp->vp); 2407c478bd9Sstevel@tonic-gate kmem_free(fp, sizeof (File)); 2417c478bd9Sstevel@tonic-gate return (error); 2427c478bd9Sstevel@tonic-gate } 2437c478bd9Sstevel@tonic-gate 2447c478bd9Sstevel@tonic-gate static int 2457c478bd9Sstevel@tonic-gate in_fflush(File *fp) 2467c478bd9Sstevel@tonic-gate { 2477c478bd9Sstevel@tonic-gate int error = 0; 2487c478bd9Sstevel@tonic-gate 2497c478bd9Sstevel@tonic-gate if (fp->count) 2507c478bd9Sstevel@tonic-gate error = in_write(fp->vp, &fp->voffset, fp->buf, fp->count); 2517c478bd9Sstevel@tonic-gate if (error == 0) 252da6c28aaSamw error = VOP_FSYNC(fp->vp, FSYNC, CRED(), NULL); 2537c478bd9Sstevel@tonic-gate return (error); 2547c478bd9Sstevel@tonic-gate } 2557c478bd9Sstevel@tonic-gate 2567c478bd9Sstevel@tonic-gate static int 2577c478bd9Sstevel@tonic-gate in_fputs(File *fp, char *buf) 2587c478bd9Sstevel@tonic-gate { 2597c478bd9Sstevel@tonic-gate int error = 0; 2607c478bd9Sstevel@tonic-gate 2617c478bd9Sstevel@tonic-gate while (*buf) { 2627c478bd9Sstevel@tonic-gate *fp->ptr++ = *buf++; 2637c478bd9Sstevel@tonic-gate if (++fp->count == FBUFSIZE) { 2647c478bd9Sstevel@tonic-gate error = in_write(fp->vp, &fp->voffset, fp->buf, 2657c478bd9Sstevel@tonic-gate fp->count); 2667c478bd9Sstevel@tonic-gate if (error) 2677c478bd9Sstevel@tonic-gate break; 2687c478bd9Sstevel@tonic-gate fp->count = 0; 2697c478bd9Sstevel@tonic-gate fp->ptr = fp->buf; 2707c478bd9Sstevel@tonic-gate } 2717c478bd9Sstevel@tonic-gate } 2727c478bd9Sstevel@tonic-gate 2737c478bd9Sstevel@tonic-gate return (error); 2747c478bd9Sstevel@tonic-gate } 2757c478bd9Sstevel@tonic-gate 2767c478bd9Sstevel@tonic-gate /* 2777c478bd9Sstevel@tonic-gate * External linkage 2787c478bd9Sstevel@tonic-gate */ 2797c478bd9Sstevel@tonic-gate static File *in_fp; 2807c478bd9Sstevel@tonic-gate 2817c478bd9Sstevel@tonic-gate /* 2827c478bd9Sstevel@tonic-gate * XXX what is the maximum length of the name of a driver? Must be maximum 2837c478bd9Sstevel@tonic-gate * XXX file name length (find the correct constant and substitute for this one 2847c478bd9Sstevel@tonic-gate */ 2857c478bd9Sstevel@tonic-gate #define DRVNAMELEN (1 + 256) 2867c478bd9Sstevel@tonic-gate static char linebuffer[MAXPATHLEN + 1 + 1 + 1 + 1 + 10 + 1 + DRVNAMELEN]; 2877c478bd9Sstevel@tonic-gate 2887c478bd9Sstevel@tonic-gate /* 2897c478bd9Sstevel@tonic-gate * XXX Maybe we should just write 'in_fprintf' instead .. 2907c478bd9Sstevel@tonic-gate */ 2917c478bd9Sstevel@tonic-gate static int 2927c478bd9Sstevel@tonic-gate in_walktree(in_node_t *np, char *this) 2937c478bd9Sstevel@tonic-gate { 2947c478bd9Sstevel@tonic-gate char *next; 2957c478bd9Sstevel@tonic-gate int error = 0; 2967c478bd9Sstevel@tonic-gate in_drv_t *dp; 2977c478bd9Sstevel@tonic-gate 2987c478bd9Sstevel@tonic-gate for (error = 0; np; np = np->in_sibling) { 2997c478bd9Sstevel@tonic-gate 300*94c894bbSVikram Hegde if (np->in_drivers == NULL) 301*94c894bbSVikram Hegde continue; 302*94c894bbSVikram Hegde 3037c478bd9Sstevel@tonic-gate if (np->in_unit_addr[0] == '\0') 3047c478bd9Sstevel@tonic-gate (void) sprintf(this, "/%s", np->in_node_name); 3057c478bd9Sstevel@tonic-gate else 3067c478bd9Sstevel@tonic-gate (void) sprintf(this, "/%s@%s", np->in_node_name, 3077c478bd9Sstevel@tonic-gate np->in_unit_addr); 3087c478bd9Sstevel@tonic-gate next = this + strlen(this); 3097c478bd9Sstevel@tonic-gate 3107c478bd9Sstevel@tonic-gate ASSERT(np->in_drivers); 3117c478bd9Sstevel@tonic-gate 3127c478bd9Sstevel@tonic-gate for (dp = np->in_drivers; dp; dp = dp->ind_next_drv) { 3137c478bd9Sstevel@tonic-gate uint_t inst_val = dp->ind_instance; 3147c478bd9Sstevel@tonic-gate 3157c478bd9Sstevel@tonic-gate /* 3167c478bd9Sstevel@tonic-gate * Flushing IN_PROVISIONAL could result in duplicate 3177c478bd9Sstevel@tonic-gate * instances 3187c478bd9Sstevel@tonic-gate * Flushing IN_UNKNOWN results in instance -1 3197c478bd9Sstevel@tonic-gate */ 3207c478bd9Sstevel@tonic-gate if (dp->ind_state != IN_PERMANENT) 3217c478bd9Sstevel@tonic-gate continue; 3227c478bd9Sstevel@tonic-gate 3237c478bd9Sstevel@tonic-gate (void) sprintf(next, "\" %d \"%s\"\n", inst_val, 3247c478bd9Sstevel@tonic-gate dp->ind_driver_name); 3257c478bd9Sstevel@tonic-gate if (error = in_fputs(in_fp, linebuffer)) 3267c478bd9Sstevel@tonic-gate return (error); 3277c478bd9Sstevel@tonic-gate } 3287c478bd9Sstevel@tonic-gate 3297c478bd9Sstevel@tonic-gate if (np->in_child) 3307c478bd9Sstevel@tonic-gate if (error = in_walktree(np->in_child, next)) 3317c478bd9Sstevel@tonic-gate break; 3327c478bd9Sstevel@tonic-gate } 3337c478bd9Sstevel@tonic-gate return (error); 3347c478bd9Sstevel@tonic-gate } 3357c478bd9Sstevel@tonic-gate 3367c478bd9Sstevel@tonic-gate 3377c478bd9Sstevel@tonic-gate /* 3387c478bd9Sstevel@tonic-gate * Walk the instance tree, writing out what we find. 3397c478bd9Sstevel@tonic-gate * 3407c478bd9Sstevel@tonic-gate * There's some fairly nasty sharing of buffers in this 3417c478bd9Sstevel@tonic-gate * bit of code, so be careful out there when you're 3427c478bd9Sstevel@tonic-gate * rewriting it .. 3437c478bd9Sstevel@tonic-gate */ 3447c478bd9Sstevel@tonic-gate static int 3457c478bd9Sstevel@tonic-gate in_write_instance(struct vnode *vp) 3467c478bd9Sstevel@tonic-gate { 3477c478bd9Sstevel@tonic-gate int error; 3487c478bd9Sstevel@tonic-gate char *cp; 3497c478bd9Sstevel@tonic-gate 3507c478bd9Sstevel@tonic-gate in_fp = in_fvpopen(vp); 3517c478bd9Sstevel@tonic-gate 3527c478bd9Sstevel@tonic-gate /* 3537c478bd9Sstevel@tonic-gate * Place a bossy comment at the beginning of the file. 3547c478bd9Sstevel@tonic-gate */ 3557c478bd9Sstevel@tonic-gate error = in_fputs(in_fp, 3567c478bd9Sstevel@tonic-gate "#\n#\tCaution! This file contains critical kernel state\n#\n"); 3577c478bd9Sstevel@tonic-gate 3587c478bd9Sstevel@tonic-gate if (error == 0) { 3597c478bd9Sstevel@tonic-gate in_node_t *root = e_ddi_instance_root(); 3607c478bd9Sstevel@tonic-gate cp = linebuffer; 3617c478bd9Sstevel@tonic-gate *cp++ = '\"'; 3627c478bd9Sstevel@tonic-gate error = in_walktree(root->in_child, cp); 3637c478bd9Sstevel@tonic-gate } 3647c478bd9Sstevel@tonic-gate 3657c478bd9Sstevel@tonic-gate if (error == 0) { 3667c478bd9Sstevel@tonic-gate if ((error = in_fflush(in_fp)) == 0) 3677c478bd9Sstevel@tonic-gate error = in_fclose(in_fp); 3687c478bd9Sstevel@tonic-gate } else 3697c478bd9Sstevel@tonic-gate (void) in_fclose(in_fp); 3707c478bd9Sstevel@tonic-gate 3717c478bd9Sstevel@tonic-gate return (error); 3727c478bd9Sstevel@tonic-gate } 373