10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*1672Sraf * Common Development and Distribution License (the "License"). 6*1672Sraf * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 21*1672Sraf 220Sstevel@tonic-gate /* 23*1672Sraf * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 240Sstevel@tonic-gate * Use is subject to license terms. 250Sstevel@tonic-gate */ 260Sstevel@tonic-gate 270Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 280Sstevel@tonic-gate 290Sstevel@tonic-gate /* Copyright (c) 1988 AT&T */ 300Sstevel@tonic-gate /* All Rights Reserved */ 310Sstevel@tonic-gate 320Sstevel@tonic-gate 330Sstevel@tonic-gate #include "synonyms.h" 340Sstevel@tonic-gate #include "mtlib.h" 350Sstevel@tonic-gate #include "file64.h" 360Sstevel@tonic-gate 370Sstevel@tonic-gate #define _iob __iob 380Sstevel@tonic-gate 390Sstevel@tonic-gate #include <sys/types.h> 400Sstevel@tonic-gate #include <stdlib.h> 410Sstevel@tonic-gate #include <stdio.h> 420Sstevel@tonic-gate #include <thread.h> 430Sstevel@tonic-gate #include <synch.h> 440Sstevel@tonic-gate #include <unistd.h> 450Sstevel@tonic-gate #include <string.h> 460Sstevel@tonic-gate #include "stdiom.h" 470Sstevel@tonic-gate #include <wchar.h> 480Sstevel@tonic-gate #include <sys/stat.h> 490Sstevel@tonic-gate #include <stddef.h> 500Sstevel@tonic-gate #include <errno.h> 510Sstevel@tonic-gate 520Sstevel@tonic-gate #undef end 530Sstevel@tonic-gate 540Sstevel@tonic-gate #define FILE_ARY_SZ 8 /* a nice size for FILE array & end_buffer_ptrs */ 550Sstevel@tonic-gate 560Sstevel@tonic-gate #ifdef _LP64 570Sstevel@tonic-gate 580Sstevel@tonic-gate /* 590Sstevel@tonic-gate * Macros to declare and loop over a fp or fp/xfp combo to 600Sstevel@tonic-gate * avoid some of the _LP64 ifdef hell. 610Sstevel@tonic-gate */ 620Sstevel@tonic-gate 630Sstevel@tonic-gate #define FPDECL(fp) FILE *fp 640Sstevel@tonic-gate #define FIRSTFP(lp, fp) fp = lp->iobp 650Sstevel@tonic-gate #define NEXTFP(fp) fp++ 660Sstevel@tonic-gate 670Sstevel@tonic-gate #define xFILE FILE 680Sstevel@tonic-gate 690Sstevel@tonic-gate #else 700Sstevel@tonic-gate 710Sstevel@tonic-gate #define FPDECL(fp) FILE *fp; xFILE *x##fp 720Sstevel@tonic-gate #define FIRSTFP(lp, fp) x##fp = lp->iobp; \ 730Sstevel@tonic-gate fp = x##fp ? &x##fp->_iob : &_iob[0] 740Sstevel@tonic-gate #define NEXTFP(fp) (x##fp ? fp = &(++x##fp)->_iob : ++fp) 750Sstevel@tonic-gate 760Sstevel@tonic-gate /* The extended 32-bit file structure for use in link buffers */ 770Sstevel@tonic-gate typedef struct xFILE { 780Sstevel@tonic-gate FILE _iob; /* must be first! */ 790Sstevel@tonic-gate struct xFILEdata _xdat; 800Sstevel@tonic-gate } xFILE; 810Sstevel@tonic-gate 820Sstevel@tonic-gate #define xmagic _xdat._magic 830Sstevel@tonic-gate #define xend _xdat._end 840Sstevel@tonic-gate #define xlock _xdat._lock 850Sstevel@tonic-gate #define xstate _xdat._state 860Sstevel@tonic-gate 870Sstevel@tonic-gate #define FILEx(fp) ((struct xFILE *)(uintptr_t)fp) 880Sstevel@tonic-gate 890Sstevel@tonic-gate /* 900Sstevel@tonic-gate * The magic number stored is actually the pointer scrambled with 910Sstevel@tonic-gate * a magic number. Pointers to data items live everywhere in memory 920Sstevel@tonic-gate * so we scramble the pointer in order to avoid accidental collisions. 930Sstevel@tonic-gate */ 940Sstevel@tonic-gate #define XFILEMAGIC 0x63687367 950Sstevel@tonic-gate #define XMAGIC(xfp) ((uintptr_t)(xfp) ^ XFILEMAGIC) 960Sstevel@tonic-gate 970Sstevel@tonic-gate #endif /* _LP64 */ 980Sstevel@tonic-gate 990Sstevel@tonic-gate struct _link_ /* manages a list of streams */ 1000Sstevel@tonic-gate { 1010Sstevel@tonic-gate xFILE *iobp; /* the array of (x)FILE's */ 1020Sstevel@tonic-gate /* NULL for the __first_link in ILP32 */ 1030Sstevel@tonic-gate int niob; /* length of the arrays */ 1040Sstevel@tonic-gate struct _link_ *next; /* next in the list */ 1050Sstevel@tonic-gate }; 1060Sstevel@tonic-gate 1070Sstevel@tonic-gate /* 1080Sstevel@tonic-gate * With dynamic linking, iob may be in either the library or in the user's 1090Sstevel@tonic-gate * a.out, so the run time linker fixes up the first entry in __first_link at 1100Sstevel@tonic-gate * process startup time. 1110Sstevel@tonic-gate * 1120Sstevel@tonic-gate * In 32 bit processes, we don't have xFILE[FILE_ARY_SZ] but FILE[], 1130Sstevel@tonic-gate * and _xftab[] instead; this is denoted by having iobp set to NULL in 1140Sstevel@tonic-gate * 32 bit mode for the first link entry. 1150Sstevel@tonic-gate */ 1160Sstevel@tonic-gate struct _link_ __first_link = /* first in linked list */ 1170Sstevel@tonic-gate { 1180Sstevel@tonic-gate #if !defined(_LP64) 1190Sstevel@tonic-gate NULL, 1200Sstevel@tonic-gate #else 1210Sstevel@tonic-gate &_iob[0], 1220Sstevel@tonic-gate #endif 1230Sstevel@tonic-gate _NFILE, 1240Sstevel@tonic-gate NULL 1250Sstevel@tonic-gate }; 1260Sstevel@tonic-gate 1270Sstevel@tonic-gate /* 1280Sstevel@tonic-gate * Information cached to speed up searches. We remember where we 1290Sstevel@tonic-gate * last found a free FILE* and we remember whether we saw any fcloses 1300Sstevel@tonic-gate * in between. We also count the number of chunks we allocated, see 1310Sstevel@tonic-gate * _findiop() for an explanation. 1320Sstevel@tonic-gate * These variables are all protected by _first_link_lock. 1330Sstevel@tonic-gate */ 1340Sstevel@tonic-gate static struct _link_ *lastlink = NULL; 1350Sstevel@tonic-gate static int fcloses; 1360Sstevel@tonic-gate static int nchunks; 1370Sstevel@tonic-gate 1380Sstevel@tonic-gate static rwlock_t _first_link_lock = DEFAULTRWLOCK; 1390Sstevel@tonic-gate 1400Sstevel@tonic-gate static int _fflush_u_iops(void); 1410Sstevel@tonic-gate static FILE *getiop(FILE *, rmutex_t *, mbstate_t *); 1420Sstevel@tonic-gate 1430Sstevel@tonic-gate #define GETIOP(fp, lk, mb) {FILE *ret; \ 144*1672Sraf if ((ret = getiop((fp), __libc_threaded? (lk): NULL, (mb))) != NULL) { \ 145*1672Sraf if (__libc_threaded) \ 1460Sstevel@tonic-gate (void) __rw_unlock(&_first_link_lock); \ 1470Sstevel@tonic-gate return (ret); \ 1480Sstevel@tonic-gate }; \ 1490Sstevel@tonic-gate } 1500Sstevel@tonic-gate 1510Sstevel@tonic-gate /* 1520Sstevel@tonic-gate * All functions that understand the linked list of iob's follow. 1530Sstevel@tonic-gate */ 1540Sstevel@tonic-gate #pragma weak _cleanup = __cleanup 1550Sstevel@tonic-gate void 1560Sstevel@tonic-gate __cleanup(void) /* called at process end to flush ouput streams */ 1570Sstevel@tonic-gate { 1580Sstevel@tonic-gate (void) fflush(NULL); 1590Sstevel@tonic-gate } 1600Sstevel@tonic-gate 1610Sstevel@tonic-gate /* 1620Sstevel@tonic-gate * For fork1-safety (see libc_prepare_atfork(), etc). 1630Sstevel@tonic-gate */ 1640Sstevel@tonic-gate void 1650Sstevel@tonic-gate stdio_locks() 1660Sstevel@tonic-gate { 1670Sstevel@tonic-gate (void) __rw_wrlock(&_first_link_lock); 1680Sstevel@tonic-gate /* 1690Sstevel@tonic-gate * XXX: We should acquire all of the iob locks here. 1700Sstevel@tonic-gate */ 1710Sstevel@tonic-gate } 1720Sstevel@tonic-gate 1730Sstevel@tonic-gate void 1740Sstevel@tonic-gate stdio_unlocks() 1750Sstevel@tonic-gate { 1760Sstevel@tonic-gate /* 1770Sstevel@tonic-gate * XXX: We should release all of the iob locks here. 1780Sstevel@tonic-gate */ 1790Sstevel@tonic-gate (void) __rw_unlock(&_first_link_lock); 1800Sstevel@tonic-gate } 1810Sstevel@tonic-gate 1820Sstevel@tonic-gate void 1830Sstevel@tonic-gate _flushlbf(void) /* fflush() all line-buffered streams */ 1840Sstevel@tonic-gate { 1850Sstevel@tonic-gate FPDECL(fp); 1860Sstevel@tonic-gate int i; 1870Sstevel@tonic-gate struct _link_ *lp; 1880Sstevel@tonic-gate 189*1672Sraf if (__libc_threaded) 1900Sstevel@tonic-gate (void) __rw_rdlock(&_first_link_lock); 1910Sstevel@tonic-gate 1920Sstevel@tonic-gate lp = &__first_link; 1930Sstevel@tonic-gate do { 1940Sstevel@tonic-gate FIRSTFP(lp, fp); 1950Sstevel@tonic-gate for (i = lp->niob; --i >= 0; NEXTFP(fp)) { 1960Sstevel@tonic-gate if ((fp->_flag & (_IOLBF | _IOWRT)) == 1970Sstevel@tonic-gate (_IOLBF | _IOWRT)) 1980Sstevel@tonic-gate (void) _fflush_u(fp); 1990Sstevel@tonic-gate } 2000Sstevel@tonic-gate } while ((lp = lp->next) != NULL); 2010Sstevel@tonic-gate 202*1672Sraf if (__libc_threaded) 2030Sstevel@tonic-gate (void) __rw_unlock(&_first_link_lock); 2040Sstevel@tonic-gate } 2050Sstevel@tonic-gate 2060Sstevel@tonic-gate /* allocate an unused stream; NULL if cannot */ 2070Sstevel@tonic-gate FILE * 2080Sstevel@tonic-gate _findiop(void) 2090Sstevel@tonic-gate { 2100Sstevel@tonic-gate struct _link_ *lp, **prev; 2110Sstevel@tonic-gate 2120Sstevel@tonic-gate /* used so there only needs to be one malloc() */ 2130Sstevel@tonic-gate #ifdef _LP64 2140Sstevel@tonic-gate typedef struct { 2150Sstevel@tonic-gate struct _link_ hdr; 2160Sstevel@tonic-gate FILE iob[FILE_ARY_SZ]; 2170Sstevel@tonic-gate } Pkg; 2180Sstevel@tonic-gate #else 2190Sstevel@tonic-gate typedef union { 2200Sstevel@tonic-gate struct { /* Normal */ 2210Sstevel@tonic-gate struct _link_ hdr; 2220Sstevel@tonic-gate xFILE iob[FILE_ARY_SZ]; 2230Sstevel@tonic-gate } Pkgn; 2240Sstevel@tonic-gate struct { /* Reversed */ 2250Sstevel@tonic-gate xFILE iob[FILE_ARY_SZ]; 2260Sstevel@tonic-gate struct _link_ hdr; 2270Sstevel@tonic-gate } Pkgr; 2280Sstevel@tonic-gate } Pkg; 2290Sstevel@tonic-gate uintptr_t delta; 2300Sstevel@tonic-gate #endif 2310Sstevel@tonic-gate Pkg *pkgp; 2320Sstevel@tonic-gate struct _link_ *hdr; 2330Sstevel@tonic-gate FPDECL(fp); 2340Sstevel@tonic-gate int i; 2350Sstevel@tonic-gate 236*1672Sraf if (__libc_threaded) 2370Sstevel@tonic-gate (void) __rw_wrlock(&_first_link_lock); 2380Sstevel@tonic-gate 2390Sstevel@tonic-gate if (lastlink == NULL) { 2400Sstevel@tonic-gate rescan: 2410Sstevel@tonic-gate fcloses = 0; 2420Sstevel@tonic-gate lastlink = &__first_link; 2430Sstevel@tonic-gate } 2440Sstevel@tonic-gate 2450Sstevel@tonic-gate lp = lastlink; 2460Sstevel@tonic-gate 2470Sstevel@tonic-gate /* 2480Sstevel@tonic-gate * lock to make testing of fp->_flag == 0 and acquiring the fp atomic 2490Sstevel@tonic-gate * and for allocation of new links 2500Sstevel@tonic-gate * low contention expected on _findiop(), hence coarse locking. 2510Sstevel@tonic-gate * for finer granularity, use fp->_lock for allocating an iop 2520Sstevel@tonic-gate * and make the testing of lp->next and allocation of new link atomic 2530Sstevel@tonic-gate * using lp->_lock 2540Sstevel@tonic-gate */ 2550Sstevel@tonic-gate 2560Sstevel@tonic-gate do { 2570Sstevel@tonic-gate prev = &lp->next; 2580Sstevel@tonic-gate FIRSTFP(lp, fp); 2590Sstevel@tonic-gate 2600Sstevel@tonic-gate for (i = lp->niob; --i >= 0; NEXTFP(fp)) { 2610Sstevel@tonic-gate #ifdef _LP64 2620Sstevel@tonic-gate GETIOP(fp, &fp->_lock, &fp->_state); 2630Sstevel@tonic-gate #else 2640Sstevel@tonic-gate GETIOP(fp, 2650Sstevel@tonic-gate xfp ? &xfp->xlock : &_xftab[IOPIND(fp)]._lock, 2660Sstevel@tonic-gate xfp ? &xfp->xstate : &_xftab[IOPIND(fp)]._state); 2670Sstevel@tonic-gate #endif /* _LP64 */ 2680Sstevel@tonic-gate } 2690Sstevel@tonic-gate } while ((lastlink = lp = lp->next) != NULL); 2700Sstevel@tonic-gate 2710Sstevel@tonic-gate /* 2720Sstevel@tonic-gate * If there was a sufficient number of fcloses since we last started 2730Sstevel@tonic-gate * at __first_link, we rescan all fp's again. We do not rescan for 2740Sstevel@tonic-gate * all fcloses; that would simplify the algorithm but would make 2750Sstevel@tonic-gate * search times near O(n) again. 2760Sstevel@tonic-gate * Worst case behaviour would still be pretty bad (open a full set, 2770Sstevel@tonic-gate * then continously opening and closing one FILE * gets you a full 2780Sstevel@tonic-gate * scan each time). That's why we over allocate 1 FILE for each 2790Sstevel@tonic-gate * 32 chunks. More over allocation is better; this is a nice 2800Sstevel@tonic-gate * empirical value which doesn't cost a lot of memory, doesn't 2810Sstevel@tonic-gate * overallocate until we reach 256 FILE *s and keeps the performance 2820Sstevel@tonic-gate * pretty close to the optimum. 2830Sstevel@tonic-gate */ 2840Sstevel@tonic-gate if (fcloses > nchunks/32) 2850Sstevel@tonic-gate goto rescan; 2860Sstevel@tonic-gate 2870Sstevel@tonic-gate /* 2880Sstevel@tonic-gate * Need to allocate another and put it in the linked list. 2890Sstevel@tonic-gate */ 2900Sstevel@tonic-gate if ((pkgp = malloc(sizeof (Pkg))) == NULL) { 291*1672Sraf if (__libc_threaded) 2920Sstevel@tonic-gate (void) __rw_unlock(&_first_link_lock); 2930Sstevel@tonic-gate return (NULL); 2940Sstevel@tonic-gate } 2950Sstevel@tonic-gate 2960Sstevel@tonic-gate (void) memset(pkgp, 0, sizeof (Pkg)); 2970Sstevel@tonic-gate 2980Sstevel@tonic-gate #ifdef _LP64 2990Sstevel@tonic-gate hdr = &pkgp->hdr; 3000Sstevel@tonic-gate hdr->iobp = &pkgp->iob[0]; 3010Sstevel@tonic-gate #else 3020Sstevel@tonic-gate /* 3030Sstevel@tonic-gate * The problem with referencing a word after a FILE* is the possibility 3040Sstevel@tonic-gate * of a SIGSEGV if a non-stdio issue FILE structure ends on a page 3050Sstevel@tonic-gate * boundary. We run this check so we never need to run an expensive 3060Sstevel@tonic-gate * check like mincore() in order to know whether it is 3070Sstevel@tonic-gate * safe to dereference ((xFILE*)fp)->xmagic. 3080Sstevel@tonic-gate * We allocate the block with two alternative layouts; if one 3090Sstevel@tonic-gate * layout is not properly aligned for our purposes, the other layout 3100Sstevel@tonic-gate * will be because the size of _link_ is small compared to 3110Sstevel@tonic-gate * sizeof (xFILE). 3120Sstevel@tonic-gate * The check performed is this: 3130Sstevel@tonic-gate * If the distance from pkgp to the end of the page is 3140Sstevel@tonic-gate * less than the the offset of the last xmagic field in the 3150Sstevel@tonic-gate * xFILE structure, (the 0x1000 boundary is inside our just 3160Sstevel@tonic-gate * allocated structure) and the distance modulo the size of xFILE 3170Sstevel@tonic-gate * is identical to the offset of the first xmagic in the 3180Sstevel@tonic-gate * structure (i.e., XXXXXX000 points to an xmagic field), 3190Sstevel@tonic-gate * we need to use the reverse structure. 3200Sstevel@tonic-gate */ 3210Sstevel@tonic-gate if ((delta = 0x1000 - ((uintptr_t)pkgp & 0xfff)) <= 3220Sstevel@tonic-gate offsetof(Pkg, Pkgn.iob[FILE_ARY_SZ-1].xmagic) && 3230Sstevel@tonic-gate delta % sizeof (struct xFILE) == 3240Sstevel@tonic-gate offsetof(Pkg, Pkgn.iob[0].xmagic)) { 3250Sstevel@tonic-gate /* Use reversed structure */ 3260Sstevel@tonic-gate hdr = &pkgp->Pkgr.hdr; 3270Sstevel@tonic-gate hdr->iobp = &pkgp->Pkgr.iob[0]; 3280Sstevel@tonic-gate } else { 3290Sstevel@tonic-gate /* Use normal structure */ 3300Sstevel@tonic-gate hdr = &pkgp->Pkgn.hdr; 3310Sstevel@tonic-gate hdr->iobp = &pkgp->Pkgn.iob[0]; 3320Sstevel@tonic-gate } 3330Sstevel@tonic-gate #endif /* _LP64 */ 3340Sstevel@tonic-gate 3350Sstevel@tonic-gate hdr->niob = FILE_ARY_SZ; 3360Sstevel@tonic-gate nchunks++; 3370Sstevel@tonic-gate 3380Sstevel@tonic-gate #ifdef _LP64 3390Sstevel@tonic-gate fp = hdr->iobp; 3400Sstevel@tonic-gate for (i = 0; i < FILE_ARY_SZ; i++) 3410Sstevel@tonic-gate _private_mutex_init(&fp[i]._lock, 3420Sstevel@tonic-gate USYNC_THREAD|LOCK_RECURSIVE, NULL); 3430Sstevel@tonic-gate #else 3440Sstevel@tonic-gate xfp = hdr->iobp; 3450Sstevel@tonic-gate fp = &xfp->_iob; 3460Sstevel@tonic-gate 3470Sstevel@tonic-gate for (i = 0; i < FILE_ARY_SZ; i++) { 3480Sstevel@tonic-gate xfp[i].xmagic = XMAGIC(&xfp[i]); 3490Sstevel@tonic-gate _private_mutex_init(&xfp[i].xlock, 3500Sstevel@tonic-gate USYNC_THREAD|LOCK_RECURSIVE, NULL); 3510Sstevel@tonic-gate } 3520Sstevel@tonic-gate #endif /* _LP64 */ 3530Sstevel@tonic-gate 3540Sstevel@tonic-gate lastlink = *prev = hdr; 3550Sstevel@tonic-gate fp->_ptr = 0; 3560Sstevel@tonic-gate fp->_base = 0; 3570Sstevel@tonic-gate fp->_flag = 0377; /* claim the fp by setting low 8 bits */ 358*1672Sraf if (__libc_threaded) 3590Sstevel@tonic-gate (void) __rw_unlock(&_first_link_lock); 3600Sstevel@tonic-gate 3610Sstevel@tonic-gate return (fp); 3620Sstevel@tonic-gate } 3630Sstevel@tonic-gate 3640Sstevel@tonic-gate static void 3650Sstevel@tonic-gate isseekable(FILE *iop) 3660Sstevel@tonic-gate { 3670Sstevel@tonic-gate struct stat64 fstatbuf; 3680Sstevel@tonic-gate int save_errno; 3690Sstevel@tonic-gate 3700Sstevel@tonic-gate save_errno = errno; 3710Sstevel@tonic-gate 3720Sstevel@tonic-gate if (fstat64(iop->_file, &fstatbuf) != 0) { 3730Sstevel@tonic-gate /* 3740Sstevel@tonic-gate * when we don't know what it is we'll 3750Sstevel@tonic-gate * do the old behaviour and flush 3760Sstevel@tonic-gate * the stream 3770Sstevel@tonic-gate */ 3780Sstevel@tonic-gate SET_SEEKABLE(iop); 3790Sstevel@tonic-gate errno = save_errno; 3800Sstevel@tonic-gate return; 3810Sstevel@tonic-gate } 3820Sstevel@tonic-gate 3830Sstevel@tonic-gate /* 3840Sstevel@tonic-gate * check for what is non-SEEKABLE 3850Sstevel@tonic-gate * otherwise assume it's SEEKABLE so we get the old 3860Sstevel@tonic-gate * behaviour and flush the stream 3870Sstevel@tonic-gate */ 3880Sstevel@tonic-gate 3890Sstevel@tonic-gate if (S_ISFIFO(fstatbuf.st_mode) || S_ISCHR(fstatbuf.st_mode) || 3900Sstevel@tonic-gate S_ISSOCK(fstatbuf.st_mode) || S_ISDOOR(fstatbuf.st_mode)) { 3910Sstevel@tonic-gate CLEAR_SEEKABLE(iop); 3920Sstevel@tonic-gate } else { 3930Sstevel@tonic-gate SET_SEEKABLE(iop); 3940Sstevel@tonic-gate } 3950Sstevel@tonic-gate 3960Sstevel@tonic-gate errno = save_errno; 3970Sstevel@tonic-gate } 3980Sstevel@tonic-gate 3990Sstevel@tonic-gate #ifdef _LP64 4000Sstevel@tonic-gate void 4010Sstevel@tonic-gate _setbufend(FILE *iop, Uchar *end) /* set the end pointer for this iop */ 4020Sstevel@tonic-gate { 4030Sstevel@tonic-gate iop->_end = end; 4040Sstevel@tonic-gate 4050Sstevel@tonic-gate isseekable(iop); 4060Sstevel@tonic-gate } 4070Sstevel@tonic-gate 4080Sstevel@tonic-gate #undef _realbufend 4090Sstevel@tonic-gate 4100Sstevel@tonic-gate Uchar * 4110Sstevel@tonic-gate _realbufend(FILE *iop) /* get the end pointer for this iop */ 4120Sstevel@tonic-gate { 4130Sstevel@tonic-gate return (iop->_end); 4140Sstevel@tonic-gate } 4150Sstevel@tonic-gate 4160Sstevel@tonic-gate #else /* _LP64 */ 4170Sstevel@tonic-gate 4180Sstevel@tonic-gate /* 4190Sstevel@tonic-gate * Awkward functions not needed for the sane 64 bit environment. 4200Sstevel@tonic-gate */ 4210Sstevel@tonic-gate /* 4220Sstevel@tonic-gate * xmagic must not be aligned on a 4K boundary. We guarantee this in 4230Sstevel@tonic-gate * _findiop(). 4240Sstevel@tonic-gate */ 4250Sstevel@tonic-gate #define VALIDXFILE(xfp) \ 4260Sstevel@tonic-gate (((uintptr_t)&(xfp)->xmagic & 0xfff) && \ 4270Sstevel@tonic-gate (xfp)->xmagic == XMAGIC(FILEx(xfp))) 4280Sstevel@tonic-gate 4290Sstevel@tonic-gate static struct xFILEdata * 4300Sstevel@tonic-gate getxfdat(FILE *iop) 4310Sstevel@tonic-gate { 4320Sstevel@tonic-gate if (STDIOP(iop)) 4330Sstevel@tonic-gate return (&_xftab[IOPIND(iop)]); 4340Sstevel@tonic-gate else if (VALIDXFILE(FILEx(iop))) 4350Sstevel@tonic-gate return (&FILEx(iop)->_xdat); 4360Sstevel@tonic-gate else 4370Sstevel@tonic-gate return (NULL); 4380Sstevel@tonic-gate } 4390Sstevel@tonic-gate 4400Sstevel@tonic-gate void 4410Sstevel@tonic-gate _setbufend(FILE *iop, Uchar *end) /* set the end pointer for this iop */ 4420Sstevel@tonic-gate { 4430Sstevel@tonic-gate struct xFILEdata *dat = getxfdat(iop); 4440Sstevel@tonic-gate 4450Sstevel@tonic-gate if (dat != NULL) 4460Sstevel@tonic-gate dat->_end = end; 4470Sstevel@tonic-gate 4480Sstevel@tonic-gate isseekable(iop); 4490Sstevel@tonic-gate 4500Sstevel@tonic-gate /* 4510Sstevel@tonic-gate * For binary compatibility with user programs using the 4520Sstevel@tonic-gate * old _bufend macro. This is *so* broken, fileno() 4530Sstevel@tonic-gate * is not the proper index. 4540Sstevel@tonic-gate */ 4550Sstevel@tonic-gate if (iop->_file < _NFILE) 4560Sstevel@tonic-gate _bufendtab[iop->_file] = end; 4570Sstevel@tonic-gate 4580Sstevel@tonic-gate } 4590Sstevel@tonic-gate 4600Sstevel@tonic-gate Uchar * 4610Sstevel@tonic-gate _realbufend(FILE *iop) /* get the end pointer for this iop */ 4620Sstevel@tonic-gate { 4630Sstevel@tonic-gate struct xFILEdata *dat = getxfdat(iop); 4640Sstevel@tonic-gate 4650Sstevel@tonic-gate if (dat != NULL) 4660Sstevel@tonic-gate return (dat->_end); 4670Sstevel@tonic-gate 4680Sstevel@tonic-gate return (NULL); 4690Sstevel@tonic-gate } 4700Sstevel@tonic-gate 4710Sstevel@tonic-gate /* 4720Sstevel@tonic-gate * _reallock() is invoked in each stdio call through the IOB_LCK() macro, 4730Sstevel@tonic-gate * it is therefor extremely performance sensitive. We get better performance 4740Sstevel@tonic-gate * by inlining the STDIOP check in IOB_LCK and inlining a custom version 4750Sstevel@tonic-gate * of getfxdat() here. 4760Sstevel@tonic-gate */ 4770Sstevel@tonic-gate rmutex_t * 4780Sstevel@tonic-gate _reallock(FILE *iop) 4790Sstevel@tonic-gate { 4800Sstevel@tonic-gate if (VALIDXFILE(FILEx(iop))) 4810Sstevel@tonic-gate return (&FILEx(iop)->xlock); 4820Sstevel@tonic-gate 4830Sstevel@tonic-gate return (NULL); 4840Sstevel@tonic-gate } 4850Sstevel@tonic-gate 4860Sstevel@tonic-gate #endif /* _LP64 */ 4870Sstevel@tonic-gate 4880Sstevel@tonic-gate /* make sure _cnt, _ptr are correct */ 4890Sstevel@tonic-gate void 4900Sstevel@tonic-gate _bufsync(FILE *iop, Uchar *bufend) 4910Sstevel@tonic-gate { 4920Sstevel@tonic-gate ssize_t spaceleft; 4930Sstevel@tonic-gate 4940Sstevel@tonic-gate spaceleft = bufend - iop->_ptr; 4950Sstevel@tonic-gate if (bufend < iop->_ptr) { 4960Sstevel@tonic-gate iop->_ptr = bufend; 4970Sstevel@tonic-gate iop->_cnt = 0; 4980Sstevel@tonic-gate } else if (spaceleft < iop->_cnt) 4990Sstevel@tonic-gate iop->_cnt = spaceleft; 5000Sstevel@tonic-gate } 5010Sstevel@tonic-gate 5020Sstevel@tonic-gate /* really write out current buffer contents */ 5030Sstevel@tonic-gate int 5040Sstevel@tonic-gate _xflsbuf(FILE *iop) 5050Sstevel@tonic-gate { 5060Sstevel@tonic-gate ssize_t n; 5070Sstevel@tonic-gate Uchar *base = iop->_base; 5080Sstevel@tonic-gate Uchar *bufend; 5090Sstevel@tonic-gate ssize_t num_wrote; 5100Sstevel@tonic-gate 5110Sstevel@tonic-gate /* 5120Sstevel@tonic-gate * Hopefully, be stable with respect to interrupts... 5130Sstevel@tonic-gate */ 5140Sstevel@tonic-gate n = iop->_ptr - base; 5150Sstevel@tonic-gate iop->_ptr = base; 5160Sstevel@tonic-gate bufend = _bufend(iop); 5170Sstevel@tonic-gate if (iop->_flag & (_IOLBF | _IONBF)) 5180Sstevel@tonic-gate iop->_cnt = 0; /* always go to a flush */ 5190Sstevel@tonic-gate else 5200Sstevel@tonic-gate iop->_cnt = bufend - base; 5210Sstevel@tonic-gate 5220Sstevel@tonic-gate if (_needsync(iop, bufend)) /* recover from interrupts */ 5230Sstevel@tonic-gate _bufsync(iop, bufend); 5240Sstevel@tonic-gate 5250Sstevel@tonic-gate if (n > 0) { 5260Sstevel@tonic-gate while ((num_wrote = 5270Sstevel@tonic-gate write(iop->_file, base, (size_t)n)) != n) { 5280Sstevel@tonic-gate if (num_wrote <= 0) { 5290Sstevel@tonic-gate iop->_flag |= _IOERR; 5300Sstevel@tonic-gate return (EOF); 5310Sstevel@tonic-gate } 5320Sstevel@tonic-gate n -= num_wrote; 5330Sstevel@tonic-gate base += num_wrote; 5340Sstevel@tonic-gate } 5350Sstevel@tonic-gate } 5360Sstevel@tonic-gate return (0); 5370Sstevel@tonic-gate } 5380Sstevel@tonic-gate 5390Sstevel@tonic-gate /* flush (write) buffer */ 5400Sstevel@tonic-gate int 5410Sstevel@tonic-gate fflush(FILE *iop) 5420Sstevel@tonic-gate { 5430Sstevel@tonic-gate int res; 5440Sstevel@tonic-gate rmutex_t *lk; 5450Sstevel@tonic-gate 5460Sstevel@tonic-gate if (iop) { 5470Sstevel@tonic-gate FLOCKFILE(lk, iop); 5480Sstevel@tonic-gate res = _fflush_u(iop); 5490Sstevel@tonic-gate FUNLOCKFILE(lk); 5500Sstevel@tonic-gate } else { 5510Sstevel@tonic-gate res = _fflush_u_iops(); /* flush all iops */ 5520Sstevel@tonic-gate } 5530Sstevel@tonic-gate return (res); 5540Sstevel@tonic-gate } 5550Sstevel@tonic-gate 5560Sstevel@tonic-gate static int 5570Sstevel@tonic-gate _fflush_u_iops(void) /* flush all buffers */ 5580Sstevel@tonic-gate { 5590Sstevel@tonic-gate FPDECL(iop); 5600Sstevel@tonic-gate 5610Sstevel@tonic-gate int i; 5620Sstevel@tonic-gate struct _link_ *lp; 5630Sstevel@tonic-gate int res = 0; 5640Sstevel@tonic-gate 565*1672Sraf if (__libc_threaded) 5660Sstevel@tonic-gate (void) __rw_rdlock(&_first_link_lock); 5670Sstevel@tonic-gate 5680Sstevel@tonic-gate lp = &__first_link; 5690Sstevel@tonic-gate 5700Sstevel@tonic-gate do { 5710Sstevel@tonic-gate /* 5720Sstevel@tonic-gate * Don't grab the locks for these file pointers 5730Sstevel@tonic-gate * since they are supposed to be flushed anyway 5740Sstevel@tonic-gate * It could also be the case in which the 2nd 5750Sstevel@tonic-gate * portion (base and lock) are not initialized 5760Sstevel@tonic-gate */ 5770Sstevel@tonic-gate FIRSTFP(lp, iop); 5780Sstevel@tonic-gate for (i = lp->niob; --i >= 0; NEXTFP(iop)) { 5790Sstevel@tonic-gate if (!(iop->_flag & _IONBF)) { 5800Sstevel@tonic-gate /* 5810Sstevel@tonic-gate * don't need to worry about the _IORW case 5820Sstevel@tonic-gate * since the iop will also marked with _IOREAD 5830Sstevel@tonic-gate * or _IOWRT whichever we are really doing 5840Sstevel@tonic-gate */ 5850Sstevel@tonic-gate if (iop->_flag & _IOWRT) { /* flush write buffers */ 5860Sstevel@tonic-gate res |= _fflush_u(iop); 5870Sstevel@tonic-gate } else if (iop->_flag & _IOREAD) { 5880Sstevel@tonic-gate /* 5890Sstevel@tonic-gate * flush seekable read buffers 5900Sstevel@tonic-gate * don't flush non-seekable read buffers 5910Sstevel@tonic-gate */ 5920Sstevel@tonic-gate if (GET_SEEKABLE(iop)) { 5930Sstevel@tonic-gate res |= _fflush_u(iop); 5940Sstevel@tonic-gate } 5950Sstevel@tonic-gate } 5960Sstevel@tonic-gate } 5970Sstevel@tonic-gate } 5980Sstevel@tonic-gate } while ((lp = lp->next) != NULL); 599*1672Sraf if (__libc_threaded) 6000Sstevel@tonic-gate (void) __rw_unlock(&_first_link_lock); 6010Sstevel@tonic-gate return (res); 6020Sstevel@tonic-gate } 6030Sstevel@tonic-gate 6040Sstevel@tonic-gate /* flush buffer */ 6050Sstevel@tonic-gate int 6060Sstevel@tonic-gate _fflush_u(FILE *iop) 6070Sstevel@tonic-gate { 6080Sstevel@tonic-gate int res = 0; 6090Sstevel@tonic-gate 6100Sstevel@tonic-gate /* this portion is always assumed locked */ 6110Sstevel@tonic-gate if (!(iop->_flag & _IOWRT)) { 6120Sstevel@tonic-gate (void) lseek64(iop->_file, -iop->_cnt, SEEK_CUR); 6130Sstevel@tonic-gate iop->_cnt = 0; 6140Sstevel@tonic-gate /* needed for ungetc & multibyte pushbacks */ 6150Sstevel@tonic-gate iop->_ptr = iop->_base; 6160Sstevel@tonic-gate if (iop->_flag & _IORW) { 6170Sstevel@tonic-gate iop->_flag &= ~_IOREAD; 6180Sstevel@tonic-gate } 6190Sstevel@tonic-gate return (0); 6200Sstevel@tonic-gate } 6210Sstevel@tonic-gate if (iop->_base != NULL && iop->_ptr > iop->_base) { 6220Sstevel@tonic-gate res = _xflsbuf(iop); 6230Sstevel@tonic-gate } 6240Sstevel@tonic-gate if (iop->_flag & _IORW) { 6250Sstevel@tonic-gate iop->_flag &= ~_IOWRT; 6260Sstevel@tonic-gate iop->_cnt = 0; 6270Sstevel@tonic-gate } 6280Sstevel@tonic-gate return (res); 6290Sstevel@tonic-gate } 6300Sstevel@tonic-gate 6310Sstevel@tonic-gate /* flush buffer and close stream */ 6320Sstevel@tonic-gate int 6330Sstevel@tonic-gate fclose(FILE *iop) 6340Sstevel@tonic-gate { 6350Sstevel@tonic-gate int res = 0; 6360Sstevel@tonic-gate rmutex_t *lk; 6370Sstevel@tonic-gate 6380Sstevel@tonic-gate if (iop == NULL) { 6390Sstevel@tonic-gate return (EOF); /* avoid passing zero to FLOCKFILE */ 6400Sstevel@tonic-gate } 6410Sstevel@tonic-gate 6420Sstevel@tonic-gate FLOCKFILE(lk, iop); 6430Sstevel@tonic-gate if (iop->_flag == 0) { 6440Sstevel@tonic-gate FUNLOCKFILE(lk); 6450Sstevel@tonic-gate return (EOF); 6460Sstevel@tonic-gate } 6470Sstevel@tonic-gate /* Is not unbuffered and opened for read and/or write ? */ 6480Sstevel@tonic-gate if (!(iop->_flag & _IONBF) && (iop->_flag & (_IOWRT | _IOREAD | _IORW))) 6490Sstevel@tonic-gate res = _fflush_u(iop); 6500Sstevel@tonic-gate if (close(iop->_file) < 0) 6510Sstevel@tonic-gate res = EOF; 6520Sstevel@tonic-gate if (iop->_flag & _IOMYBUF) { 6530Sstevel@tonic-gate (void) free((char *)iop->_base - PUSHBACK); 6540Sstevel@tonic-gate } 6550Sstevel@tonic-gate iop->_base = NULL; 6560Sstevel@tonic-gate iop->_ptr = NULL; 6570Sstevel@tonic-gate iop->_cnt = 0; 6580Sstevel@tonic-gate iop->_flag = 0; /* marks it as available */ 6590Sstevel@tonic-gate FUNLOCKFILE(lk); 6600Sstevel@tonic-gate 661*1672Sraf if (__libc_threaded) 6620Sstevel@tonic-gate (void) __rw_wrlock(&_first_link_lock); 6630Sstevel@tonic-gate fcloses++; 664*1672Sraf if (__libc_threaded) 6650Sstevel@tonic-gate (void) __rw_unlock(&_first_link_lock); 6660Sstevel@tonic-gate 6670Sstevel@tonic-gate return (res); 6680Sstevel@tonic-gate } 6690Sstevel@tonic-gate 6700Sstevel@tonic-gate /* flush buffer, close fd but keep the stream used by freopen() */ 6710Sstevel@tonic-gate int 6720Sstevel@tonic-gate close_fd(FILE *iop) 6730Sstevel@tonic-gate { 6740Sstevel@tonic-gate int res = 0; 6750Sstevel@tonic-gate mbstate_t *mb; 6760Sstevel@tonic-gate 6770Sstevel@tonic-gate if (iop == NULL || iop->_flag == 0) 6780Sstevel@tonic-gate return (EOF); 6790Sstevel@tonic-gate /* Is not unbuffered and opened for read and/or write ? */ 6800Sstevel@tonic-gate if (!(iop->_flag & _IONBF) && (iop->_flag & (_IOWRT | _IOREAD | _IORW))) 6810Sstevel@tonic-gate res = _fflush_u(iop); 6820Sstevel@tonic-gate if (close(iop->_file) < 0) 6830Sstevel@tonic-gate res = EOF; 6840Sstevel@tonic-gate if (iop->_flag & _IOMYBUF) { 6850Sstevel@tonic-gate (void) free((char *)iop->_base - PUSHBACK); 6860Sstevel@tonic-gate } 6870Sstevel@tonic-gate iop->_base = NULL; 6880Sstevel@tonic-gate iop->_ptr = NULL; 6890Sstevel@tonic-gate mb = _getmbstate(iop); 6900Sstevel@tonic-gate if (mb != NULL) 6910Sstevel@tonic-gate (void) memset(mb, 0, sizeof (mbstate_t)); 6920Sstevel@tonic-gate iop->_cnt = 0; 6930Sstevel@tonic-gate _setorientation(iop, _NO_MODE); 6940Sstevel@tonic-gate return (res); 6950Sstevel@tonic-gate } 6960Sstevel@tonic-gate 6970Sstevel@tonic-gate static FILE * 6980Sstevel@tonic-gate getiop(FILE *fp, rmutex_t *lk, mbstate_t *mb) 6990Sstevel@tonic-gate { 7000Sstevel@tonic-gate if (lk != NULL && rmutex_trylock(lk)) 7010Sstevel@tonic-gate return (NULL); /* locked: fp in use */ 7020Sstevel@tonic-gate 7030Sstevel@tonic-gate if (fp->_flag == 0) { /* unused */ 7040Sstevel@tonic-gate #ifndef _LP64 7050Sstevel@tonic-gate fp->__orientation = 0; 7060Sstevel@tonic-gate #endif /* _LP64 */ 7070Sstevel@tonic-gate fp->_cnt = 0; 7080Sstevel@tonic-gate fp->_ptr = NULL; 7090Sstevel@tonic-gate fp->_base = NULL; 7100Sstevel@tonic-gate fp->_flag = 0377; /* claim the fp by setting low 8 bits */ 7110Sstevel@tonic-gate (void) memset(mb, 0, sizeof (mbstate_t)); 7120Sstevel@tonic-gate FUNLOCKFILE(lk); 7130Sstevel@tonic-gate return (fp); 7140Sstevel@tonic-gate } 7150Sstevel@tonic-gate FUNLOCKFILE(lk); 7160Sstevel@tonic-gate return (NULL); 7170Sstevel@tonic-gate } 7180Sstevel@tonic-gate 7190Sstevel@tonic-gate #ifndef _LP64 7200Sstevel@tonic-gate /* 7210Sstevel@tonic-gate * DESCRIPTION: 7220Sstevel@tonic-gate * This function gets the pointer to the mbstate_t structure associated 7230Sstevel@tonic-gate * with the specified iop. 7240Sstevel@tonic-gate * 7250Sstevel@tonic-gate * RETURNS: 7260Sstevel@tonic-gate * If the associated mbstate_t found, the pointer to the mbstate_t is 7270Sstevel@tonic-gate * returned. Otherwise, NULL is returned. 7280Sstevel@tonic-gate */ 7290Sstevel@tonic-gate mbstate_t * 7300Sstevel@tonic-gate _getmbstate(FILE *iop) 7310Sstevel@tonic-gate { 7320Sstevel@tonic-gate struct xFILEdata *dat = getxfdat(iop); 7330Sstevel@tonic-gate 7340Sstevel@tonic-gate if (dat != NULL) 7350Sstevel@tonic-gate return (&dat->_state); 7360Sstevel@tonic-gate 7370Sstevel@tonic-gate return (NULL); 7380Sstevel@tonic-gate } 7390Sstevel@tonic-gate #endif 740