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 51d2738a5Sraf * Common Development and Distribution License (the "License"). 61d2738a5Sraf * 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 */ 211d2738a5Sraf 227c478bd9Sstevel@tonic-gate /* 231d2738a5Sraf * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 247c478bd9Sstevel@tonic-gate * Use is subject to license terms. 257c478bd9Sstevel@tonic-gate */ 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 287c478bd9Sstevel@tonic-gate 297c478bd9Sstevel@tonic-gate /* Copyright (c) 1988 AT&T */ 307c478bd9Sstevel@tonic-gate /* All Rights Reserved */ 317c478bd9Sstevel@tonic-gate 327c478bd9Sstevel@tonic-gate 337c478bd9Sstevel@tonic-gate #include "synonyms.h" 347c478bd9Sstevel@tonic-gate #include "mtlib.h" 357c478bd9Sstevel@tonic-gate #include "file64.h" 36*a5f69788Scraigm #include "../gen/_libc_gettext.h" 377c478bd9Sstevel@tonic-gate 387c478bd9Sstevel@tonic-gate #define _iob __iob 397c478bd9Sstevel@tonic-gate 407c478bd9Sstevel@tonic-gate #include <sys/types.h> 417c478bd9Sstevel@tonic-gate #include <stdlib.h> 427c478bd9Sstevel@tonic-gate #include <stdio.h> 437c478bd9Sstevel@tonic-gate #include <thread.h> 447c478bd9Sstevel@tonic-gate #include <synch.h> 457c478bd9Sstevel@tonic-gate #include <unistd.h> 467c478bd9Sstevel@tonic-gate #include <string.h> 477c478bd9Sstevel@tonic-gate #include "stdiom.h" 487c478bd9Sstevel@tonic-gate #include <wchar.h> 497c478bd9Sstevel@tonic-gate #include <sys/stat.h> 507c478bd9Sstevel@tonic-gate #include <stddef.h> 517c478bd9Sstevel@tonic-gate #include <errno.h> 52*a5f69788Scraigm #include <fcntl.h> 537c478bd9Sstevel@tonic-gate 547c478bd9Sstevel@tonic-gate #undef end 557c478bd9Sstevel@tonic-gate 567c478bd9Sstevel@tonic-gate #define FILE_ARY_SZ 8 /* a nice size for FILE array & end_buffer_ptrs */ 577c478bd9Sstevel@tonic-gate 587c478bd9Sstevel@tonic-gate #ifdef _LP64 597c478bd9Sstevel@tonic-gate 607c478bd9Sstevel@tonic-gate /* 617c478bd9Sstevel@tonic-gate * Macros to declare and loop over a fp or fp/xfp combo to 627c478bd9Sstevel@tonic-gate * avoid some of the _LP64 ifdef hell. 637c478bd9Sstevel@tonic-gate */ 647c478bd9Sstevel@tonic-gate 657c478bd9Sstevel@tonic-gate #define FPDECL(fp) FILE *fp 667c478bd9Sstevel@tonic-gate #define FIRSTFP(lp, fp) fp = lp->iobp 677c478bd9Sstevel@tonic-gate #define NEXTFP(fp) fp++ 68*a5f69788Scraigm #define FPLOCK(fp) &fp->_lock 69*a5f69788Scraigm #define FPSTATE(fp) &fp->_state 707c478bd9Sstevel@tonic-gate 717c478bd9Sstevel@tonic-gate #define xFILE FILE 727c478bd9Sstevel@tonic-gate 737c478bd9Sstevel@tonic-gate #else 747c478bd9Sstevel@tonic-gate 757c478bd9Sstevel@tonic-gate #define FPDECL(fp) FILE *fp; xFILE *x##fp 767c478bd9Sstevel@tonic-gate #define FIRSTFP(lp, fp) x##fp = lp->iobp; \ 777c478bd9Sstevel@tonic-gate fp = x##fp ? &x##fp->_iob : &_iob[0] 787c478bd9Sstevel@tonic-gate #define NEXTFP(fp) (x##fp ? fp = &(++x##fp)->_iob : ++fp) 79*a5f69788Scraigm #define FPLOCK(fp) x##fp ? \ 80*a5f69788Scraigm &x##fp->xlock : &_xftab[IOPIND(fp)]._lock 81*a5f69788Scraigm #define FPSTATE(fp) x##fp ? \ 82*a5f69788Scraigm &x##fp->xstate : &_xftab[IOPIND(fp)]._state 837c478bd9Sstevel@tonic-gate 847c478bd9Sstevel@tonic-gate /* The extended 32-bit file structure for use in link buffers */ 857c478bd9Sstevel@tonic-gate typedef struct xFILE { 867c478bd9Sstevel@tonic-gate FILE _iob; /* must be first! */ 877c478bd9Sstevel@tonic-gate struct xFILEdata _xdat; 887c478bd9Sstevel@tonic-gate } xFILE; 897c478bd9Sstevel@tonic-gate 907c478bd9Sstevel@tonic-gate #define xmagic _xdat._magic 917c478bd9Sstevel@tonic-gate #define xend _xdat._end 927c478bd9Sstevel@tonic-gate #define xlock _xdat._lock 937c478bd9Sstevel@tonic-gate #define xstate _xdat._state 947c478bd9Sstevel@tonic-gate 957c478bd9Sstevel@tonic-gate #define FILEx(fp) ((struct xFILE *)(uintptr_t)fp) 967c478bd9Sstevel@tonic-gate 977c478bd9Sstevel@tonic-gate /* 987c478bd9Sstevel@tonic-gate * The magic number stored is actually the pointer scrambled with 997c478bd9Sstevel@tonic-gate * a magic number. Pointers to data items live everywhere in memory 1007c478bd9Sstevel@tonic-gate * so we scramble the pointer in order to avoid accidental collisions. 1017c478bd9Sstevel@tonic-gate */ 1027c478bd9Sstevel@tonic-gate #define XFILEMAGIC 0x63687367 1037c478bd9Sstevel@tonic-gate #define XMAGIC(xfp) ((uintptr_t)(xfp) ^ XFILEMAGIC) 1047c478bd9Sstevel@tonic-gate 1057c478bd9Sstevel@tonic-gate #endif /* _LP64 */ 1067c478bd9Sstevel@tonic-gate 1077c478bd9Sstevel@tonic-gate struct _link_ /* manages a list of streams */ 1087c478bd9Sstevel@tonic-gate { 1097c478bd9Sstevel@tonic-gate xFILE *iobp; /* the array of (x)FILE's */ 1107c478bd9Sstevel@tonic-gate /* NULL for the __first_link in ILP32 */ 1117c478bd9Sstevel@tonic-gate int niob; /* length of the arrays */ 1127c478bd9Sstevel@tonic-gate struct _link_ *next; /* next in the list */ 1137c478bd9Sstevel@tonic-gate }; 1147c478bd9Sstevel@tonic-gate 1157c478bd9Sstevel@tonic-gate /* 1167c478bd9Sstevel@tonic-gate * With dynamic linking, iob may be in either the library or in the user's 1177c478bd9Sstevel@tonic-gate * a.out, so the run time linker fixes up the first entry in __first_link at 1187c478bd9Sstevel@tonic-gate * process startup time. 1197c478bd9Sstevel@tonic-gate * 1207c478bd9Sstevel@tonic-gate * In 32 bit processes, we don't have xFILE[FILE_ARY_SZ] but FILE[], 1217c478bd9Sstevel@tonic-gate * and _xftab[] instead; this is denoted by having iobp set to NULL in 1227c478bd9Sstevel@tonic-gate * 32 bit mode for the first link entry. 1237c478bd9Sstevel@tonic-gate */ 1247c478bd9Sstevel@tonic-gate struct _link_ __first_link = /* first in linked list */ 1257c478bd9Sstevel@tonic-gate { 1267c478bd9Sstevel@tonic-gate #if !defined(_LP64) 1277c478bd9Sstevel@tonic-gate NULL, 1287c478bd9Sstevel@tonic-gate #else 1297c478bd9Sstevel@tonic-gate &_iob[0], 1307c478bd9Sstevel@tonic-gate #endif 1317c478bd9Sstevel@tonic-gate _NFILE, 1327c478bd9Sstevel@tonic-gate NULL 1337c478bd9Sstevel@tonic-gate }; 1347c478bd9Sstevel@tonic-gate 1357c478bd9Sstevel@tonic-gate /* 1367c478bd9Sstevel@tonic-gate * Information cached to speed up searches. We remember where we 1377c478bd9Sstevel@tonic-gate * last found a free FILE* and we remember whether we saw any fcloses 1387c478bd9Sstevel@tonic-gate * in between. We also count the number of chunks we allocated, see 1397c478bd9Sstevel@tonic-gate * _findiop() for an explanation. 1407c478bd9Sstevel@tonic-gate * These variables are all protected by _first_link_lock. 1417c478bd9Sstevel@tonic-gate */ 1427c478bd9Sstevel@tonic-gate static struct _link_ *lastlink = NULL; 1437c478bd9Sstevel@tonic-gate static int fcloses; 1447c478bd9Sstevel@tonic-gate static int nchunks; 1457c478bd9Sstevel@tonic-gate 146*a5f69788Scraigm static mutex_t _first_link_lock = DEFAULTMUTEX; 1477c478bd9Sstevel@tonic-gate 148*a5f69788Scraigm static int _fflush_l_iops(void); 1497c478bd9Sstevel@tonic-gate static FILE *getiop(FILE *, rmutex_t *, mbstate_t *); 1507c478bd9Sstevel@tonic-gate 1517c478bd9Sstevel@tonic-gate /* 1527c478bd9Sstevel@tonic-gate * All functions that understand the linked list of iob's follow. 1537c478bd9Sstevel@tonic-gate */ 1547c478bd9Sstevel@tonic-gate #pragma weak _cleanup = __cleanup 1557c478bd9Sstevel@tonic-gate void 1567c478bd9Sstevel@tonic-gate __cleanup(void) /* called at process end to flush ouput streams */ 1577c478bd9Sstevel@tonic-gate { 1587c478bd9Sstevel@tonic-gate (void) fflush(NULL); 1597c478bd9Sstevel@tonic-gate } 1607c478bd9Sstevel@tonic-gate 1617c478bd9Sstevel@tonic-gate /* 1627c478bd9Sstevel@tonic-gate * For fork1-safety (see libc_prepare_atfork(), etc). 1637c478bd9Sstevel@tonic-gate */ 1647c478bd9Sstevel@tonic-gate void 1657c478bd9Sstevel@tonic-gate stdio_locks() 1667c478bd9Sstevel@tonic-gate { 167*a5f69788Scraigm (void) __mutex_lock(&_first_link_lock); 1687c478bd9Sstevel@tonic-gate /* 1697c478bd9Sstevel@tonic-gate * XXX: We should acquire all of the iob locks here. 1707c478bd9Sstevel@tonic-gate */ 1717c478bd9Sstevel@tonic-gate } 1727c478bd9Sstevel@tonic-gate 1737c478bd9Sstevel@tonic-gate void 1747c478bd9Sstevel@tonic-gate stdio_unlocks() 1757c478bd9Sstevel@tonic-gate { 1767c478bd9Sstevel@tonic-gate /* 1777c478bd9Sstevel@tonic-gate * XXX: We should release all of the iob locks here. 1787c478bd9Sstevel@tonic-gate */ 179*a5f69788Scraigm (void) __mutex_unlock(&_first_link_lock); 1807c478bd9Sstevel@tonic-gate } 1817c478bd9Sstevel@tonic-gate 1827c478bd9Sstevel@tonic-gate void 1837c478bd9Sstevel@tonic-gate _flushlbf(void) /* fflush() all line-buffered streams */ 1847c478bd9Sstevel@tonic-gate { 1857c478bd9Sstevel@tonic-gate FPDECL(fp); 1867c478bd9Sstevel@tonic-gate int i; 1877c478bd9Sstevel@tonic-gate struct _link_ *lp; 188*a5f69788Scraigm /* Allow compiler to optimize the loop */ 189*a5f69788Scraigm int threaded = __libc_threaded; 1907c478bd9Sstevel@tonic-gate 191*a5f69788Scraigm if (threaded) 192*a5f69788Scraigm (void) __mutex_lock(&_first_link_lock); 1937c478bd9Sstevel@tonic-gate 1947c478bd9Sstevel@tonic-gate lp = &__first_link; 1957c478bd9Sstevel@tonic-gate do { 1967c478bd9Sstevel@tonic-gate FIRSTFP(lp, fp); 1977c478bd9Sstevel@tonic-gate for (i = lp->niob; --i >= 0; NEXTFP(fp)) { 198*a5f69788Scraigm /* 199*a5f69788Scraigm * The additional _IONBF check guards againsts 200*a5f69788Scraigm * allocated but uninitialized iops (see _findiop). 201*a5f69788Scraigm * We also automatically skip non allocated iop's. 202*a5f69788Scraigm * Don't block on locks. 203*a5f69788Scraigm */ 204*a5f69788Scraigm if ((fp->_flag & (_IOLBF | _IOWRT | _IONBF)) == 205*a5f69788Scraigm (_IOLBF | _IOWRT)) { 206*a5f69788Scraigm if (threaded) { 207*a5f69788Scraigm rmutex_t *lk = FPLOCK(fp); 208*a5f69788Scraigm if (rmutex_trylock(lk) != 0) 209*a5f69788Scraigm continue; 210*a5f69788Scraigm /* Recheck after locking */ 211*a5f69788Scraigm if ((fp->_flag & (_IOLBF | _IOWRT)) == 212*a5f69788Scraigm (_IOLBF | _IOWRT)) { 213*a5f69788Scraigm (void) _fflush_u(fp); 214*a5f69788Scraigm } 215*a5f69788Scraigm (void) rmutex_unlock(lk); 216*a5f69788Scraigm } else { 217*a5f69788Scraigm (void) _fflush_u(fp); 218*a5f69788Scraigm } 219*a5f69788Scraigm } 2207c478bd9Sstevel@tonic-gate } 2217c478bd9Sstevel@tonic-gate } while ((lp = lp->next) != NULL); 2227c478bd9Sstevel@tonic-gate 223*a5f69788Scraigm if (threaded) 224*a5f69788Scraigm (void) __mutex_unlock(&_first_link_lock); 2257c478bd9Sstevel@tonic-gate } 2267c478bd9Sstevel@tonic-gate 2277c478bd9Sstevel@tonic-gate /* allocate an unused stream; NULL if cannot */ 2287c478bd9Sstevel@tonic-gate FILE * 2297c478bd9Sstevel@tonic-gate _findiop(void) 2307c478bd9Sstevel@tonic-gate { 2317c478bd9Sstevel@tonic-gate struct _link_ *lp, **prev; 2327c478bd9Sstevel@tonic-gate 2337c478bd9Sstevel@tonic-gate /* used so there only needs to be one malloc() */ 2347c478bd9Sstevel@tonic-gate #ifdef _LP64 2357c478bd9Sstevel@tonic-gate typedef struct { 2367c478bd9Sstevel@tonic-gate struct _link_ hdr; 2377c478bd9Sstevel@tonic-gate FILE iob[FILE_ARY_SZ]; 2387c478bd9Sstevel@tonic-gate } Pkg; 2397c478bd9Sstevel@tonic-gate #else 2407c478bd9Sstevel@tonic-gate typedef union { 2417c478bd9Sstevel@tonic-gate struct { /* Normal */ 2427c478bd9Sstevel@tonic-gate struct _link_ hdr; 2437c478bd9Sstevel@tonic-gate xFILE iob[FILE_ARY_SZ]; 2447c478bd9Sstevel@tonic-gate } Pkgn; 2457c478bd9Sstevel@tonic-gate struct { /* Reversed */ 2467c478bd9Sstevel@tonic-gate xFILE iob[FILE_ARY_SZ]; 2477c478bd9Sstevel@tonic-gate struct _link_ hdr; 2487c478bd9Sstevel@tonic-gate } Pkgr; 2497c478bd9Sstevel@tonic-gate } Pkg; 2507c478bd9Sstevel@tonic-gate uintptr_t delta; 2517c478bd9Sstevel@tonic-gate #endif 2527c478bd9Sstevel@tonic-gate Pkg *pkgp; 2537c478bd9Sstevel@tonic-gate struct _link_ *hdr; 2547c478bd9Sstevel@tonic-gate FPDECL(fp); 2557c478bd9Sstevel@tonic-gate int i; 256*a5f69788Scraigm int threaded = __libc_threaded; 2577c478bd9Sstevel@tonic-gate 258*a5f69788Scraigm if (threaded) 259*a5f69788Scraigm (void) __mutex_lock(&_first_link_lock); 2607c478bd9Sstevel@tonic-gate 2617c478bd9Sstevel@tonic-gate if (lastlink == NULL) { 2627c478bd9Sstevel@tonic-gate rescan: 2637c478bd9Sstevel@tonic-gate fcloses = 0; 2647c478bd9Sstevel@tonic-gate lastlink = &__first_link; 2657c478bd9Sstevel@tonic-gate } 2667c478bd9Sstevel@tonic-gate 2677c478bd9Sstevel@tonic-gate lp = lastlink; 2687c478bd9Sstevel@tonic-gate 2697c478bd9Sstevel@tonic-gate /* 2707c478bd9Sstevel@tonic-gate * lock to make testing of fp->_flag == 0 and acquiring the fp atomic 2717c478bd9Sstevel@tonic-gate * and for allocation of new links 2727c478bd9Sstevel@tonic-gate * low contention expected on _findiop(), hence coarse locking. 2737c478bd9Sstevel@tonic-gate * for finer granularity, use fp->_lock for allocating an iop 2747c478bd9Sstevel@tonic-gate * and make the testing of lp->next and allocation of new link atomic 2757c478bd9Sstevel@tonic-gate * using lp->_lock 2767c478bd9Sstevel@tonic-gate */ 2777c478bd9Sstevel@tonic-gate 2787c478bd9Sstevel@tonic-gate do { 2797c478bd9Sstevel@tonic-gate prev = &lp->next; 2807c478bd9Sstevel@tonic-gate FIRSTFP(lp, fp); 2817c478bd9Sstevel@tonic-gate 2827c478bd9Sstevel@tonic-gate for (i = lp->niob; --i >= 0; NEXTFP(fp)) { 283*a5f69788Scraigm FILE *ret; 284*a5f69788Scraigm if (threaded) { 285*a5f69788Scraigm ret = getiop(fp, FPLOCK(fp), FPSTATE(fp)); 286*a5f69788Scraigm if (ret != NULL) { 287*a5f69788Scraigm (void) __mutex_unlock(&_first_link_lock); 288*a5f69788Scraigm return (ret); 289*a5f69788Scraigm } 290*a5f69788Scraigm } else { 291*a5f69788Scraigm ret = getiop(fp, NULL, FPSTATE(fp)); 292*a5f69788Scraigm if (ret != NULL) 293*a5f69788Scraigm return (ret); 294*a5f69788Scraigm } 2957c478bd9Sstevel@tonic-gate } 2967c478bd9Sstevel@tonic-gate } while ((lastlink = lp = lp->next) != NULL); 2977c478bd9Sstevel@tonic-gate 2987c478bd9Sstevel@tonic-gate /* 2997c478bd9Sstevel@tonic-gate * If there was a sufficient number of fcloses since we last started 3007c478bd9Sstevel@tonic-gate * at __first_link, we rescan all fp's again. We do not rescan for 3017c478bd9Sstevel@tonic-gate * all fcloses; that would simplify the algorithm but would make 3027c478bd9Sstevel@tonic-gate * search times near O(n) again. 3037c478bd9Sstevel@tonic-gate * Worst case behaviour would still be pretty bad (open a full set, 3047c478bd9Sstevel@tonic-gate * then continously opening and closing one FILE * gets you a full 3057c478bd9Sstevel@tonic-gate * scan each time). That's why we over allocate 1 FILE for each 3067c478bd9Sstevel@tonic-gate * 32 chunks. More over allocation is better; this is a nice 3077c478bd9Sstevel@tonic-gate * empirical value which doesn't cost a lot of memory, doesn't 3087c478bd9Sstevel@tonic-gate * overallocate until we reach 256 FILE *s and keeps the performance 3097c478bd9Sstevel@tonic-gate * pretty close to the optimum. 3107c478bd9Sstevel@tonic-gate */ 3117c478bd9Sstevel@tonic-gate if (fcloses > nchunks/32) 3127c478bd9Sstevel@tonic-gate goto rescan; 3137c478bd9Sstevel@tonic-gate 3147c478bd9Sstevel@tonic-gate /* 3157c478bd9Sstevel@tonic-gate * Need to allocate another and put it in the linked list. 3167c478bd9Sstevel@tonic-gate */ 3177c478bd9Sstevel@tonic-gate if ((pkgp = malloc(sizeof (Pkg))) == NULL) { 318*a5f69788Scraigm if (threaded) 319*a5f69788Scraigm (void) __mutex_unlock(&_first_link_lock); 3207c478bd9Sstevel@tonic-gate return (NULL); 3217c478bd9Sstevel@tonic-gate } 3227c478bd9Sstevel@tonic-gate 3237c478bd9Sstevel@tonic-gate (void) memset(pkgp, 0, sizeof (Pkg)); 3247c478bd9Sstevel@tonic-gate 3257c478bd9Sstevel@tonic-gate #ifdef _LP64 3267c478bd9Sstevel@tonic-gate hdr = &pkgp->hdr; 3277c478bd9Sstevel@tonic-gate hdr->iobp = &pkgp->iob[0]; 3287c478bd9Sstevel@tonic-gate #else 3297c478bd9Sstevel@tonic-gate /* 3307c478bd9Sstevel@tonic-gate * The problem with referencing a word after a FILE* is the possibility 3317c478bd9Sstevel@tonic-gate * of a SIGSEGV if a non-stdio issue FILE structure ends on a page 3327c478bd9Sstevel@tonic-gate * boundary. We run this check so we never need to run an expensive 3337c478bd9Sstevel@tonic-gate * check like mincore() in order to know whether it is 3347c478bd9Sstevel@tonic-gate * safe to dereference ((xFILE*)fp)->xmagic. 3357c478bd9Sstevel@tonic-gate * We allocate the block with two alternative layouts; if one 3367c478bd9Sstevel@tonic-gate * layout is not properly aligned for our purposes, the other layout 3377c478bd9Sstevel@tonic-gate * will be because the size of _link_ is small compared to 3387c478bd9Sstevel@tonic-gate * sizeof (xFILE). 3397c478bd9Sstevel@tonic-gate * The check performed is this: 3407c478bd9Sstevel@tonic-gate * If the distance from pkgp to the end of the page is 3417c478bd9Sstevel@tonic-gate * less than the the offset of the last xmagic field in the 3427c478bd9Sstevel@tonic-gate * xFILE structure, (the 0x1000 boundary is inside our just 3437c478bd9Sstevel@tonic-gate * allocated structure) and the distance modulo the size of xFILE 3447c478bd9Sstevel@tonic-gate * is identical to the offset of the first xmagic in the 3457c478bd9Sstevel@tonic-gate * structure (i.e., XXXXXX000 points to an xmagic field), 3467c478bd9Sstevel@tonic-gate * we need to use the reverse structure. 3477c478bd9Sstevel@tonic-gate */ 3487c478bd9Sstevel@tonic-gate if ((delta = 0x1000 - ((uintptr_t)pkgp & 0xfff)) <= 3497c478bd9Sstevel@tonic-gate offsetof(Pkg, Pkgn.iob[FILE_ARY_SZ-1].xmagic) && 3507c478bd9Sstevel@tonic-gate delta % sizeof (struct xFILE) == 3517c478bd9Sstevel@tonic-gate offsetof(Pkg, Pkgn.iob[0].xmagic)) { 3527c478bd9Sstevel@tonic-gate /* Use reversed structure */ 3537c478bd9Sstevel@tonic-gate hdr = &pkgp->Pkgr.hdr; 3547c478bd9Sstevel@tonic-gate hdr->iobp = &pkgp->Pkgr.iob[0]; 3557c478bd9Sstevel@tonic-gate } else { 3567c478bd9Sstevel@tonic-gate /* Use normal structure */ 3577c478bd9Sstevel@tonic-gate hdr = &pkgp->Pkgn.hdr; 3587c478bd9Sstevel@tonic-gate hdr->iobp = &pkgp->Pkgn.iob[0]; 3597c478bd9Sstevel@tonic-gate } 3607c478bd9Sstevel@tonic-gate #endif /* _LP64 */ 3617c478bd9Sstevel@tonic-gate 3627c478bd9Sstevel@tonic-gate hdr->niob = FILE_ARY_SZ; 3637c478bd9Sstevel@tonic-gate nchunks++; 3647c478bd9Sstevel@tonic-gate 3657c478bd9Sstevel@tonic-gate #ifdef _LP64 3667c478bd9Sstevel@tonic-gate fp = hdr->iobp; 3677c478bd9Sstevel@tonic-gate for (i = 0; i < FILE_ARY_SZ; i++) 3687c478bd9Sstevel@tonic-gate _private_mutex_init(&fp[i]._lock, 3697c478bd9Sstevel@tonic-gate USYNC_THREAD|LOCK_RECURSIVE, NULL); 3707c478bd9Sstevel@tonic-gate #else 3717c478bd9Sstevel@tonic-gate xfp = hdr->iobp; 3727c478bd9Sstevel@tonic-gate fp = &xfp->_iob; 3737c478bd9Sstevel@tonic-gate 3747c478bd9Sstevel@tonic-gate for (i = 0; i < FILE_ARY_SZ; i++) { 3757c478bd9Sstevel@tonic-gate xfp[i].xmagic = XMAGIC(&xfp[i]); 3767c478bd9Sstevel@tonic-gate _private_mutex_init(&xfp[i].xlock, 3777c478bd9Sstevel@tonic-gate USYNC_THREAD|LOCK_RECURSIVE, NULL); 3787c478bd9Sstevel@tonic-gate } 3797c478bd9Sstevel@tonic-gate #endif /* _LP64 */ 3807c478bd9Sstevel@tonic-gate 3817c478bd9Sstevel@tonic-gate lastlink = *prev = hdr; 3827c478bd9Sstevel@tonic-gate fp->_ptr = 0; 3837c478bd9Sstevel@tonic-gate fp->_base = 0; 3847c478bd9Sstevel@tonic-gate fp->_flag = 0377; /* claim the fp by setting low 8 bits */ 385*a5f69788Scraigm if (threaded) 386*a5f69788Scraigm (void) __mutex_unlock(&_first_link_lock); 3877c478bd9Sstevel@tonic-gate 3887c478bd9Sstevel@tonic-gate return (fp); 3897c478bd9Sstevel@tonic-gate } 3907c478bd9Sstevel@tonic-gate 3917c478bd9Sstevel@tonic-gate static void 3927c478bd9Sstevel@tonic-gate isseekable(FILE *iop) 3937c478bd9Sstevel@tonic-gate { 3947c478bd9Sstevel@tonic-gate struct stat64 fstatbuf; 3957c478bd9Sstevel@tonic-gate int save_errno; 3967c478bd9Sstevel@tonic-gate 3977c478bd9Sstevel@tonic-gate save_errno = errno; 3987c478bd9Sstevel@tonic-gate 399*a5f69788Scraigm if (fstat64(GET_FD(iop), &fstatbuf) != 0) { 4007c478bd9Sstevel@tonic-gate /* 4017c478bd9Sstevel@tonic-gate * when we don't know what it is we'll 4027c478bd9Sstevel@tonic-gate * do the old behaviour and flush 4037c478bd9Sstevel@tonic-gate * the stream 4047c478bd9Sstevel@tonic-gate */ 4057c478bd9Sstevel@tonic-gate SET_SEEKABLE(iop); 4067c478bd9Sstevel@tonic-gate errno = save_errno; 4077c478bd9Sstevel@tonic-gate return; 4087c478bd9Sstevel@tonic-gate } 4097c478bd9Sstevel@tonic-gate 4107c478bd9Sstevel@tonic-gate /* 4117c478bd9Sstevel@tonic-gate * check for what is non-SEEKABLE 4127c478bd9Sstevel@tonic-gate * otherwise assume it's SEEKABLE so we get the old 4137c478bd9Sstevel@tonic-gate * behaviour and flush the stream 4147c478bd9Sstevel@tonic-gate */ 4157c478bd9Sstevel@tonic-gate 4167c478bd9Sstevel@tonic-gate if (S_ISFIFO(fstatbuf.st_mode) || S_ISCHR(fstatbuf.st_mode) || 4177c478bd9Sstevel@tonic-gate S_ISSOCK(fstatbuf.st_mode) || S_ISDOOR(fstatbuf.st_mode)) { 4187c478bd9Sstevel@tonic-gate CLEAR_SEEKABLE(iop); 4197c478bd9Sstevel@tonic-gate } else { 4207c478bd9Sstevel@tonic-gate SET_SEEKABLE(iop); 4217c478bd9Sstevel@tonic-gate } 4227c478bd9Sstevel@tonic-gate 4237c478bd9Sstevel@tonic-gate errno = save_errno; 4247c478bd9Sstevel@tonic-gate } 4257c478bd9Sstevel@tonic-gate 4267c478bd9Sstevel@tonic-gate #ifdef _LP64 4277c478bd9Sstevel@tonic-gate void 4287c478bd9Sstevel@tonic-gate _setbufend(FILE *iop, Uchar *end) /* set the end pointer for this iop */ 4297c478bd9Sstevel@tonic-gate { 4307c478bd9Sstevel@tonic-gate iop->_end = end; 4317c478bd9Sstevel@tonic-gate 4327c478bd9Sstevel@tonic-gate isseekable(iop); 4337c478bd9Sstevel@tonic-gate } 4347c478bd9Sstevel@tonic-gate 4357c478bd9Sstevel@tonic-gate #undef _realbufend 4367c478bd9Sstevel@tonic-gate 4377c478bd9Sstevel@tonic-gate Uchar * 4387c478bd9Sstevel@tonic-gate _realbufend(FILE *iop) /* get the end pointer for this iop */ 4397c478bd9Sstevel@tonic-gate { 4407c478bd9Sstevel@tonic-gate return (iop->_end); 4417c478bd9Sstevel@tonic-gate } 4427c478bd9Sstevel@tonic-gate 4437c478bd9Sstevel@tonic-gate #else /* _LP64 */ 4447c478bd9Sstevel@tonic-gate 4457c478bd9Sstevel@tonic-gate /* 4467c478bd9Sstevel@tonic-gate * Awkward functions not needed for the sane 64 bit environment. 4477c478bd9Sstevel@tonic-gate */ 4487c478bd9Sstevel@tonic-gate /* 4497c478bd9Sstevel@tonic-gate * xmagic must not be aligned on a 4K boundary. We guarantee this in 4507c478bd9Sstevel@tonic-gate * _findiop(). 4517c478bd9Sstevel@tonic-gate */ 4527c478bd9Sstevel@tonic-gate #define VALIDXFILE(xfp) \ 4537c478bd9Sstevel@tonic-gate (((uintptr_t)&(xfp)->xmagic & 0xfff) && \ 4547c478bd9Sstevel@tonic-gate (xfp)->xmagic == XMAGIC(FILEx(xfp))) 4557c478bd9Sstevel@tonic-gate 4567c478bd9Sstevel@tonic-gate static struct xFILEdata * 4577c478bd9Sstevel@tonic-gate getxfdat(FILE *iop) 4587c478bd9Sstevel@tonic-gate { 4597c478bd9Sstevel@tonic-gate if (STDIOP(iop)) 4607c478bd9Sstevel@tonic-gate return (&_xftab[IOPIND(iop)]); 4617c478bd9Sstevel@tonic-gate else if (VALIDXFILE(FILEx(iop))) 4627c478bd9Sstevel@tonic-gate return (&FILEx(iop)->_xdat); 4637c478bd9Sstevel@tonic-gate else 4647c478bd9Sstevel@tonic-gate return (NULL); 4657c478bd9Sstevel@tonic-gate } 4667c478bd9Sstevel@tonic-gate 4677c478bd9Sstevel@tonic-gate void 4687c478bd9Sstevel@tonic-gate _setbufend(FILE *iop, Uchar *end) /* set the end pointer for this iop */ 4697c478bd9Sstevel@tonic-gate { 4707c478bd9Sstevel@tonic-gate struct xFILEdata *dat = getxfdat(iop); 4717c478bd9Sstevel@tonic-gate 4727c478bd9Sstevel@tonic-gate if (dat != NULL) 4737c478bd9Sstevel@tonic-gate dat->_end = end; 4747c478bd9Sstevel@tonic-gate 4757c478bd9Sstevel@tonic-gate isseekable(iop); 4767c478bd9Sstevel@tonic-gate 4777c478bd9Sstevel@tonic-gate /* 4787c478bd9Sstevel@tonic-gate * For binary compatibility with user programs using the 4797c478bd9Sstevel@tonic-gate * old _bufend macro. This is *so* broken, fileno() 4807c478bd9Sstevel@tonic-gate * is not the proper index. 4817c478bd9Sstevel@tonic-gate */ 482*a5f69788Scraigm if (iop->_magic < _NFILE) 483*a5f69788Scraigm _bufendtab[iop->_magic] = end; 4847c478bd9Sstevel@tonic-gate 4857c478bd9Sstevel@tonic-gate } 4867c478bd9Sstevel@tonic-gate 4877c478bd9Sstevel@tonic-gate Uchar * 4887c478bd9Sstevel@tonic-gate _realbufend(FILE *iop) /* get the end pointer for this iop */ 4897c478bd9Sstevel@tonic-gate { 4907c478bd9Sstevel@tonic-gate struct xFILEdata *dat = getxfdat(iop); 4917c478bd9Sstevel@tonic-gate 4927c478bd9Sstevel@tonic-gate if (dat != NULL) 4937c478bd9Sstevel@tonic-gate return (dat->_end); 4947c478bd9Sstevel@tonic-gate 4957c478bd9Sstevel@tonic-gate return (NULL); 4967c478bd9Sstevel@tonic-gate } 4977c478bd9Sstevel@tonic-gate 4987c478bd9Sstevel@tonic-gate /* 4997c478bd9Sstevel@tonic-gate * _reallock() is invoked in each stdio call through the IOB_LCK() macro, 5007c478bd9Sstevel@tonic-gate * it is therefor extremely performance sensitive. We get better performance 5017c478bd9Sstevel@tonic-gate * by inlining the STDIOP check in IOB_LCK and inlining a custom version 5027c478bd9Sstevel@tonic-gate * of getfxdat() here. 5037c478bd9Sstevel@tonic-gate */ 5047c478bd9Sstevel@tonic-gate rmutex_t * 5057c478bd9Sstevel@tonic-gate _reallock(FILE *iop) 5067c478bd9Sstevel@tonic-gate { 5077c478bd9Sstevel@tonic-gate if (VALIDXFILE(FILEx(iop))) 5087c478bd9Sstevel@tonic-gate return (&FILEx(iop)->xlock); 5097c478bd9Sstevel@tonic-gate 5107c478bd9Sstevel@tonic-gate return (NULL); 5117c478bd9Sstevel@tonic-gate } 5127c478bd9Sstevel@tonic-gate 5137c478bd9Sstevel@tonic-gate #endif /* _LP64 */ 5147c478bd9Sstevel@tonic-gate 5157c478bd9Sstevel@tonic-gate /* make sure _cnt, _ptr are correct */ 5167c478bd9Sstevel@tonic-gate void 5177c478bd9Sstevel@tonic-gate _bufsync(FILE *iop, Uchar *bufend) 5187c478bd9Sstevel@tonic-gate { 5197c478bd9Sstevel@tonic-gate ssize_t spaceleft; 5207c478bd9Sstevel@tonic-gate 5217c478bd9Sstevel@tonic-gate spaceleft = bufend - iop->_ptr; 5227c478bd9Sstevel@tonic-gate if (bufend < iop->_ptr) { 5237c478bd9Sstevel@tonic-gate iop->_ptr = bufend; 5247c478bd9Sstevel@tonic-gate iop->_cnt = 0; 5257c478bd9Sstevel@tonic-gate } else if (spaceleft < iop->_cnt) 5267c478bd9Sstevel@tonic-gate iop->_cnt = spaceleft; 5277c478bd9Sstevel@tonic-gate } 5287c478bd9Sstevel@tonic-gate 5297c478bd9Sstevel@tonic-gate /* really write out current buffer contents */ 5307c478bd9Sstevel@tonic-gate int 5317c478bd9Sstevel@tonic-gate _xflsbuf(FILE *iop) 5327c478bd9Sstevel@tonic-gate { 5337c478bd9Sstevel@tonic-gate ssize_t n; 5347c478bd9Sstevel@tonic-gate Uchar *base = iop->_base; 5357c478bd9Sstevel@tonic-gate Uchar *bufend; 5367c478bd9Sstevel@tonic-gate ssize_t num_wrote; 5377c478bd9Sstevel@tonic-gate 5387c478bd9Sstevel@tonic-gate /* 5397c478bd9Sstevel@tonic-gate * Hopefully, be stable with respect to interrupts... 5407c478bd9Sstevel@tonic-gate */ 5417c478bd9Sstevel@tonic-gate n = iop->_ptr - base; 5427c478bd9Sstevel@tonic-gate iop->_ptr = base; 5437c478bd9Sstevel@tonic-gate bufend = _bufend(iop); 5447c478bd9Sstevel@tonic-gate if (iop->_flag & (_IOLBF | _IONBF)) 5457c478bd9Sstevel@tonic-gate iop->_cnt = 0; /* always go to a flush */ 5467c478bd9Sstevel@tonic-gate else 5477c478bd9Sstevel@tonic-gate iop->_cnt = bufend - base; 5487c478bd9Sstevel@tonic-gate 5497c478bd9Sstevel@tonic-gate if (_needsync(iop, bufend)) /* recover from interrupts */ 5507c478bd9Sstevel@tonic-gate _bufsync(iop, bufend); 5517c478bd9Sstevel@tonic-gate 5527c478bd9Sstevel@tonic-gate if (n > 0) { 553*a5f69788Scraigm int fd = GET_FD(iop); 5547c478bd9Sstevel@tonic-gate while ((num_wrote = 555*a5f69788Scraigm write(fd, base, (size_t)n)) != n) { 5567c478bd9Sstevel@tonic-gate if (num_wrote <= 0) { 5577c478bd9Sstevel@tonic-gate iop->_flag |= _IOERR; 5587c478bd9Sstevel@tonic-gate return (EOF); 5597c478bd9Sstevel@tonic-gate } 5607c478bd9Sstevel@tonic-gate n -= num_wrote; 5617c478bd9Sstevel@tonic-gate base += num_wrote; 5627c478bd9Sstevel@tonic-gate } 5637c478bd9Sstevel@tonic-gate } 5647c478bd9Sstevel@tonic-gate return (0); 5657c478bd9Sstevel@tonic-gate } 5667c478bd9Sstevel@tonic-gate 5677c478bd9Sstevel@tonic-gate /* flush (write) buffer */ 5687c478bd9Sstevel@tonic-gate int 5697c478bd9Sstevel@tonic-gate fflush(FILE *iop) 5707c478bd9Sstevel@tonic-gate { 5717c478bd9Sstevel@tonic-gate int res; 5727c478bd9Sstevel@tonic-gate rmutex_t *lk; 5737c478bd9Sstevel@tonic-gate 5747c478bd9Sstevel@tonic-gate if (iop) { 5757c478bd9Sstevel@tonic-gate FLOCKFILE(lk, iop); 5767c478bd9Sstevel@tonic-gate res = _fflush_u(iop); 5777c478bd9Sstevel@tonic-gate FUNLOCKFILE(lk); 5787c478bd9Sstevel@tonic-gate } else { 579*a5f69788Scraigm res = _fflush_l_iops(); /* flush all iops */ 5807c478bd9Sstevel@tonic-gate } 5817c478bd9Sstevel@tonic-gate return (res); 5827c478bd9Sstevel@tonic-gate } 5837c478bd9Sstevel@tonic-gate 5847c478bd9Sstevel@tonic-gate static int 585*a5f69788Scraigm _fflush_l_iops(void) /* flush all buffers */ 5867c478bd9Sstevel@tonic-gate { 5877c478bd9Sstevel@tonic-gate FPDECL(iop); 5887c478bd9Sstevel@tonic-gate 5897c478bd9Sstevel@tonic-gate int i; 5907c478bd9Sstevel@tonic-gate struct _link_ *lp; 5917c478bd9Sstevel@tonic-gate int res = 0; 592*a5f69788Scraigm rmutex_t *lk; 593*a5f69788Scraigm /* Allow the compiler to optimize the load out of the loop */ 594*a5f69788Scraigm int threaded = __libc_threaded; 5957c478bd9Sstevel@tonic-gate 596*a5f69788Scraigm if (threaded) 597*a5f69788Scraigm (void) __mutex_lock(&_first_link_lock); 5987c478bd9Sstevel@tonic-gate 5997c478bd9Sstevel@tonic-gate lp = &__first_link; 6007c478bd9Sstevel@tonic-gate 6017c478bd9Sstevel@tonic-gate do { 6027c478bd9Sstevel@tonic-gate /* 603*a5f69788Scraigm * We need to grab the file locks or file corruption 604*a5f69788Scraigm * will happen. But we first check the flags field 605*a5f69788Scraigm * knowing that when it is 0, it isn't allocated and 606*a5f69788Scraigm * cannot be allocated while we're holding the 607*a5f69788Scraigm * _first_link_lock. And when _IONBF is set (also the 608*a5f69788Scraigm * case when _flag is 0377, or alloc in progress), we 609*a5f69788Scraigm * also ignore it. 610*a5f69788Scraigm * 611*a5f69788Scraigm * Ignore locked streams; it will appear as if 612*a5f69788Scraigm * concurrent updates happened after fflush(NULL). Note 613*a5f69788Scraigm * that we even attempt to lock if the locking is set to 614*a5f69788Scraigm * "by caller". We don't want to penalize callers of 615*a5f69788Scraigm * __fsetlocking() by not flushing their files. Note: if 616*a5f69788Scraigm * __fsetlocking() callers don't employ any locking, they 617*a5f69788Scraigm * may still face corruption in fflush(NULL); but that's 618*a5f69788Scraigm * no change from earlier releases. 6197c478bd9Sstevel@tonic-gate */ 6207c478bd9Sstevel@tonic-gate FIRSTFP(lp, iop); 6217c478bd9Sstevel@tonic-gate for (i = lp->niob; --i >= 0; NEXTFP(iop)) { 622*a5f69788Scraigm unsigned int flag = iop->_flag; 623*a5f69788Scraigm 624*a5f69788Scraigm /* flag 0, flag 0377, or _IONBF set */ 625*a5f69788Scraigm if (flag == 0 || (flag & _IONBF) != 0) 626*a5f69788Scraigm continue; 627*a5f69788Scraigm 628*a5f69788Scraigm if (threaded) { 629*a5f69788Scraigm lk = FPLOCK(iop); 630*a5f69788Scraigm if (rmutex_trylock(lk) != 0) 631*a5f69788Scraigm continue; 632*a5f69788Scraigm } 633*a5f69788Scraigm 634*a5f69788Scraigm if (!(iop->_flag & _IONBF)) { 6357c478bd9Sstevel@tonic-gate /* 636*a5f69788Scraigm * don't need to worry about the _IORW case 637*a5f69788Scraigm * since the iop will also marked with _IOREAD 638*a5f69788Scraigm * or _IOWRT whichever we are really doing 6397c478bd9Sstevel@tonic-gate */ 640*a5f69788Scraigm if (iop->_flag & _IOWRT) { 641*a5f69788Scraigm /* Flush write buffers */ 642*a5f69788Scraigm res |= _fflush_u(iop); 643*a5f69788Scraigm } else if (iop->_flag & _IOREAD) { 644*a5f69788Scraigm /* 645*a5f69788Scraigm * flush seekable read buffers 646*a5f69788Scraigm * don't flush non-seekable read buffers 647*a5f69788Scraigm */ 648*a5f69788Scraigm if (GET_SEEKABLE(iop)) { 649*a5f69788Scraigm res |= _fflush_u(iop); 650*a5f69788Scraigm } 651*a5f69788Scraigm } 6527c478bd9Sstevel@tonic-gate } 653*a5f69788Scraigm if (threaded) 654*a5f69788Scraigm (void) rmutex_unlock(lk); 6557c478bd9Sstevel@tonic-gate } 6567c478bd9Sstevel@tonic-gate } while ((lp = lp->next) != NULL); 657*a5f69788Scraigm if (threaded) 658*a5f69788Scraigm (void) __mutex_unlock(&_first_link_lock); 6597c478bd9Sstevel@tonic-gate return (res); 6607c478bd9Sstevel@tonic-gate } 6617c478bd9Sstevel@tonic-gate 6627c478bd9Sstevel@tonic-gate /* flush buffer */ 6637c478bd9Sstevel@tonic-gate int 6647c478bd9Sstevel@tonic-gate _fflush_u(FILE *iop) 6657c478bd9Sstevel@tonic-gate { 6667c478bd9Sstevel@tonic-gate int res = 0; 6677c478bd9Sstevel@tonic-gate 6687c478bd9Sstevel@tonic-gate /* this portion is always assumed locked */ 6697c478bd9Sstevel@tonic-gate if (!(iop->_flag & _IOWRT)) { 670*a5f69788Scraigm (void) lseek64(GET_FD(iop), -iop->_cnt, SEEK_CUR); 6717c478bd9Sstevel@tonic-gate iop->_cnt = 0; 6727c478bd9Sstevel@tonic-gate /* needed for ungetc & multibyte pushbacks */ 6737c478bd9Sstevel@tonic-gate iop->_ptr = iop->_base; 6747c478bd9Sstevel@tonic-gate if (iop->_flag & _IORW) { 6757c478bd9Sstevel@tonic-gate iop->_flag &= ~_IOREAD; 6767c478bd9Sstevel@tonic-gate } 6777c478bd9Sstevel@tonic-gate return (0); 6787c478bd9Sstevel@tonic-gate } 6797c478bd9Sstevel@tonic-gate if (iop->_base != NULL && iop->_ptr > iop->_base) { 6807c478bd9Sstevel@tonic-gate res = _xflsbuf(iop); 6817c478bd9Sstevel@tonic-gate } 6827c478bd9Sstevel@tonic-gate if (iop->_flag & _IORW) { 6837c478bd9Sstevel@tonic-gate iop->_flag &= ~_IOWRT; 6847c478bd9Sstevel@tonic-gate iop->_cnt = 0; 6857c478bd9Sstevel@tonic-gate } 6867c478bd9Sstevel@tonic-gate return (res); 6877c478bd9Sstevel@tonic-gate } 6887c478bd9Sstevel@tonic-gate 6897c478bd9Sstevel@tonic-gate /* flush buffer and close stream */ 6907c478bd9Sstevel@tonic-gate int 6917c478bd9Sstevel@tonic-gate fclose(FILE *iop) 6927c478bd9Sstevel@tonic-gate { 6937c478bd9Sstevel@tonic-gate int res = 0; 6947c478bd9Sstevel@tonic-gate rmutex_t *lk; 6957c478bd9Sstevel@tonic-gate 6967c478bd9Sstevel@tonic-gate if (iop == NULL) { 6977c478bd9Sstevel@tonic-gate return (EOF); /* avoid passing zero to FLOCKFILE */ 6987c478bd9Sstevel@tonic-gate } 6997c478bd9Sstevel@tonic-gate 7007c478bd9Sstevel@tonic-gate FLOCKFILE(lk, iop); 7017c478bd9Sstevel@tonic-gate if (iop->_flag == 0) { 7027c478bd9Sstevel@tonic-gate FUNLOCKFILE(lk); 7037c478bd9Sstevel@tonic-gate return (EOF); 7047c478bd9Sstevel@tonic-gate } 7057c478bd9Sstevel@tonic-gate /* Is not unbuffered and opened for read and/or write ? */ 7067c478bd9Sstevel@tonic-gate if (!(iop->_flag & _IONBF) && (iop->_flag & (_IOWRT | _IOREAD | _IORW))) 7077c478bd9Sstevel@tonic-gate res = _fflush_u(iop); 708*a5f69788Scraigm if (close(GET_FD(iop)) < 0) 7097c478bd9Sstevel@tonic-gate res = EOF; 7107c478bd9Sstevel@tonic-gate if (iop->_flag & _IOMYBUF) { 7117c478bd9Sstevel@tonic-gate (void) free((char *)iop->_base - PUSHBACK); 7127c478bd9Sstevel@tonic-gate } 7137c478bd9Sstevel@tonic-gate iop->_base = NULL; 7147c478bd9Sstevel@tonic-gate iop->_ptr = NULL; 7157c478bd9Sstevel@tonic-gate iop->_cnt = 0; 7167c478bd9Sstevel@tonic-gate iop->_flag = 0; /* marks it as available */ 7177c478bd9Sstevel@tonic-gate FUNLOCKFILE(lk); 7187c478bd9Sstevel@tonic-gate 7191d2738a5Sraf if (__libc_threaded) 720*a5f69788Scraigm (void) __mutex_lock(&_first_link_lock); 7217c478bd9Sstevel@tonic-gate fcloses++; 7221d2738a5Sraf if (__libc_threaded) 723*a5f69788Scraigm (void) __mutex_unlock(&_first_link_lock); 7247c478bd9Sstevel@tonic-gate 7257c478bd9Sstevel@tonic-gate return (res); 7267c478bd9Sstevel@tonic-gate } 7277c478bd9Sstevel@tonic-gate 7287c478bd9Sstevel@tonic-gate /* flush buffer, close fd but keep the stream used by freopen() */ 7297c478bd9Sstevel@tonic-gate int 7307c478bd9Sstevel@tonic-gate close_fd(FILE *iop) 7317c478bd9Sstevel@tonic-gate { 7327c478bd9Sstevel@tonic-gate int res = 0; 7337c478bd9Sstevel@tonic-gate mbstate_t *mb; 7347c478bd9Sstevel@tonic-gate 7357c478bd9Sstevel@tonic-gate if (iop == NULL || iop->_flag == 0) 7367c478bd9Sstevel@tonic-gate return (EOF); 7377c478bd9Sstevel@tonic-gate /* Is not unbuffered and opened for read and/or write ? */ 7387c478bd9Sstevel@tonic-gate if (!(iop->_flag & _IONBF) && (iop->_flag & (_IOWRT | _IOREAD | _IORW))) 7397c478bd9Sstevel@tonic-gate res = _fflush_u(iop); 740*a5f69788Scraigm if (close(GET_FD(iop)) < 0) 7417c478bd9Sstevel@tonic-gate res = EOF; 7427c478bd9Sstevel@tonic-gate if (iop->_flag & _IOMYBUF) { 7437c478bd9Sstevel@tonic-gate (void) free((char *)iop->_base - PUSHBACK); 7447c478bd9Sstevel@tonic-gate } 7457c478bd9Sstevel@tonic-gate iop->_base = NULL; 7467c478bd9Sstevel@tonic-gate iop->_ptr = NULL; 7477c478bd9Sstevel@tonic-gate mb = _getmbstate(iop); 7487c478bd9Sstevel@tonic-gate if (mb != NULL) 7497c478bd9Sstevel@tonic-gate (void) memset(mb, 0, sizeof (mbstate_t)); 7507c478bd9Sstevel@tonic-gate iop->_cnt = 0; 7517c478bd9Sstevel@tonic-gate _setorientation(iop, _NO_MODE); 7527c478bd9Sstevel@tonic-gate return (res); 7537c478bd9Sstevel@tonic-gate } 7547c478bd9Sstevel@tonic-gate 7557c478bd9Sstevel@tonic-gate static FILE * 7567c478bd9Sstevel@tonic-gate getiop(FILE *fp, rmutex_t *lk, mbstate_t *mb) 7577c478bd9Sstevel@tonic-gate { 7587c478bd9Sstevel@tonic-gate if (lk != NULL && rmutex_trylock(lk)) 7597c478bd9Sstevel@tonic-gate return (NULL); /* locked: fp in use */ 7607c478bd9Sstevel@tonic-gate 7617c478bd9Sstevel@tonic-gate if (fp->_flag == 0) { /* unused */ 7627c478bd9Sstevel@tonic-gate #ifndef _LP64 7637c478bd9Sstevel@tonic-gate fp->__orientation = 0; 7647c478bd9Sstevel@tonic-gate #endif /* _LP64 */ 7657c478bd9Sstevel@tonic-gate fp->_cnt = 0; 7667c478bd9Sstevel@tonic-gate fp->_ptr = NULL; 7677c478bd9Sstevel@tonic-gate fp->_base = NULL; 7687c478bd9Sstevel@tonic-gate fp->_flag = 0377; /* claim the fp by setting low 8 bits */ 7697c478bd9Sstevel@tonic-gate (void) memset(mb, 0, sizeof (mbstate_t)); 7707c478bd9Sstevel@tonic-gate FUNLOCKFILE(lk); 7717c478bd9Sstevel@tonic-gate return (fp); 7727c478bd9Sstevel@tonic-gate } 7737c478bd9Sstevel@tonic-gate FUNLOCKFILE(lk); 7747c478bd9Sstevel@tonic-gate return (NULL); 7757c478bd9Sstevel@tonic-gate } 7767c478bd9Sstevel@tonic-gate 7777c478bd9Sstevel@tonic-gate #ifndef _LP64 7787c478bd9Sstevel@tonic-gate /* 7797c478bd9Sstevel@tonic-gate * DESCRIPTION: 7807c478bd9Sstevel@tonic-gate * This function gets the pointer to the mbstate_t structure associated 7817c478bd9Sstevel@tonic-gate * with the specified iop. 7827c478bd9Sstevel@tonic-gate * 7837c478bd9Sstevel@tonic-gate * RETURNS: 7847c478bd9Sstevel@tonic-gate * If the associated mbstate_t found, the pointer to the mbstate_t is 7857c478bd9Sstevel@tonic-gate * returned. Otherwise, NULL is returned. 7867c478bd9Sstevel@tonic-gate */ 7877c478bd9Sstevel@tonic-gate mbstate_t * 7887c478bd9Sstevel@tonic-gate _getmbstate(FILE *iop) 7897c478bd9Sstevel@tonic-gate { 7907c478bd9Sstevel@tonic-gate struct xFILEdata *dat = getxfdat(iop); 7917c478bd9Sstevel@tonic-gate 7927c478bd9Sstevel@tonic-gate if (dat != NULL) 7937c478bd9Sstevel@tonic-gate return (&dat->_state); 7947c478bd9Sstevel@tonic-gate 7957c478bd9Sstevel@tonic-gate return (NULL); 7967c478bd9Sstevel@tonic-gate } 797*a5f69788Scraigm 798*a5f69788Scraigm /* 799*a5f69788Scraigm * More 32-bit only functions. 800*a5f69788Scraigm * They lookup/set large fd's for extended FILE support. 801*a5f69788Scraigm */ 802*a5f69788Scraigm 803*a5f69788Scraigm /* 804*a5f69788Scraigm * The negative value indicates that Extended fd FILE's has not 805*a5f69788Scraigm * been enabled by the user. 806*a5f69788Scraigm */ 807*a5f69788Scraigm static int bad_fd = -1; 808*a5f69788Scraigm 809*a5f69788Scraigm int 810*a5f69788Scraigm _file_get(FILE *iop) 811*a5f69788Scraigm { 812*a5f69788Scraigm int altfd; 813*a5f69788Scraigm 814*a5f69788Scraigm /* 815*a5f69788Scraigm * Failure indicates a FILE * not allocated through stdio; 816*a5f69788Scraigm * it means the flag values are probably bogus and that if 817*a5f69788Scraigm * a file descriptor is set, it's in _magic. 818*a5f69788Scraigm * Inline getxfdat() for performance reasons. 819*a5f69788Scraigm */ 820*a5f69788Scraigm if (STDIOP(iop)) 821*a5f69788Scraigm altfd = _xftab[IOPIND(iop)]._altfd; 822*a5f69788Scraigm else if (VALIDXFILE(FILEx(iop))) 823*a5f69788Scraigm altfd = FILEx(iop)->_xdat._altfd; 824*a5f69788Scraigm else 825*a5f69788Scraigm return (iop->_magic); 826*a5f69788Scraigm /* 827*a5f69788Scraigm * if this is not an internal extended FILE then check 828*a5f69788Scraigm * if _file is being changed from underneath us. 829*a5f69788Scraigm * It should not be because if 830*a5f69788Scraigm * it is then then we lose our ability to guard against 831*a5f69788Scraigm * silent data corruption. 832*a5f69788Scraigm */ 833*a5f69788Scraigm if (!iop->__xf_nocheck && bad_fd > -1 && iop->_magic != bad_fd) { 834*a5f69788Scraigm /* LINTED: variable format specifier */ 835*a5f69788Scraigm (void) fprintf(stderr, _libc_gettext( 836*a5f69788Scraigm "Application violated extended FILE safety mechanism.\n" 837*a5f69788Scraigm "Please read the man page for extendedFILE.\nAborting\n")); 838*a5f69788Scraigm abort(); 839*a5f69788Scraigm } 840*a5f69788Scraigm return (altfd); 841*a5f69788Scraigm } 842*a5f69788Scraigm 843*a5f69788Scraigm int 844*a5f69788Scraigm _file_set(FILE *iop, int fd, const char *type) 845*a5f69788Scraigm { 846*a5f69788Scraigm struct xFILEdata *dat; 847*a5f69788Scraigm int Fflag; 848*a5f69788Scraigm 849*a5f69788Scraigm /* Already known to contain at least one byte */ 850*a5f69788Scraigm while (*++type != '\0') 851*a5f69788Scraigm ; 852*a5f69788Scraigm 853*a5f69788Scraigm Fflag = type[-1] == 'F'; 854*a5f69788Scraigm if (!Fflag && bad_fd < 0) { 855*a5f69788Scraigm errno = EMFILE; 856*a5f69788Scraigm return (-1); 857*a5f69788Scraigm } 858*a5f69788Scraigm 859*a5f69788Scraigm dat = getxfdat(iop); 860*a5f69788Scraigm iop->__extendedfd = 1; 861*a5f69788Scraigm iop->__xf_nocheck = Fflag; 862*a5f69788Scraigm dat->_altfd = fd; 863*a5f69788Scraigm iop->_magic = (unsigned char)bad_fd; 864*a5f69788Scraigm return (0); 865*a5f69788Scraigm } 866*a5f69788Scraigm 867*a5f69788Scraigm /* 868*a5f69788Scraigm * Activates extended fd's in FILE's 869*a5f69788Scraigm */ 870*a5f69788Scraigm 871*a5f69788Scraigm static const int tries[] = {196, 120, 60, 3}; 872*a5f69788Scraigm #define NTRIES (sizeof (tries)/sizeof (int)) 873*a5f69788Scraigm 874*a5f69788Scraigm int 875*a5f69788Scraigm enable_extended_FILE_stdio(int fd, int action) 876*a5f69788Scraigm { 877*a5f69788Scraigm int i; 878*a5f69788Scraigm 879*a5f69788Scraigm if (action < 0) 880*a5f69788Scraigm action = SIGABRT; /* default signal */ 881*a5f69788Scraigm 882*a5f69788Scraigm if (fd < 0) { 883*a5f69788Scraigm /* 884*a5f69788Scraigm * search for an available fd and make it the badfd 885*a5f69788Scraigm */ 886*a5f69788Scraigm for (i = 0; i < NTRIES; i++) { 887*a5f69788Scraigm fd = fcntl(tries[i], F_BADFD, action); 888*a5f69788Scraigm if (fd >= 0) 889*a5f69788Scraigm break; 890*a5f69788Scraigm } 891*a5f69788Scraigm if (fd < 0) /* failed to find an available fd */ 892*a5f69788Scraigm return (-1); 893*a5f69788Scraigm } else { 894*a5f69788Scraigm /* caller requests that fd be the chosen badfd */ 895*a5f69788Scraigm int nfd = fcntl(fd, F_BADFD, action); 896*a5f69788Scraigm if (nfd < 0 || nfd != fd) 897*a5f69788Scraigm return (-1); 898*a5f69788Scraigm } 899*a5f69788Scraigm bad_fd = fd; 900*a5f69788Scraigm return (0); 901*a5f69788Scraigm } 9027c478bd9Sstevel@tonic-gate #endif 903