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 /* 23*23a1cceaSRoger A. Faulkner * Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate /* Copyright (c) 1988 AT&T */ 277c478bd9Sstevel@tonic-gate /* All Rights Reserved */ 287c478bd9Sstevel@tonic-gate 297257d1b4Sraf #include "lint.h" 307c478bd9Sstevel@tonic-gate #include "mtlib.h" 317c478bd9Sstevel@tonic-gate #include "file64.h" 327c478bd9Sstevel@tonic-gate #include <sys/types.h> 337c478bd9Sstevel@tonic-gate #include <stdlib.h> 347c478bd9Sstevel@tonic-gate #include <stdio.h> 357c478bd9Sstevel@tonic-gate #include <thread.h> 367c478bd9Sstevel@tonic-gate #include <synch.h> 377c478bd9Sstevel@tonic-gate #include <unistd.h> 387c478bd9Sstevel@tonic-gate #include <string.h> 397c478bd9Sstevel@tonic-gate #include "stdiom.h" 407c478bd9Sstevel@tonic-gate #include <wchar.h> 417c478bd9Sstevel@tonic-gate #include <sys/stat.h> 427c478bd9Sstevel@tonic-gate #include <stddef.h> 437c478bd9Sstevel@tonic-gate #include <errno.h> 44a5f69788Scraigm #include <fcntl.h> 457c478bd9Sstevel@tonic-gate 467257d1b4Sraf #define _iob __iob 477257d1b4Sraf 487c478bd9Sstevel@tonic-gate #undef end 497c478bd9Sstevel@tonic-gate 507c478bd9Sstevel@tonic-gate #define FILE_ARY_SZ 8 /* a nice size for FILE array & end_buffer_ptrs */ 517c478bd9Sstevel@tonic-gate 527c478bd9Sstevel@tonic-gate #ifdef _LP64 537c478bd9Sstevel@tonic-gate 547c478bd9Sstevel@tonic-gate /* 557c478bd9Sstevel@tonic-gate * Macros to declare and loop over a fp or fp/xfp combo to 567c478bd9Sstevel@tonic-gate * avoid some of the _LP64 ifdef hell. 577c478bd9Sstevel@tonic-gate */ 587c478bd9Sstevel@tonic-gate 597c478bd9Sstevel@tonic-gate #define FPDECL(fp) FILE *fp 607c478bd9Sstevel@tonic-gate #define FIRSTFP(lp, fp) fp = lp->iobp 617c478bd9Sstevel@tonic-gate #define NEXTFP(fp) fp++ 62a5f69788Scraigm #define FPLOCK(fp) &fp->_lock 63a5f69788Scraigm #define FPSTATE(fp) &fp->_state 647c478bd9Sstevel@tonic-gate 657c478bd9Sstevel@tonic-gate #define xFILE FILE 667c478bd9Sstevel@tonic-gate 677c478bd9Sstevel@tonic-gate #else 687c478bd9Sstevel@tonic-gate 697c478bd9Sstevel@tonic-gate #define FPDECL(fp) FILE *fp; xFILE *x##fp 707c478bd9Sstevel@tonic-gate #define FIRSTFP(lp, fp) x##fp = lp->iobp; \ 717c478bd9Sstevel@tonic-gate fp = x##fp ? &x##fp->_iob : &_iob[0] 727c478bd9Sstevel@tonic-gate #define NEXTFP(fp) (x##fp ? fp = &(++x##fp)->_iob : ++fp) 73a5f69788Scraigm #define FPLOCK(fp) x##fp ? \ 74a5f69788Scraigm &x##fp->xlock : &_xftab[IOPIND(fp)]._lock 75a5f69788Scraigm #define FPSTATE(fp) x##fp ? \ 76a5f69788Scraigm &x##fp->xstate : &_xftab[IOPIND(fp)]._state 777c478bd9Sstevel@tonic-gate 787c478bd9Sstevel@tonic-gate /* The extended 32-bit file structure for use in link buffers */ 797c478bd9Sstevel@tonic-gate typedef struct xFILE { 807c478bd9Sstevel@tonic-gate FILE _iob; /* must be first! */ 817c478bd9Sstevel@tonic-gate struct xFILEdata _xdat; 827c478bd9Sstevel@tonic-gate } xFILE; 837c478bd9Sstevel@tonic-gate 847c478bd9Sstevel@tonic-gate #define xmagic _xdat._magic 857c478bd9Sstevel@tonic-gate #define xend _xdat._end 867c478bd9Sstevel@tonic-gate #define xlock _xdat._lock 877c478bd9Sstevel@tonic-gate #define xstate _xdat._state 887c478bd9Sstevel@tonic-gate 897c478bd9Sstevel@tonic-gate #define FILEx(fp) ((struct xFILE *)(uintptr_t)fp) 907c478bd9Sstevel@tonic-gate 917c478bd9Sstevel@tonic-gate /* 927c478bd9Sstevel@tonic-gate * The magic number stored is actually the pointer scrambled with 937c478bd9Sstevel@tonic-gate * a magic number. Pointers to data items live everywhere in memory 947c478bd9Sstevel@tonic-gate * so we scramble the pointer in order to avoid accidental collisions. 957c478bd9Sstevel@tonic-gate */ 967c478bd9Sstevel@tonic-gate #define XFILEMAGIC 0x63687367 977c478bd9Sstevel@tonic-gate #define XMAGIC(xfp) ((uintptr_t)(xfp) ^ XFILEMAGIC) 987c478bd9Sstevel@tonic-gate 997c478bd9Sstevel@tonic-gate #endif /* _LP64 */ 1007c478bd9Sstevel@tonic-gate 1017c478bd9Sstevel@tonic-gate struct _link_ /* manages a list of streams */ 1027c478bd9Sstevel@tonic-gate { 1037c478bd9Sstevel@tonic-gate xFILE *iobp; /* the array of (x)FILE's */ 1047c478bd9Sstevel@tonic-gate /* NULL for the __first_link in ILP32 */ 1057c478bd9Sstevel@tonic-gate int niob; /* length of the arrays */ 1067c478bd9Sstevel@tonic-gate struct _link_ *next; /* next in the list */ 1077c478bd9Sstevel@tonic-gate }; 1087c478bd9Sstevel@tonic-gate 1097c478bd9Sstevel@tonic-gate /* 1107c478bd9Sstevel@tonic-gate * With dynamic linking, iob may be in either the library or in the user's 1117c478bd9Sstevel@tonic-gate * a.out, so the run time linker fixes up the first entry in __first_link at 1127c478bd9Sstevel@tonic-gate * process startup time. 1137c478bd9Sstevel@tonic-gate * 1147c478bd9Sstevel@tonic-gate * In 32 bit processes, we don't have xFILE[FILE_ARY_SZ] but FILE[], 1157c478bd9Sstevel@tonic-gate * and _xftab[] instead; this is denoted by having iobp set to NULL in 1167c478bd9Sstevel@tonic-gate * 32 bit mode for the first link entry. 1177c478bd9Sstevel@tonic-gate */ 1187c478bd9Sstevel@tonic-gate struct _link_ __first_link = /* first in linked list */ 1197c478bd9Sstevel@tonic-gate { 1207c478bd9Sstevel@tonic-gate #if !defined(_LP64) 1217c478bd9Sstevel@tonic-gate NULL, 1227c478bd9Sstevel@tonic-gate #else 1237c478bd9Sstevel@tonic-gate &_iob[0], 1247c478bd9Sstevel@tonic-gate #endif 1257c478bd9Sstevel@tonic-gate _NFILE, 1267c478bd9Sstevel@tonic-gate NULL 1277c478bd9Sstevel@tonic-gate }; 1287c478bd9Sstevel@tonic-gate 1297c478bd9Sstevel@tonic-gate /* 1307c478bd9Sstevel@tonic-gate * Information cached to speed up searches. We remember where we 1317c478bd9Sstevel@tonic-gate * last found a free FILE* and we remember whether we saw any fcloses 1327c478bd9Sstevel@tonic-gate * in between. We also count the number of chunks we allocated, see 1337c478bd9Sstevel@tonic-gate * _findiop() for an explanation. 1347c478bd9Sstevel@tonic-gate * These variables are all protected by _first_link_lock. 1357c478bd9Sstevel@tonic-gate */ 1367c478bd9Sstevel@tonic-gate static struct _link_ *lastlink = NULL; 1377c478bd9Sstevel@tonic-gate static int fcloses; 1387c478bd9Sstevel@tonic-gate static int nchunks; 1397c478bd9Sstevel@tonic-gate 140a5f69788Scraigm static mutex_t _first_link_lock = DEFAULTMUTEX; 1417c478bd9Sstevel@tonic-gate 142a5f69788Scraigm static int _fflush_l_iops(void); 1437c478bd9Sstevel@tonic-gate static FILE *getiop(FILE *, rmutex_t *, mbstate_t *); 1447c478bd9Sstevel@tonic-gate 1457c478bd9Sstevel@tonic-gate /* 1467c478bd9Sstevel@tonic-gate * All functions that understand the linked list of iob's follow. 1477c478bd9Sstevel@tonic-gate */ 1487c478bd9Sstevel@tonic-gate #pragma weak _cleanup = __cleanup 1497c478bd9Sstevel@tonic-gate void 1507c478bd9Sstevel@tonic-gate __cleanup(void) /* called at process end to flush ouput streams */ 1517c478bd9Sstevel@tonic-gate { 1527c478bd9Sstevel@tonic-gate (void) fflush(NULL); 1537c478bd9Sstevel@tonic-gate } 1547c478bd9Sstevel@tonic-gate 1557c478bd9Sstevel@tonic-gate /* 1567c478bd9Sstevel@tonic-gate * For fork1-safety (see libc_prepare_atfork(), etc). 1577c478bd9Sstevel@tonic-gate */ 1587c478bd9Sstevel@tonic-gate void 1597c478bd9Sstevel@tonic-gate stdio_locks() 1607c478bd9Sstevel@tonic-gate { 1618cd45542Sraf (void) mutex_lock(&_first_link_lock); 1627c478bd9Sstevel@tonic-gate /* 1637c478bd9Sstevel@tonic-gate * XXX: We should acquire all of the iob locks here. 1647c478bd9Sstevel@tonic-gate */ 1657c478bd9Sstevel@tonic-gate } 1667c478bd9Sstevel@tonic-gate 1677c478bd9Sstevel@tonic-gate void 1687c478bd9Sstevel@tonic-gate stdio_unlocks() 1697c478bd9Sstevel@tonic-gate { 1707c478bd9Sstevel@tonic-gate /* 1717c478bd9Sstevel@tonic-gate * XXX: We should release all of the iob locks here. 1727c478bd9Sstevel@tonic-gate */ 1738cd45542Sraf (void) mutex_unlock(&_first_link_lock); 1747c478bd9Sstevel@tonic-gate } 1757c478bd9Sstevel@tonic-gate 1767c478bd9Sstevel@tonic-gate void 1777c478bd9Sstevel@tonic-gate _flushlbf(void) /* fflush() all line-buffered streams */ 1787c478bd9Sstevel@tonic-gate { 1797c478bd9Sstevel@tonic-gate FPDECL(fp); 1807c478bd9Sstevel@tonic-gate int i; 1817c478bd9Sstevel@tonic-gate struct _link_ *lp; 182a5f69788Scraigm /* Allow compiler to optimize the loop */ 183a5f69788Scraigm int threaded = __libc_threaded; 1847c478bd9Sstevel@tonic-gate 185a5f69788Scraigm if (threaded) 186a574db85Sraf cancel_safe_mutex_lock(&_first_link_lock); 1877c478bd9Sstevel@tonic-gate 1887c478bd9Sstevel@tonic-gate lp = &__first_link; 1897c478bd9Sstevel@tonic-gate do { 1907c478bd9Sstevel@tonic-gate FIRSTFP(lp, fp); 1917c478bd9Sstevel@tonic-gate for (i = lp->niob; --i >= 0; NEXTFP(fp)) { 192a5f69788Scraigm /* 193a5f69788Scraigm * The additional _IONBF check guards againsts 194a5f69788Scraigm * allocated but uninitialized iops (see _findiop). 195a5f69788Scraigm * We also automatically skip non allocated iop's. 196a5f69788Scraigm * Don't block on locks. 197a5f69788Scraigm */ 198a5f69788Scraigm if ((fp->_flag & (_IOLBF | _IOWRT | _IONBF)) == 199a5f69788Scraigm (_IOLBF | _IOWRT)) { 200a5f69788Scraigm if (threaded) { 201a5f69788Scraigm rmutex_t *lk = FPLOCK(fp); 202a574db85Sraf if (cancel_safe_mutex_trylock(lk) != 0) 203a5f69788Scraigm continue; 204a5f69788Scraigm /* Recheck after locking */ 2057c478bd9Sstevel@tonic-gate if ((fp->_flag & (_IOLBF | _IOWRT)) == 206a5f69788Scraigm (_IOLBF | _IOWRT)) { 2077c478bd9Sstevel@tonic-gate (void) _fflush_u(fp); 2087c478bd9Sstevel@tonic-gate } 209a574db85Sraf cancel_safe_mutex_unlock(lk); 210a5f69788Scraigm } else { 211a5f69788Scraigm (void) _fflush_u(fp); 212a5f69788Scraigm } 213a5f69788Scraigm } 214a5f69788Scraigm } 2157c478bd9Sstevel@tonic-gate } while ((lp = lp->next) != NULL); 2167c478bd9Sstevel@tonic-gate 217a5f69788Scraigm if (threaded) 218a574db85Sraf cancel_safe_mutex_unlock(&_first_link_lock); 2197c478bd9Sstevel@tonic-gate } 2207c478bd9Sstevel@tonic-gate 2217c478bd9Sstevel@tonic-gate /* allocate an unused stream; NULL if cannot */ 2227c478bd9Sstevel@tonic-gate FILE * 2237c478bd9Sstevel@tonic-gate _findiop(void) 2247c478bd9Sstevel@tonic-gate { 2257c478bd9Sstevel@tonic-gate struct _link_ *lp, **prev; 2267c478bd9Sstevel@tonic-gate 2277c478bd9Sstevel@tonic-gate /* used so there only needs to be one malloc() */ 2287c478bd9Sstevel@tonic-gate #ifdef _LP64 2297c478bd9Sstevel@tonic-gate typedef struct { 2307c478bd9Sstevel@tonic-gate struct _link_ hdr; 2317c478bd9Sstevel@tonic-gate FILE iob[FILE_ARY_SZ]; 2327c478bd9Sstevel@tonic-gate } Pkg; 2337c478bd9Sstevel@tonic-gate #else 2347c478bd9Sstevel@tonic-gate typedef union { 2357c478bd9Sstevel@tonic-gate struct { /* Normal */ 2367c478bd9Sstevel@tonic-gate struct _link_ hdr; 2377c478bd9Sstevel@tonic-gate xFILE iob[FILE_ARY_SZ]; 2387c478bd9Sstevel@tonic-gate } Pkgn; 2397c478bd9Sstevel@tonic-gate struct { /* Reversed */ 2407c478bd9Sstevel@tonic-gate xFILE iob[FILE_ARY_SZ]; 2417c478bd9Sstevel@tonic-gate struct _link_ hdr; 2427c478bd9Sstevel@tonic-gate } Pkgr; 2437c478bd9Sstevel@tonic-gate } Pkg; 2447c478bd9Sstevel@tonic-gate uintptr_t delta; 2457c478bd9Sstevel@tonic-gate #endif 2467c478bd9Sstevel@tonic-gate Pkg *pkgp; 2477c478bd9Sstevel@tonic-gate struct _link_ *hdr; 2487c478bd9Sstevel@tonic-gate FPDECL(fp); 2497c478bd9Sstevel@tonic-gate int i; 250a5f69788Scraigm int threaded = __libc_threaded; 2517c478bd9Sstevel@tonic-gate 252a5f69788Scraigm if (threaded) 253a574db85Sraf cancel_safe_mutex_lock(&_first_link_lock); 2547c478bd9Sstevel@tonic-gate 2557c478bd9Sstevel@tonic-gate if (lastlink == NULL) { 2567c478bd9Sstevel@tonic-gate rescan: 2577c478bd9Sstevel@tonic-gate fcloses = 0; 2587c478bd9Sstevel@tonic-gate lastlink = &__first_link; 2597c478bd9Sstevel@tonic-gate } 2607c478bd9Sstevel@tonic-gate 2617c478bd9Sstevel@tonic-gate lp = lastlink; 2627c478bd9Sstevel@tonic-gate 2637c478bd9Sstevel@tonic-gate /* 2647c478bd9Sstevel@tonic-gate * lock to make testing of fp->_flag == 0 and acquiring the fp atomic 2657c478bd9Sstevel@tonic-gate * and for allocation of new links 2667c478bd9Sstevel@tonic-gate * low contention expected on _findiop(), hence coarse locking. 2677c478bd9Sstevel@tonic-gate * for finer granularity, use fp->_lock for allocating an iop 2687c478bd9Sstevel@tonic-gate * and make the testing of lp->next and allocation of new link atomic 2697c478bd9Sstevel@tonic-gate * using lp->_lock 2707c478bd9Sstevel@tonic-gate */ 2717c478bd9Sstevel@tonic-gate 2727c478bd9Sstevel@tonic-gate do { 2737c478bd9Sstevel@tonic-gate prev = &lp->next; 2747c478bd9Sstevel@tonic-gate FIRSTFP(lp, fp); 2757c478bd9Sstevel@tonic-gate 2767c478bd9Sstevel@tonic-gate for (i = lp->niob; --i >= 0; NEXTFP(fp)) { 277a5f69788Scraigm FILE *ret; 278a5f69788Scraigm if (threaded) { 279a5f69788Scraigm ret = getiop(fp, FPLOCK(fp), FPSTATE(fp)); 280a5f69788Scraigm if (ret != NULL) { 281a574db85Sraf cancel_safe_mutex_unlock( 282b2e86e7aScasper &_first_link_lock); 283a5f69788Scraigm return (ret); 284a5f69788Scraigm } 285a5f69788Scraigm } else { 286a5f69788Scraigm ret = getiop(fp, NULL, FPSTATE(fp)); 287a5f69788Scraigm if (ret != NULL) 288a5f69788Scraigm return (ret); 289a5f69788Scraigm } 2907c478bd9Sstevel@tonic-gate } 2917c478bd9Sstevel@tonic-gate } while ((lastlink = lp = lp->next) != NULL); 2927c478bd9Sstevel@tonic-gate 2937c478bd9Sstevel@tonic-gate /* 2947c478bd9Sstevel@tonic-gate * If there was a sufficient number of fcloses since we last started 2957c478bd9Sstevel@tonic-gate * at __first_link, we rescan all fp's again. We do not rescan for 2967c478bd9Sstevel@tonic-gate * all fcloses; that would simplify the algorithm but would make 2977c478bd9Sstevel@tonic-gate * search times near O(n) again. 2987c478bd9Sstevel@tonic-gate * Worst case behaviour would still be pretty bad (open a full set, 2997c478bd9Sstevel@tonic-gate * then continously opening and closing one FILE * gets you a full 3007c478bd9Sstevel@tonic-gate * scan each time). That's why we over allocate 1 FILE for each 3017c478bd9Sstevel@tonic-gate * 32 chunks. More over allocation is better; this is a nice 3027c478bd9Sstevel@tonic-gate * empirical value which doesn't cost a lot of memory, doesn't 3037c478bd9Sstevel@tonic-gate * overallocate until we reach 256 FILE *s and keeps the performance 3047c478bd9Sstevel@tonic-gate * pretty close to the optimum. 3057c478bd9Sstevel@tonic-gate */ 3067c478bd9Sstevel@tonic-gate if (fcloses > nchunks/32) 3077c478bd9Sstevel@tonic-gate goto rescan; 3087c478bd9Sstevel@tonic-gate 3097c478bd9Sstevel@tonic-gate /* 3107c478bd9Sstevel@tonic-gate * Need to allocate another and put it in the linked list. 3117c478bd9Sstevel@tonic-gate */ 3127c478bd9Sstevel@tonic-gate if ((pkgp = malloc(sizeof (Pkg))) == NULL) { 313a5f69788Scraigm if (threaded) 314a574db85Sraf cancel_safe_mutex_unlock(&_first_link_lock); 3157c478bd9Sstevel@tonic-gate return (NULL); 3167c478bd9Sstevel@tonic-gate } 3177c478bd9Sstevel@tonic-gate 3187c478bd9Sstevel@tonic-gate (void) memset(pkgp, 0, sizeof (Pkg)); 3197c478bd9Sstevel@tonic-gate 3207c478bd9Sstevel@tonic-gate #ifdef _LP64 3217c478bd9Sstevel@tonic-gate hdr = &pkgp->hdr; 3227c478bd9Sstevel@tonic-gate hdr->iobp = &pkgp->iob[0]; 3237c478bd9Sstevel@tonic-gate #else 3247c478bd9Sstevel@tonic-gate /* 3257c478bd9Sstevel@tonic-gate * The problem with referencing a word after a FILE* is the possibility 3267c478bd9Sstevel@tonic-gate * of a SIGSEGV if a non-stdio issue FILE structure ends on a page 3277c478bd9Sstevel@tonic-gate * boundary. We run this check so we never need to run an expensive 3287c478bd9Sstevel@tonic-gate * check like mincore() in order to know whether it is 3297c478bd9Sstevel@tonic-gate * safe to dereference ((xFILE*)fp)->xmagic. 3307c478bd9Sstevel@tonic-gate * We allocate the block with two alternative layouts; if one 3317c478bd9Sstevel@tonic-gate * layout is not properly aligned for our purposes, the other layout 3327c478bd9Sstevel@tonic-gate * will be because the size of _link_ is small compared to 3337c478bd9Sstevel@tonic-gate * sizeof (xFILE). 3347c478bd9Sstevel@tonic-gate * The check performed is this: 3357c478bd9Sstevel@tonic-gate * If the distance from pkgp to the end of the page is 3367c478bd9Sstevel@tonic-gate * less than the the offset of the last xmagic field in the 3377c478bd9Sstevel@tonic-gate * xFILE structure, (the 0x1000 boundary is inside our just 3387c478bd9Sstevel@tonic-gate * allocated structure) and the distance modulo the size of xFILE 3397c478bd9Sstevel@tonic-gate * is identical to the offset of the first xmagic in the 3407c478bd9Sstevel@tonic-gate * structure (i.e., XXXXXX000 points to an xmagic field), 3417c478bd9Sstevel@tonic-gate * we need to use the reverse structure. 3427c478bd9Sstevel@tonic-gate */ 3437c478bd9Sstevel@tonic-gate if ((delta = 0x1000 - ((uintptr_t)pkgp & 0xfff)) <= 3447c478bd9Sstevel@tonic-gate offsetof(Pkg, Pkgn.iob[FILE_ARY_SZ-1].xmagic) && 3457c478bd9Sstevel@tonic-gate delta % sizeof (struct xFILE) == 3467c478bd9Sstevel@tonic-gate offsetof(Pkg, Pkgn.iob[0].xmagic)) { 3477c478bd9Sstevel@tonic-gate /* Use reversed structure */ 3487c478bd9Sstevel@tonic-gate hdr = &pkgp->Pkgr.hdr; 3497c478bd9Sstevel@tonic-gate hdr->iobp = &pkgp->Pkgr.iob[0]; 3507c478bd9Sstevel@tonic-gate } else { 3517c478bd9Sstevel@tonic-gate /* Use normal structure */ 3527c478bd9Sstevel@tonic-gate hdr = &pkgp->Pkgn.hdr; 3537c478bd9Sstevel@tonic-gate hdr->iobp = &pkgp->Pkgn.iob[0]; 3547c478bd9Sstevel@tonic-gate } 3557c478bd9Sstevel@tonic-gate #endif /* _LP64 */ 3567c478bd9Sstevel@tonic-gate 3577c478bd9Sstevel@tonic-gate hdr->niob = FILE_ARY_SZ; 3587c478bd9Sstevel@tonic-gate nchunks++; 3597c478bd9Sstevel@tonic-gate 3607c478bd9Sstevel@tonic-gate #ifdef _LP64 3617c478bd9Sstevel@tonic-gate fp = hdr->iobp; 3627c478bd9Sstevel@tonic-gate for (i = 0; i < FILE_ARY_SZ; i++) 3637257d1b4Sraf (void) mutex_init(&fp[i]._lock, 3647257d1b4Sraf USYNC_THREAD | LOCK_RECURSIVE, NULL); 3657c478bd9Sstevel@tonic-gate #else 3667c478bd9Sstevel@tonic-gate xfp = hdr->iobp; 3677c478bd9Sstevel@tonic-gate fp = &xfp->_iob; 3687c478bd9Sstevel@tonic-gate 3697c478bd9Sstevel@tonic-gate for (i = 0; i < FILE_ARY_SZ; i++) { 3707c478bd9Sstevel@tonic-gate xfp[i].xmagic = XMAGIC(&xfp[i]); 3717257d1b4Sraf (void) mutex_init(&xfp[i].xlock, 3727257d1b4Sraf USYNC_THREAD | LOCK_RECURSIVE, NULL); 3737c478bd9Sstevel@tonic-gate } 3747c478bd9Sstevel@tonic-gate #endif /* _LP64 */ 3757c478bd9Sstevel@tonic-gate 3767c478bd9Sstevel@tonic-gate lastlink = *prev = hdr; 3777c478bd9Sstevel@tonic-gate fp->_ptr = 0; 3787c478bd9Sstevel@tonic-gate fp->_base = 0; 3797c478bd9Sstevel@tonic-gate fp->_flag = 0377; /* claim the fp by setting low 8 bits */ 380a5f69788Scraigm if (threaded) 381a574db85Sraf cancel_safe_mutex_unlock(&_first_link_lock); 3827c478bd9Sstevel@tonic-gate 3837c478bd9Sstevel@tonic-gate return (fp); 3847c478bd9Sstevel@tonic-gate } 3857c478bd9Sstevel@tonic-gate 3867c478bd9Sstevel@tonic-gate static void 3877c478bd9Sstevel@tonic-gate isseekable(FILE *iop) 3887c478bd9Sstevel@tonic-gate { 3897c478bd9Sstevel@tonic-gate struct stat64 fstatbuf; 3907c478bd9Sstevel@tonic-gate int save_errno; 3917c478bd9Sstevel@tonic-gate 3927c478bd9Sstevel@tonic-gate save_errno = errno; 3937c478bd9Sstevel@tonic-gate 394a5f69788Scraigm if (fstat64(GET_FD(iop), &fstatbuf) != 0) { 3957c478bd9Sstevel@tonic-gate /* 3967c478bd9Sstevel@tonic-gate * when we don't know what it is we'll 3977c478bd9Sstevel@tonic-gate * do the old behaviour and flush 3987c478bd9Sstevel@tonic-gate * the stream 3997c478bd9Sstevel@tonic-gate */ 4007c478bd9Sstevel@tonic-gate SET_SEEKABLE(iop); 4017c478bd9Sstevel@tonic-gate errno = save_errno; 4027c478bd9Sstevel@tonic-gate return; 4037c478bd9Sstevel@tonic-gate } 4047c478bd9Sstevel@tonic-gate 4057c478bd9Sstevel@tonic-gate /* 4067c478bd9Sstevel@tonic-gate * check for what is non-SEEKABLE 4077c478bd9Sstevel@tonic-gate * otherwise assume it's SEEKABLE so we get the old 4087c478bd9Sstevel@tonic-gate * behaviour and flush the stream 4097c478bd9Sstevel@tonic-gate */ 4107c478bd9Sstevel@tonic-gate 4117c478bd9Sstevel@tonic-gate if (S_ISFIFO(fstatbuf.st_mode) || S_ISCHR(fstatbuf.st_mode) || 4127c478bd9Sstevel@tonic-gate S_ISSOCK(fstatbuf.st_mode) || S_ISDOOR(fstatbuf.st_mode)) { 4137c478bd9Sstevel@tonic-gate CLEAR_SEEKABLE(iop); 4147c478bd9Sstevel@tonic-gate } else { 4157c478bd9Sstevel@tonic-gate SET_SEEKABLE(iop); 4167c478bd9Sstevel@tonic-gate } 4177c478bd9Sstevel@tonic-gate 4187c478bd9Sstevel@tonic-gate errno = save_errno; 4197c478bd9Sstevel@tonic-gate } 4207c478bd9Sstevel@tonic-gate 4217c478bd9Sstevel@tonic-gate #ifdef _LP64 4227c478bd9Sstevel@tonic-gate void 4237c478bd9Sstevel@tonic-gate _setbufend(FILE *iop, Uchar *end) /* set the end pointer for this iop */ 4247c478bd9Sstevel@tonic-gate { 4257c478bd9Sstevel@tonic-gate iop->_end = end; 4267c478bd9Sstevel@tonic-gate 4277c478bd9Sstevel@tonic-gate isseekable(iop); 4287c478bd9Sstevel@tonic-gate } 4297c478bd9Sstevel@tonic-gate 4307c478bd9Sstevel@tonic-gate #undef _realbufend 4317c478bd9Sstevel@tonic-gate 4327c478bd9Sstevel@tonic-gate Uchar * 4337c478bd9Sstevel@tonic-gate _realbufend(FILE *iop) /* get the end pointer for this iop */ 4347c478bd9Sstevel@tonic-gate { 4357c478bd9Sstevel@tonic-gate return (iop->_end); 4367c478bd9Sstevel@tonic-gate } 4377c478bd9Sstevel@tonic-gate 4387c478bd9Sstevel@tonic-gate #else /* _LP64 */ 4397c478bd9Sstevel@tonic-gate 4407c478bd9Sstevel@tonic-gate /* 4417c478bd9Sstevel@tonic-gate * Awkward functions not needed for the sane 64 bit environment. 4427c478bd9Sstevel@tonic-gate */ 4437c478bd9Sstevel@tonic-gate /* 4447c478bd9Sstevel@tonic-gate * xmagic must not be aligned on a 4K boundary. We guarantee this in 4457c478bd9Sstevel@tonic-gate * _findiop(). 4467c478bd9Sstevel@tonic-gate */ 4477c478bd9Sstevel@tonic-gate #define VALIDXFILE(xfp) \ 4487c478bd9Sstevel@tonic-gate (((uintptr_t)&(xfp)->xmagic & 0xfff) && \ 4497c478bd9Sstevel@tonic-gate (xfp)->xmagic == XMAGIC(FILEx(xfp))) 4507c478bd9Sstevel@tonic-gate 4517c478bd9Sstevel@tonic-gate static struct xFILEdata * 4527c478bd9Sstevel@tonic-gate getxfdat(FILE *iop) 4537c478bd9Sstevel@tonic-gate { 4547c478bd9Sstevel@tonic-gate if (STDIOP(iop)) 4557c478bd9Sstevel@tonic-gate return (&_xftab[IOPIND(iop)]); 4567c478bd9Sstevel@tonic-gate else if (VALIDXFILE(FILEx(iop))) 4577c478bd9Sstevel@tonic-gate return (&FILEx(iop)->_xdat); 4587c478bd9Sstevel@tonic-gate else 4597c478bd9Sstevel@tonic-gate return (NULL); 4607c478bd9Sstevel@tonic-gate } 4617c478bd9Sstevel@tonic-gate 4627c478bd9Sstevel@tonic-gate void 4637c478bd9Sstevel@tonic-gate _setbufend(FILE *iop, Uchar *end) /* set the end pointer for this iop */ 4647c478bd9Sstevel@tonic-gate { 4657c478bd9Sstevel@tonic-gate struct xFILEdata *dat = getxfdat(iop); 4667c478bd9Sstevel@tonic-gate 4677c478bd9Sstevel@tonic-gate if (dat != NULL) 4687c478bd9Sstevel@tonic-gate dat->_end = end; 4697c478bd9Sstevel@tonic-gate 4707c478bd9Sstevel@tonic-gate isseekable(iop); 4717c478bd9Sstevel@tonic-gate 4727c478bd9Sstevel@tonic-gate /* 4737c478bd9Sstevel@tonic-gate * For binary compatibility with user programs using the 4747c478bd9Sstevel@tonic-gate * old _bufend macro. This is *so* broken, fileno() 4757c478bd9Sstevel@tonic-gate * is not the proper index. 4767c478bd9Sstevel@tonic-gate */ 477a5f69788Scraigm if (iop->_magic < _NFILE) 478a5f69788Scraigm _bufendtab[iop->_magic] = end; 4797c478bd9Sstevel@tonic-gate 4807c478bd9Sstevel@tonic-gate } 4817c478bd9Sstevel@tonic-gate 4827c478bd9Sstevel@tonic-gate Uchar * 4837c478bd9Sstevel@tonic-gate _realbufend(FILE *iop) /* get the end pointer for this iop */ 4847c478bd9Sstevel@tonic-gate { 4857c478bd9Sstevel@tonic-gate struct xFILEdata *dat = getxfdat(iop); 4867c478bd9Sstevel@tonic-gate 4877c478bd9Sstevel@tonic-gate if (dat != NULL) 4887c478bd9Sstevel@tonic-gate return (dat->_end); 4897c478bd9Sstevel@tonic-gate 4907c478bd9Sstevel@tonic-gate return (NULL); 4917c478bd9Sstevel@tonic-gate } 4927c478bd9Sstevel@tonic-gate 4937c478bd9Sstevel@tonic-gate /* 4947c478bd9Sstevel@tonic-gate * _reallock() is invoked in each stdio call through the IOB_LCK() macro, 4957c478bd9Sstevel@tonic-gate * it is therefor extremely performance sensitive. We get better performance 4967c478bd9Sstevel@tonic-gate * by inlining the STDIOP check in IOB_LCK and inlining a custom version 4977c478bd9Sstevel@tonic-gate * of getfxdat() here. 4987c478bd9Sstevel@tonic-gate */ 4997c478bd9Sstevel@tonic-gate rmutex_t * 5007c478bd9Sstevel@tonic-gate _reallock(FILE *iop) 5017c478bd9Sstevel@tonic-gate { 5027c478bd9Sstevel@tonic-gate if (VALIDXFILE(FILEx(iop))) 5037c478bd9Sstevel@tonic-gate return (&FILEx(iop)->xlock); 5047c478bd9Sstevel@tonic-gate 5057c478bd9Sstevel@tonic-gate return (NULL); 5067c478bd9Sstevel@tonic-gate } 5077c478bd9Sstevel@tonic-gate 5087c478bd9Sstevel@tonic-gate #endif /* _LP64 */ 5097c478bd9Sstevel@tonic-gate 5107c478bd9Sstevel@tonic-gate /* make sure _cnt, _ptr are correct */ 5117c478bd9Sstevel@tonic-gate void 5127c478bd9Sstevel@tonic-gate _bufsync(FILE *iop, Uchar *bufend) 5137c478bd9Sstevel@tonic-gate { 5147c478bd9Sstevel@tonic-gate ssize_t spaceleft; 5157c478bd9Sstevel@tonic-gate 5167c478bd9Sstevel@tonic-gate spaceleft = bufend - iop->_ptr; 5177c478bd9Sstevel@tonic-gate if (bufend < iop->_ptr) { 5187c478bd9Sstevel@tonic-gate iop->_ptr = bufend; 5197c478bd9Sstevel@tonic-gate iop->_cnt = 0; 5207c478bd9Sstevel@tonic-gate } else if (spaceleft < iop->_cnt) 5217c478bd9Sstevel@tonic-gate iop->_cnt = spaceleft; 5227c478bd9Sstevel@tonic-gate } 5237c478bd9Sstevel@tonic-gate 5247c478bd9Sstevel@tonic-gate /* really write out current buffer contents */ 5257c478bd9Sstevel@tonic-gate int 5267c478bd9Sstevel@tonic-gate _xflsbuf(FILE *iop) 5277c478bd9Sstevel@tonic-gate { 5287c478bd9Sstevel@tonic-gate ssize_t n; 5297c478bd9Sstevel@tonic-gate Uchar *base = iop->_base; 5307c478bd9Sstevel@tonic-gate Uchar *bufend; 5317c478bd9Sstevel@tonic-gate ssize_t num_wrote; 5327c478bd9Sstevel@tonic-gate 5337c478bd9Sstevel@tonic-gate /* 5347c478bd9Sstevel@tonic-gate * Hopefully, be stable with respect to interrupts... 5357c478bd9Sstevel@tonic-gate */ 5367c478bd9Sstevel@tonic-gate n = iop->_ptr - base; 5377c478bd9Sstevel@tonic-gate iop->_ptr = base; 5387c478bd9Sstevel@tonic-gate bufend = _bufend(iop); 5397c478bd9Sstevel@tonic-gate if (iop->_flag & (_IOLBF | _IONBF)) 5407c478bd9Sstevel@tonic-gate iop->_cnt = 0; /* always go to a flush */ 5417c478bd9Sstevel@tonic-gate else 5427c478bd9Sstevel@tonic-gate iop->_cnt = bufend - base; 5437c478bd9Sstevel@tonic-gate 5447c478bd9Sstevel@tonic-gate if (_needsync(iop, bufend)) /* recover from interrupts */ 5457c478bd9Sstevel@tonic-gate _bufsync(iop, bufend); 5467c478bd9Sstevel@tonic-gate 5477c478bd9Sstevel@tonic-gate if (n > 0) { 548a5f69788Scraigm int fd = GET_FD(iop); 549a574db85Sraf while ((num_wrote = write(fd, base, (size_t)n)) != n) { 5507c478bd9Sstevel@tonic-gate if (num_wrote <= 0) { 551a574db85Sraf if (!cancel_active()) 5527c478bd9Sstevel@tonic-gate iop->_flag |= _IOERR; 5537c478bd9Sstevel@tonic-gate return (EOF); 5547c478bd9Sstevel@tonic-gate } 5557c478bd9Sstevel@tonic-gate n -= num_wrote; 5567c478bd9Sstevel@tonic-gate base += num_wrote; 5577c478bd9Sstevel@tonic-gate } 5587c478bd9Sstevel@tonic-gate } 5597c478bd9Sstevel@tonic-gate return (0); 5607c478bd9Sstevel@tonic-gate } 5617c478bd9Sstevel@tonic-gate 5627c478bd9Sstevel@tonic-gate /* flush (write) buffer */ 5637c478bd9Sstevel@tonic-gate int 5647c478bd9Sstevel@tonic-gate fflush(FILE *iop) 5657c478bd9Sstevel@tonic-gate { 5667c478bd9Sstevel@tonic-gate int res; 5677c478bd9Sstevel@tonic-gate rmutex_t *lk; 5687c478bd9Sstevel@tonic-gate 5697c478bd9Sstevel@tonic-gate if (iop) { 5707c478bd9Sstevel@tonic-gate FLOCKFILE(lk, iop); 5717c478bd9Sstevel@tonic-gate res = _fflush_u(iop); 5727c478bd9Sstevel@tonic-gate FUNLOCKFILE(lk); 5737c478bd9Sstevel@tonic-gate } else { 574a5f69788Scraigm res = _fflush_l_iops(); /* flush all iops */ 5757c478bd9Sstevel@tonic-gate } 5767c478bd9Sstevel@tonic-gate return (res); 5777c478bd9Sstevel@tonic-gate } 5787c478bd9Sstevel@tonic-gate 5797c478bd9Sstevel@tonic-gate static int 580a5f69788Scraigm _fflush_l_iops(void) /* flush all buffers */ 5817c478bd9Sstevel@tonic-gate { 5827c478bd9Sstevel@tonic-gate FPDECL(iop); 5837c478bd9Sstevel@tonic-gate 5847c478bd9Sstevel@tonic-gate int i; 5857c478bd9Sstevel@tonic-gate struct _link_ *lp; 5867c478bd9Sstevel@tonic-gate int res = 0; 587a5f69788Scraigm rmutex_t *lk; 588a5f69788Scraigm /* Allow the compiler to optimize the load out of the loop */ 589a5f69788Scraigm int threaded = __libc_threaded; 5907c478bd9Sstevel@tonic-gate 591a5f69788Scraigm if (threaded) 592a574db85Sraf cancel_safe_mutex_lock(&_first_link_lock); 5937c478bd9Sstevel@tonic-gate 5947c478bd9Sstevel@tonic-gate lp = &__first_link; 5957c478bd9Sstevel@tonic-gate 5967c478bd9Sstevel@tonic-gate do { 5977c478bd9Sstevel@tonic-gate /* 598a5f69788Scraigm * We need to grab the file locks or file corruption 599a5f69788Scraigm * will happen. But we first check the flags field 600a5f69788Scraigm * knowing that when it is 0, it isn't allocated and 601a5f69788Scraigm * cannot be allocated while we're holding the 602a5f69788Scraigm * _first_link_lock. And when _IONBF is set (also the 603a5f69788Scraigm * case when _flag is 0377, or alloc in progress), we 604a5f69788Scraigm * also ignore it. 605a5f69788Scraigm * 606a5f69788Scraigm * Ignore locked streams; it will appear as if 607a5f69788Scraigm * concurrent updates happened after fflush(NULL). Note 608a5f69788Scraigm * that we even attempt to lock if the locking is set to 609a5f69788Scraigm * "by caller". We don't want to penalize callers of 610a5f69788Scraigm * __fsetlocking() by not flushing their files. Note: if 611a5f69788Scraigm * __fsetlocking() callers don't employ any locking, they 612a5f69788Scraigm * may still face corruption in fflush(NULL); but that's 613a5f69788Scraigm * no change from earlier releases. 6147c478bd9Sstevel@tonic-gate */ 6157c478bd9Sstevel@tonic-gate FIRSTFP(lp, iop); 6167c478bd9Sstevel@tonic-gate for (i = lp->niob; --i >= 0; NEXTFP(iop)) { 617a5f69788Scraigm unsigned int flag = iop->_flag; 618a5f69788Scraigm 619a5f69788Scraigm /* flag 0, flag 0377, or _IONBF set */ 620a5f69788Scraigm if (flag == 0 || (flag & _IONBF) != 0) 621a5f69788Scraigm continue; 622a5f69788Scraigm 623a5f69788Scraigm if (threaded) { 624a5f69788Scraigm lk = FPLOCK(iop); 625a574db85Sraf if (cancel_safe_mutex_trylock(lk) != 0) 626a5f69788Scraigm continue; 627a5f69788Scraigm } 628a5f69788Scraigm 6297c478bd9Sstevel@tonic-gate if (!(iop->_flag & _IONBF)) { 6307c478bd9Sstevel@tonic-gate /* 6317c478bd9Sstevel@tonic-gate * don't need to worry about the _IORW case 6327c478bd9Sstevel@tonic-gate * since the iop will also marked with _IOREAD 6337c478bd9Sstevel@tonic-gate * or _IOWRT whichever we are really doing 6347c478bd9Sstevel@tonic-gate */ 635a5f69788Scraigm if (iop->_flag & _IOWRT) { 636a5f69788Scraigm /* Flush write buffers */ 6377c478bd9Sstevel@tonic-gate res |= _fflush_u(iop); 6387c478bd9Sstevel@tonic-gate } else if (iop->_flag & _IOREAD) { 6397c478bd9Sstevel@tonic-gate /* 6407c478bd9Sstevel@tonic-gate * flush seekable read buffers 6417c478bd9Sstevel@tonic-gate * don't flush non-seekable read buffers 6427c478bd9Sstevel@tonic-gate */ 6437c478bd9Sstevel@tonic-gate if (GET_SEEKABLE(iop)) { 6447c478bd9Sstevel@tonic-gate res |= _fflush_u(iop); 6457c478bd9Sstevel@tonic-gate } 6467c478bd9Sstevel@tonic-gate } 6477c478bd9Sstevel@tonic-gate } 648a5f69788Scraigm if (threaded) 649a574db85Sraf cancel_safe_mutex_unlock(lk); 6507c478bd9Sstevel@tonic-gate } 6517c478bd9Sstevel@tonic-gate } while ((lp = lp->next) != NULL); 652a5f69788Scraigm if (threaded) 653a574db85Sraf cancel_safe_mutex_unlock(&_first_link_lock); 6547c478bd9Sstevel@tonic-gate return (res); 6557c478bd9Sstevel@tonic-gate } 6567c478bd9Sstevel@tonic-gate 6577c478bd9Sstevel@tonic-gate /* flush buffer */ 6587c478bd9Sstevel@tonic-gate int 6597c478bd9Sstevel@tonic-gate _fflush_u(FILE *iop) 6607c478bd9Sstevel@tonic-gate { 6617c478bd9Sstevel@tonic-gate int res = 0; 6627c478bd9Sstevel@tonic-gate 6637c478bd9Sstevel@tonic-gate /* this portion is always assumed locked */ 6647c478bd9Sstevel@tonic-gate if (!(iop->_flag & _IOWRT)) { 665a5f69788Scraigm (void) lseek64(GET_FD(iop), -iop->_cnt, SEEK_CUR); 6667c478bd9Sstevel@tonic-gate iop->_cnt = 0; 6677c478bd9Sstevel@tonic-gate /* needed for ungetc & multibyte pushbacks */ 6687c478bd9Sstevel@tonic-gate iop->_ptr = iop->_base; 6697c478bd9Sstevel@tonic-gate if (iop->_flag & _IORW) { 6707c478bd9Sstevel@tonic-gate iop->_flag &= ~_IOREAD; 6717c478bd9Sstevel@tonic-gate } 6727c478bd9Sstevel@tonic-gate return (0); 6737c478bd9Sstevel@tonic-gate } 6747c478bd9Sstevel@tonic-gate if (iop->_base != NULL && iop->_ptr > iop->_base) { 6757c478bd9Sstevel@tonic-gate res = _xflsbuf(iop); 6767c478bd9Sstevel@tonic-gate } 6777c478bd9Sstevel@tonic-gate if (iop->_flag & _IORW) { 6787c478bd9Sstevel@tonic-gate iop->_flag &= ~_IOWRT; 6797c478bd9Sstevel@tonic-gate iop->_cnt = 0; 6807c478bd9Sstevel@tonic-gate } 6817c478bd9Sstevel@tonic-gate return (res); 6827c478bd9Sstevel@tonic-gate } 6837c478bd9Sstevel@tonic-gate 6847c478bd9Sstevel@tonic-gate /* flush buffer and close stream */ 6857c478bd9Sstevel@tonic-gate int 6867c478bd9Sstevel@tonic-gate fclose(FILE *iop) 6877c478bd9Sstevel@tonic-gate { 6887c478bd9Sstevel@tonic-gate int res = 0; 6897c478bd9Sstevel@tonic-gate rmutex_t *lk; 6907c478bd9Sstevel@tonic-gate 6917c478bd9Sstevel@tonic-gate if (iop == NULL) { 6927c478bd9Sstevel@tonic-gate return (EOF); /* avoid passing zero to FLOCKFILE */ 6937c478bd9Sstevel@tonic-gate } 6947c478bd9Sstevel@tonic-gate 6957c478bd9Sstevel@tonic-gate FLOCKFILE(lk, iop); 6967c478bd9Sstevel@tonic-gate if (iop->_flag == 0) { 6977c478bd9Sstevel@tonic-gate FUNLOCKFILE(lk); 6987c478bd9Sstevel@tonic-gate return (EOF); 6997c478bd9Sstevel@tonic-gate } 7007c478bd9Sstevel@tonic-gate /* Is not unbuffered and opened for read and/or write ? */ 7017c478bd9Sstevel@tonic-gate if (!(iop->_flag & _IONBF) && (iop->_flag & (_IOWRT | _IOREAD | _IORW))) 7027c478bd9Sstevel@tonic-gate res = _fflush_u(iop); 703a5f69788Scraigm if (close(GET_FD(iop)) < 0) 7047c478bd9Sstevel@tonic-gate res = EOF; 7057c478bd9Sstevel@tonic-gate if (iop->_flag & _IOMYBUF) { 7067c478bd9Sstevel@tonic-gate (void) free((char *)iop->_base - PUSHBACK); 7077c478bd9Sstevel@tonic-gate } 7087c478bd9Sstevel@tonic-gate iop->_base = NULL; 7097c478bd9Sstevel@tonic-gate iop->_ptr = NULL; 7107c478bd9Sstevel@tonic-gate iop->_cnt = 0; 7117c478bd9Sstevel@tonic-gate iop->_flag = 0; /* marks it as available */ 7127c478bd9Sstevel@tonic-gate FUNLOCKFILE(lk); 7137c478bd9Sstevel@tonic-gate 7141d2738a5Sraf if (__libc_threaded) 715a574db85Sraf cancel_safe_mutex_lock(&_first_link_lock); 7167c478bd9Sstevel@tonic-gate fcloses++; 7171d2738a5Sraf if (__libc_threaded) 718a574db85Sraf cancel_safe_mutex_unlock(&_first_link_lock); 7197c478bd9Sstevel@tonic-gate 7207c478bd9Sstevel@tonic-gate return (res); 7217c478bd9Sstevel@tonic-gate } 7227c478bd9Sstevel@tonic-gate 723*23a1cceaSRoger A. Faulkner /* close all open streams */ 724*23a1cceaSRoger A. Faulkner int 725*23a1cceaSRoger A. Faulkner fcloseall(void) 726*23a1cceaSRoger A. Faulkner { 727*23a1cceaSRoger A. Faulkner FPDECL(iop); 728*23a1cceaSRoger A. Faulkner 729*23a1cceaSRoger A. Faulkner struct _link_ *lp; 730*23a1cceaSRoger A. Faulkner rmutex_t *lk; 731*23a1cceaSRoger A. Faulkner 732*23a1cceaSRoger A. Faulkner if (__libc_threaded) 733*23a1cceaSRoger A. Faulkner cancel_safe_mutex_lock(&_first_link_lock); 734*23a1cceaSRoger A. Faulkner 735*23a1cceaSRoger A. Faulkner lp = &__first_link; 736*23a1cceaSRoger A. Faulkner 737*23a1cceaSRoger A. Faulkner do { 738*23a1cceaSRoger A. Faulkner int i; 739*23a1cceaSRoger A. Faulkner 740*23a1cceaSRoger A. Faulkner FIRSTFP(lp, iop); 741*23a1cceaSRoger A. Faulkner for (i = lp->niob; --i >= 0; NEXTFP(iop)) { 742*23a1cceaSRoger A. Faulkner /* code stolen from fclose(), above */ 743*23a1cceaSRoger A. Faulkner 744*23a1cceaSRoger A. Faulkner FLOCKFILE(lk, iop); 745*23a1cceaSRoger A. Faulkner if (iop->_flag == 0) { 746*23a1cceaSRoger A. Faulkner FUNLOCKFILE(lk); 747*23a1cceaSRoger A. Faulkner continue; 748*23a1cceaSRoger A. Faulkner } 749*23a1cceaSRoger A. Faulkner 750*23a1cceaSRoger A. Faulkner /* Not unbuffered and opened for read and/or write? */ 751*23a1cceaSRoger A. Faulkner if (!(iop->_flag & _IONBF) && 752*23a1cceaSRoger A. Faulkner (iop->_flag & (_IOWRT | _IOREAD | _IORW))) 753*23a1cceaSRoger A. Faulkner (void) _fflush_u(iop); 754*23a1cceaSRoger A. Faulkner (void) close(GET_FD(iop)); 755*23a1cceaSRoger A. Faulkner if (iop->_flag & _IOMYBUF) 756*23a1cceaSRoger A. Faulkner free((char *)iop->_base - PUSHBACK); 757*23a1cceaSRoger A. Faulkner iop->_base = NULL; 758*23a1cceaSRoger A. Faulkner iop->_ptr = NULL; 759*23a1cceaSRoger A. Faulkner iop->_cnt = 0; 760*23a1cceaSRoger A. Faulkner iop->_flag = 0; /* marks it as available */ 761*23a1cceaSRoger A. Faulkner FUNLOCKFILE(lk); 762*23a1cceaSRoger A. Faulkner fcloses++; 763*23a1cceaSRoger A. Faulkner } 764*23a1cceaSRoger A. Faulkner } while ((lp = lp->next) != NULL); 765*23a1cceaSRoger A. Faulkner 766*23a1cceaSRoger A. Faulkner if (__libc_threaded) 767*23a1cceaSRoger A. Faulkner cancel_safe_mutex_unlock(&_first_link_lock); 768*23a1cceaSRoger A. Faulkner 769*23a1cceaSRoger A. Faulkner return (0); 770*23a1cceaSRoger A. Faulkner } 771*23a1cceaSRoger A. Faulkner 7727c478bd9Sstevel@tonic-gate /* flush buffer, close fd but keep the stream used by freopen() */ 7737c478bd9Sstevel@tonic-gate int 7747c478bd9Sstevel@tonic-gate close_fd(FILE *iop) 7757c478bd9Sstevel@tonic-gate { 7767c478bd9Sstevel@tonic-gate int res = 0; 7777c478bd9Sstevel@tonic-gate mbstate_t *mb; 7787c478bd9Sstevel@tonic-gate 7797c478bd9Sstevel@tonic-gate if (iop == NULL || iop->_flag == 0) 7807c478bd9Sstevel@tonic-gate return (EOF); 7817c478bd9Sstevel@tonic-gate /* Is not unbuffered and opened for read and/or write ? */ 7827c478bd9Sstevel@tonic-gate if (!(iop->_flag & _IONBF) && (iop->_flag & (_IOWRT | _IOREAD | _IORW))) 7837c478bd9Sstevel@tonic-gate res = _fflush_u(iop); 784a5f69788Scraigm if (close(GET_FD(iop)) < 0) 7857c478bd9Sstevel@tonic-gate res = EOF; 7867c478bd9Sstevel@tonic-gate if (iop->_flag & _IOMYBUF) { 7877c478bd9Sstevel@tonic-gate (void) free((char *)iop->_base - PUSHBACK); 7887c478bd9Sstevel@tonic-gate } 7897c478bd9Sstevel@tonic-gate iop->_base = NULL; 7907c478bd9Sstevel@tonic-gate iop->_ptr = NULL; 7917c478bd9Sstevel@tonic-gate mb = _getmbstate(iop); 7927c478bd9Sstevel@tonic-gate if (mb != NULL) 7937c478bd9Sstevel@tonic-gate (void) memset(mb, 0, sizeof (mbstate_t)); 7947c478bd9Sstevel@tonic-gate iop->_cnt = 0; 7957c478bd9Sstevel@tonic-gate _setorientation(iop, _NO_MODE); 7967c478bd9Sstevel@tonic-gate return (res); 7977c478bd9Sstevel@tonic-gate } 7987c478bd9Sstevel@tonic-gate 7997c478bd9Sstevel@tonic-gate static FILE * 8007c478bd9Sstevel@tonic-gate getiop(FILE *fp, rmutex_t *lk, mbstate_t *mb) 8017c478bd9Sstevel@tonic-gate { 802a574db85Sraf if (lk != NULL && cancel_safe_mutex_trylock(lk) != 0) 8037c478bd9Sstevel@tonic-gate return (NULL); /* locked: fp in use */ 8047c478bd9Sstevel@tonic-gate 8057c478bd9Sstevel@tonic-gate if (fp->_flag == 0) { /* unused */ 8067c478bd9Sstevel@tonic-gate #ifndef _LP64 8077c478bd9Sstevel@tonic-gate fp->__orientation = 0; 8087c478bd9Sstevel@tonic-gate #endif /* _LP64 */ 8097c478bd9Sstevel@tonic-gate fp->_cnt = 0; 8107c478bd9Sstevel@tonic-gate fp->_ptr = NULL; 8117c478bd9Sstevel@tonic-gate fp->_base = NULL; 8127c478bd9Sstevel@tonic-gate fp->_flag = 0377; /* claim the fp by setting low 8 bits */ 8137c478bd9Sstevel@tonic-gate (void) memset(mb, 0, sizeof (mbstate_t)); 8147c478bd9Sstevel@tonic-gate FUNLOCKFILE(lk); 8157c478bd9Sstevel@tonic-gate return (fp); 8167c478bd9Sstevel@tonic-gate } 8177c478bd9Sstevel@tonic-gate FUNLOCKFILE(lk); 8187c478bd9Sstevel@tonic-gate return (NULL); 8197c478bd9Sstevel@tonic-gate } 8207c478bd9Sstevel@tonic-gate 8217c478bd9Sstevel@tonic-gate #ifndef _LP64 8227c478bd9Sstevel@tonic-gate /* 8237c478bd9Sstevel@tonic-gate * DESCRIPTION: 8247c478bd9Sstevel@tonic-gate * This function gets the pointer to the mbstate_t structure associated 8257c478bd9Sstevel@tonic-gate * with the specified iop. 8267c478bd9Sstevel@tonic-gate * 8277c478bd9Sstevel@tonic-gate * RETURNS: 8287c478bd9Sstevel@tonic-gate * If the associated mbstate_t found, the pointer to the mbstate_t is 8297c478bd9Sstevel@tonic-gate * returned. Otherwise, NULL is returned. 8307c478bd9Sstevel@tonic-gate */ 8317c478bd9Sstevel@tonic-gate mbstate_t * 8327c478bd9Sstevel@tonic-gate _getmbstate(FILE *iop) 8337c478bd9Sstevel@tonic-gate { 8347c478bd9Sstevel@tonic-gate struct xFILEdata *dat = getxfdat(iop); 8357c478bd9Sstevel@tonic-gate 8367c478bd9Sstevel@tonic-gate if (dat != NULL) 8377c478bd9Sstevel@tonic-gate return (&dat->_state); 8387c478bd9Sstevel@tonic-gate 8397c478bd9Sstevel@tonic-gate return (NULL); 8407c478bd9Sstevel@tonic-gate } 841a5f69788Scraigm 842a5f69788Scraigm /* 843a5f69788Scraigm * More 32-bit only functions. 844a5f69788Scraigm * They lookup/set large fd's for extended FILE support. 845a5f69788Scraigm */ 846a5f69788Scraigm 847a5f69788Scraigm /* 848a5f69788Scraigm * The negative value indicates that Extended fd FILE's has not 849a5f69788Scraigm * been enabled by the user. 850a5f69788Scraigm */ 851a5f69788Scraigm static int bad_fd = -1; 852a5f69788Scraigm 853a5f69788Scraigm int 854a5f69788Scraigm _file_get(FILE *iop) 855a5f69788Scraigm { 856a5f69788Scraigm int altfd; 857a5f69788Scraigm 858a5f69788Scraigm /* 859a5f69788Scraigm * Failure indicates a FILE * not allocated through stdio; 860a5f69788Scraigm * it means the flag values are probably bogus and that if 861a5f69788Scraigm * a file descriptor is set, it's in _magic. 862a5f69788Scraigm * Inline getxfdat() for performance reasons. 863a5f69788Scraigm */ 864a5f69788Scraigm if (STDIOP(iop)) 865a5f69788Scraigm altfd = _xftab[IOPIND(iop)]._altfd; 866a5f69788Scraigm else if (VALIDXFILE(FILEx(iop))) 867a5f69788Scraigm altfd = FILEx(iop)->_xdat._altfd; 868a5f69788Scraigm else 869a5f69788Scraigm return (iop->_magic); 870a5f69788Scraigm /* 871a5f69788Scraigm * if this is not an internal extended FILE then check 872a5f69788Scraigm * if _file is being changed from underneath us. 873a5f69788Scraigm * It should not be because if 874a5f69788Scraigm * it is then then we lose our ability to guard against 875a5f69788Scraigm * silent data corruption. 876a5f69788Scraigm */ 877a5f69788Scraigm if (!iop->__xf_nocheck && bad_fd > -1 && iop->_magic != bad_fd) { 878e1d65dbdScraigm (void) fprintf(stderr, 879a5f69788Scraigm "Application violated extended FILE safety mechanism.\n" 880e1d65dbdScraigm "Please read the man page for extendedFILE.\nAborting\n"); 881a5f69788Scraigm abort(); 882a5f69788Scraigm } 883a5f69788Scraigm return (altfd); 884a5f69788Scraigm } 885a5f69788Scraigm 886a5f69788Scraigm int 887a5f69788Scraigm _file_set(FILE *iop, int fd, const char *type) 888a5f69788Scraigm { 889a5f69788Scraigm struct xFILEdata *dat; 890a5f69788Scraigm int Fflag; 891a5f69788Scraigm 892a5f69788Scraigm /* Already known to contain at least one byte */ 893a5f69788Scraigm while (*++type != '\0') 894a5f69788Scraigm ; 895a5f69788Scraigm 896a5f69788Scraigm Fflag = type[-1] == 'F'; 897a5f69788Scraigm if (!Fflag && bad_fd < 0) { 898a5f69788Scraigm errno = EMFILE; 899a5f69788Scraigm return (-1); 900a5f69788Scraigm } 901a5f69788Scraigm 902a5f69788Scraigm dat = getxfdat(iop); 903a5f69788Scraigm iop->__extendedfd = 1; 904a5f69788Scraigm iop->__xf_nocheck = Fflag; 905a5f69788Scraigm dat->_altfd = fd; 906a5f69788Scraigm iop->_magic = (unsigned char)bad_fd; 907a5f69788Scraigm return (0); 908a5f69788Scraigm } 909a5f69788Scraigm 910a5f69788Scraigm /* 911a5f69788Scraigm * Activates extended fd's in FILE's 912a5f69788Scraigm */ 913a5f69788Scraigm 914a5f69788Scraigm static const int tries[] = {196, 120, 60, 3}; 915a5f69788Scraigm #define NTRIES (sizeof (tries)/sizeof (int)) 916a5f69788Scraigm 917a5f69788Scraigm int 918a5f69788Scraigm enable_extended_FILE_stdio(int fd, int action) 919a5f69788Scraigm { 920a5f69788Scraigm int i; 921a5f69788Scraigm 922a5f69788Scraigm if (action < 0) 923a5f69788Scraigm action = SIGABRT; /* default signal */ 924a5f69788Scraigm 925a5f69788Scraigm if (fd < 0) { 926a5f69788Scraigm /* 927a5f69788Scraigm * search for an available fd and make it the badfd 928a5f69788Scraigm */ 929a5f69788Scraigm for (i = 0; i < NTRIES; i++) { 930a5f69788Scraigm fd = fcntl(tries[i], F_BADFD, action); 931a5f69788Scraigm if (fd >= 0) 932a5f69788Scraigm break; 933a5f69788Scraigm } 934a5f69788Scraigm if (fd < 0) /* failed to find an available fd */ 935a5f69788Scraigm return (-1); 936a5f69788Scraigm } else { 937a5f69788Scraigm /* caller requests that fd be the chosen badfd */ 938a5f69788Scraigm int nfd = fcntl(fd, F_BADFD, action); 939a5f69788Scraigm if (nfd < 0 || nfd != fd) 940a5f69788Scraigm return (-1); 941a5f69788Scraigm } 942a5f69788Scraigm bad_fd = fd; 943a5f69788Scraigm return (0); 944a5f69788Scraigm } 9457c478bd9Sstevel@tonic-gate #endif 946