1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate /* Copyright (c) 1988 AT&T */ 30*0Sstevel@tonic-gate /* All Rights Reserved */ 31*0Sstevel@tonic-gate 32*0Sstevel@tonic-gate 33*0Sstevel@tonic-gate #include "synonyms.h" 34*0Sstevel@tonic-gate #include "mtlib.h" 35*0Sstevel@tonic-gate #include "file64.h" 36*0Sstevel@tonic-gate 37*0Sstevel@tonic-gate #define _iob __iob 38*0Sstevel@tonic-gate 39*0Sstevel@tonic-gate #include <sys/types.h> 40*0Sstevel@tonic-gate #include <stdlib.h> 41*0Sstevel@tonic-gate #include <stdio.h> 42*0Sstevel@tonic-gate #include <thread.h> 43*0Sstevel@tonic-gate #include <synch.h> 44*0Sstevel@tonic-gate #include <unistd.h> 45*0Sstevel@tonic-gate #include <string.h> 46*0Sstevel@tonic-gate #include "stdiom.h" 47*0Sstevel@tonic-gate #include <wchar.h> 48*0Sstevel@tonic-gate #include <sys/stat.h> 49*0Sstevel@tonic-gate #include <stddef.h> 50*0Sstevel@tonic-gate #include <errno.h> 51*0Sstevel@tonic-gate 52*0Sstevel@tonic-gate #undef end 53*0Sstevel@tonic-gate 54*0Sstevel@tonic-gate #define FILE_ARY_SZ 8 /* a nice size for FILE array & end_buffer_ptrs */ 55*0Sstevel@tonic-gate 56*0Sstevel@tonic-gate #ifdef _LP64 57*0Sstevel@tonic-gate 58*0Sstevel@tonic-gate /* 59*0Sstevel@tonic-gate * Macros to declare and loop over a fp or fp/xfp combo to 60*0Sstevel@tonic-gate * avoid some of the _LP64 ifdef hell. 61*0Sstevel@tonic-gate */ 62*0Sstevel@tonic-gate 63*0Sstevel@tonic-gate #define FPDECL(fp) FILE *fp 64*0Sstevel@tonic-gate #define FIRSTFP(lp, fp) fp = lp->iobp 65*0Sstevel@tonic-gate #define NEXTFP(fp) fp++ 66*0Sstevel@tonic-gate 67*0Sstevel@tonic-gate #define xFILE FILE 68*0Sstevel@tonic-gate 69*0Sstevel@tonic-gate #else 70*0Sstevel@tonic-gate 71*0Sstevel@tonic-gate #define FPDECL(fp) FILE *fp; xFILE *x##fp 72*0Sstevel@tonic-gate #define FIRSTFP(lp, fp) x##fp = lp->iobp; \ 73*0Sstevel@tonic-gate fp = x##fp ? &x##fp->_iob : &_iob[0] 74*0Sstevel@tonic-gate #define NEXTFP(fp) (x##fp ? fp = &(++x##fp)->_iob : ++fp) 75*0Sstevel@tonic-gate 76*0Sstevel@tonic-gate /* The extended 32-bit file structure for use in link buffers */ 77*0Sstevel@tonic-gate typedef struct xFILE { 78*0Sstevel@tonic-gate FILE _iob; /* must be first! */ 79*0Sstevel@tonic-gate struct xFILEdata _xdat; 80*0Sstevel@tonic-gate } xFILE; 81*0Sstevel@tonic-gate 82*0Sstevel@tonic-gate #define xmagic _xdat._magic 83*0Sstevel@tonic-gate #define xend _xdat._end 84*0Sstevel@tonic-gate #define xlock _xdat._lock 85*0Sstevel@tonic-gate #define xstate _xdat._state 86*0Sstevel@tonic-gate 87*0Sstevel@tonic-gate #define FILEx(fp) ((struct xFILE *)(uintptr_t)fp) 88*0Sstevel@tonic-gate 89*0Sstevel@tonic-gate /* 90*0Sstevel@tonic-gate * The magic number stored is actually the pointer scrambled with 91*0Sstevel@tonic-gate * a magic number. Pointers to data items live everywhere in memory 92*0Sstevel@tonic-gate * so we scramble the pointer in order to avoid accidental collisions. 93*0Sstevel@tonic-gate */ 94*0Sstevel@tonic-gate #define XFILEMAGIC 0x63687367 95*0Sstevel@tonic-gate #define XMAGIC(xfp) ((uintptr_t)(xfp) ^ XFILEMAGIC) 96*0Sstevel@tonic-gate 97*0Sstevel@tonic-gate #endif /* _LP64 */ 98*0Sstevel@tonic-gate 99*0Sstevel@tonic-gate struct _link_ /* manages a list of streams */ 100*0Sstevel@tonic-gate { 101*0Sstevel@tonic-gate xFILE *iobp; /* the array of (x)FILE's */ 102*0Sstevel@tonic-gate /* NULL for the __first_link in ILP32 */ 103*0Sstevel@tonic-gate int niob; /* length of the arrays */ 104*0Sstevel@tonic-gate struct _link_ *next; /* next in the list */ 105*0Sstevel@tonic-gate }; 106*0Sstevel@tonic-gate 107*0Sstevel@tonic-gate /* 108*0Sstevel@tonic-gate * With dynamic linking, iob may be in either the library or in the user's 109*0Sstevel@tonic-gate * a.out, so the run time linker fixes up the first entry in __first_link at 110*0Sstevel@tonic-gate * process startup time. 111*0Sstevel@tonic-gate * 112*0Sstevel@tonic-gate * In 32 bit processes, we don't have xFILE[FILE_ARY_SZ] but FILE[], 113*0Sstevel@tonic-gate * and _xftab[] instead; this is denoted by having iobp set to NULL in 114*0Sstevel@tonic-gate * 32 bit mode for the first link entry. 115*0Sstevel@tonic-gate */ 116*0Sstevel@tonic-gate struct _link_ __first_link = /* first in linked list */ 117*0Sstevel@tonic-gate { 118*0Sstevel@tonic-gate #if !defined(_LP64) 119*0Sstevel@tonic-gate NULL, 120*0Sstevel@tonic-gate #else 121*0Sstevel@tonic-gate &_iob[0], 122*0Sstevel@tonic-gate #endif 123*0Sstevel@tonic-gate _NFILE, 124*0Sstevel@tonic-gate NULL 125*0Sstevel@tonic-gate }; 126*0Sstevel@tonic-gate 127*0Sstevel@tonic-gate /* 128*0Sstevel@tonic-gate * Information cached to speed up searches. We remember where we 129*0Sstevel@tonic-gate * last found a free FILE* and we remember whether we saw any fcloses 130*0Sstevel@tonic-gate * in between. We also count the number of chunks we allocated, see 131*0Sstevel@tonic-gate * _findiop() for an explanation. 132*0Sstevel@tonic-gate * These variables are all protected by _first_link_lock. 133*0Sstevel@tonic-gate */ 134*0Sstevel@tonic-gate static struct _link_ *lastlink = NULL; 135*0Sstevel@tonic-gate static int fcloses; 136*0Sstevel@tonic-gate static int nchunks; 137*0Sstevel@tonic-gate 138*0Sstevel@tonic-gate static rwlock_t _first_link_lock = DEFAULTRWLOCK; 139*0Sstevel@tonic-gate 140*0Sstevel@tonic-gate static int _fflush_u_iops(void); 141*0Sstevel@tonic-gate static FILE *getiop(FILE *, rmutex_t *, mbstate_t *); 142*0Sstevel@tonic-gate 143*0Sstevel@tonic-gate #define GETIOP(fp, lk, mb) {FILE *ret; \ 144*0Sstevel@tonic-gate if ((ret = getiop((fp), __threaded ? (lk) : NULL, (mb))) != NULL) { \ 145*0Sstevel@tonic-gate if (__threaded) \ 146*0Sstevel@tonic-gate (void) __rw_unlock(&_first_link_lock); \ 147*0Sstevel@tonic-gate return (ret); \ 148*0Sstevel@tonic-gate }; \ 149*0Sstevel@tonic-gate } 150*0Sstevel@tonic-gate 151*0Sstevel@tonic-gate /* 152*0Sstevel@tonic-gate * All functions that understand the linked list of iob's follow. 153*0Sstevel@tonic-gate */ 154*0Sstevel@tonic-gate #pragma weak _cleanup = __cleanup 155*0Sstevel@tonic-gate void 156*0Sstevel@tonic-gate __cleanup(void) /* called at process end to flush ouput streams */ 157*0Sstevel@tonic-gate { 158*0Sstevel@tonic-gate (void) fflush(NULL); 159*0Sstevel@tonic-gate } 160*0Sstevel@tonic-gate 161*0Sstevel@tonic-gate /* 162*0Sstevel@tonic-gate * For fork1-safety (see libc_prepare_atfork(), etc). 163*0Sstevel@tonic-gate */ 164*0Sstevel@tonic-gate void 165*0Sstevel@tonic-gate stdio_locks() 166*0Sstevel@tonic-gate { 167*0Sstevel@tonic-gate (void) __rw_wrlock(&_first_link_lock); 168*0Sstevel@tonic-gate /* 169*0Sstevel@tonic-gate * XXX: We should acquire all of the iob locks here. 170*0Sstevel@tonic-gate */ 171*0Sstevel@tonic-gate } 172*0Sstevel@tonic-gate 173*0Sstevel@tonic-gate void 174*0Sstevel@tonic-gate stdio_unlocks() 175*0Sstevel@tonic-gate { 176*0Sstevel@tonic-gate /* 177*0Sstevel@tonic-gate * XXX: We should release all of the iob locks here. 178*0Sstevel@tonic-gate */ 179*0Sstevel@tonic-gate (void) __rw_unlock(&_first_link_lock); 180*0Sstevel@tonic-gate } 181*0Sstevel@tonic-gate 182*0Sstevel@tonic-gate void 183*0Sstevel@tonic-gate _flushlbf(void) /* fflush() all line-buffered streams */ 184*0Sstevel@tonic-gate { 185*0Sstevel@tonic-gate FPDECL(fp); 186*0Sstevel@tonic-gate int i; 187*0Sstevel@tonic-gate struct _link_ *lp; 188*0Sstevel@tonic-gate 189*0Sstevel@tonic-gate if (__threaded) 190*0Sstevel@tonic-gate (void) __rw_rdlock(&_first_link_lock); 191*0Sstevel@tonic-gate 192*0Sstevel@tonic-gate lp = &__first_link; 193*0Sstevel@tonic-gate do { 194*0Sstevel@tonic-gate FIRSTFP(lp, fp); 195*0Sstevel@tonic-gate for (i = lp->niob; --i >= 0; NEXTFP(fp)) { 196*0Sstevel@tonic-gate if ((fp->_flag & (_IOLBF | _IOWRT)) == 197*0Sstevel@tonic-gate (_IOLBF | _IOWRT)) 198*0Sstevel@tonic-gate (void) _fflush_u(fp); 199*0Sstevel@tonic-gate } 200*0Sstevel@tonic-gate } while ((lp = lp->next) != NULL); 201*0Sstevel@tonic-gate 202*0Sstevel@tonic-gate if (__threaded) 203*0Sstevel@tonic-gate (void) __rw_unlock(&_first_link_lock); 204*0Sstevel@tonic-gate } 205*0Sstevel@tonic-gate 206*0Sstevel@tonic-gate /* allocate an unused stream; NULL if cannot */ 207*0Sstevel@tonic-gate FILE * 208*0Sstevel@tonic-gate _findiop(void) 209*0Sstevel@tonic-gate { 210*0Sstevel@tonic-gate struct _link_ *lp, **prev; 211*0Sstevel@tonic-gate 212*0Sstevel@tonic-gate /* used so there only needs to be one malloc() */ 213*0Sstevel@tonic-gate #ifdef _LP64 214*0Sstevel@tonic-gate typedef struct { 215*0Sstevel@tonic-gate struct _link_ hdr; 216*0Sstevel@tonic-gate FILE iob[FILE_ARY_SZ]; 217*0Sstevel@tonic-gate } Pkg; 218*0Sstevel@tonic-gate #else 219*0Sstevel@tonic-gate typedef union { 220*0Sstevel@tonic-gate struct { /* Normal */ 221*0Sstevel@tonic-gate struct _link_ hdr; 222*0Sstevel@tonic-gate xFILE iob[FILE_ARY_SZ]; 223*0Sstevel@tonic-gate } Pkgn; 224*0Sstevel@tonic-gate struct { /* Reversed */ 225*0Sstevel@tonic-gate xFILE iob[FILE_ARY_SZ]; 226*0Sstevel@tonic-gate struct _link_ hdr; 227*0Sstevel@tonic-gate } Pkgr; 228*0Sstevel@tonic-gate } Pkg; 229*0Sstevel@tonic-gate uintptr_t delta; 230*0Sstevel@tonic-gate #endif 231*0Sstevel@tonic-gate Pkg *pkgp; 232*0Sstevel@tonic-gate struct _link_ *hdr; 233*0Sstevel@tonic-gate FPDECL(fp); 234*0Sstevel@tonic-gate int i; 235*0Sstevel@tonic-gate 236*0Sstevel@tonic-gate if (__threaded) 237*0Sstevel@tonic-gate (void) __rw_wrlock(&_first_link_lock); 238*0Sstevel@tonic-gate 239*0Sstevel@tonic-gate if (lastlink == NULL) { 240*0Sstevel@tonic-gate rescan: 241*0Sstevel@tonic-gate fcloses = 0; 242*0Sstevel@tonic-gate lastlink = &__first_link; 243*0Sstevel@tonic-gate } 244*0Sstevel@tonic-gate 245*0Sstevel@tonic-gate lp = lastlink; 246*0Sstevel@tonic-gate 247*0Sstevel@tonic-gate /* 248*0Sstevel@tonic-gate * lock to make testing of fp->_flag == 0 and acquiring the fp atomic 249*0Sstevel@tonic-gate * and for allocation of new links 250*0Sstevel@tonic-gate * low contention expected on _findiop(), hence coarse locking. 251*0Sstevel@tonic-gate * for finer granularity, use fp->_lock for allocating an iop 252*0Sstevel@tonic-gate * and make the testing of lp->next and allocation of new link atomic 253*0Sstevel@tonic-gate * using lp->_lock 254*0Sstevel@tonic-gate */ 255*0Sstevel@tonic-gate 256*0Sstevel@tonic-gate do { 257*0Sstevel@tonic-gate prev = &lp->next; 258*0Sstevel@tonic-gate FIRSTFP(lp, fp); 259*0Sstevel@tonic-gate 260*0Sstevel@tonic-gate for (i = lp->niob; --i >= 0; NEXTFP(fp)) { 261*0Sstevel@tonic-gate #ifdef _LP64 262*0Sstevel@tonic-gate GETIOP(fp, &fp->_lock, &fp->_state); 263*0Sstevel@tonic-gate #else 264*0Sstevel@tonic-gate GETIOP(fp, 265*0Sstevel@tonic-gate xfp ? &xfp->xlock : &_xftab[IOPIND(fp)]._lock, 266*0Sstevel@tonic-gate xfp ? &xfp->xstate : &_xftab[IOPIND(fp)]._state); 267*0Sstevel@tonic-gate #endif /* _LP64 */ 268*0Sstevel@tonic-gate } 269*0Sstevel@tonic-gate } while ((lastlink = lp = lp->next) != NULL); 270*0Sstevel@tonic-gate 271*0Sstevel@tonic-gate /* 272*0Sstevel@tonic-gate * If there was a sufficient number of fcloses since we last started 273*0Sstevel@tonic-gate * at __first_link, we rescan all fp's again. We do not rescan for 274*0Sstevel@tonic-gate * all fcloses; that would simplify the algorithm but would make 275*0Sstevel@tonic-gate * search times near O(n) again. 276*0Sstevel@tonic-gate * Worst case behaviour would still be pretty bad (open a full set, 277*0Sstevel@tonic-gate * then continously opening and closing one FILE * gets you a full 278*0Sstevel@tonic-gate * scan each time). That's why we over allocate 1 FILE for each 279*0Sstevel@tonic-gate * 32 chunks. More over allocation is better; this is a nice 280*0Sstevel@tonic-gate * empirical value which doesn't cost a lot of memory, doesn't 281*0Sstevel@tonic-gate * overallocate until we reach 256 FILE *s and keeps the performance 282*0Sstevel@tonic-gate * pretty close to the optimum. 283*0Sstevel@tonic-gate */ 284*0Sstevel@tonic-gate if (fcloses > nchunks/32) 285*0Sstevel@tonic-gate goto rescan; 286*0Sstevel@tonic-gate 287*0Sstevel@tonic-gate /* 288*0Sstevel@tonic-gate * Need to allocate another and put it in the linked list. 289*0Sstevel@tonic-gate */ 290*0Sstevel@tonic-gate if ((pkgp = malloc(sizeof (Pkg))) == NULL) { 291*0Sstevel@tonic-gate if (__threaded) 292*0Sstevel@tonic-gate (void) __rw_unlock(&_first_link_lock); 293*0Sstevel@tonic-gate return (NULL); 294*0Sstevel@tonic-gate } 295*0Sstevel@tonic-gate 296*0Sstevel@tonic-gate (void) memset(pkgp, 0, sizeof (Pkg)); 297*0Sstevel@tonic-gate 298*0Sstevel@tonic-gate #ifdef _LP64 299*0Sstevel@tonic-gate hdr = &pkgp->hdr; 300*0Sstevel@tonic-gate hdr->iobp = &pkgp->iob[0]; 301*0Sstevel@tonic-gate #else 302*0Sstevel@tonic-gate /* 303*0Sstevel@tonic-gate * The problem with referencing a word after a FILE* is the possibility 304*0Sstevel@tonic-gate * of a SIGSEGV if a non-stdio issue FILE structure ends on a page 305*0Sstevel@tonic-gate * boundary. We run this check so we never need to run an expensive 306*0Sstevel@tonic-gate * check like mincore() in order to know whether it is 307*0Sstevel@tonic-gate * safe to dereference ((xFILE*)fp)->xmagic. 308*0Sstevel@tonic-gate * We allocate the block with two alternative layouts; if one 309*0Sstevel@tonic-gate * layout is not properly aligned for our purposes, the other layout 310*0Sstevel@tonic-gate * will be because the size of _link_ is small compared to 311*0Sstevel@tonic-gate * sizeof (xFILE). 312*0Sstevel@tonic-gate * The check performed is this: 313*0Sstevel@tonic-gate * If the distance from pkgp to the end of the page is 314*0Sstevel@tonic-gate * less than the the offset of the last xmagic field in the 315*0Sstevel@tonic-gate * xFILE structure, (the 0x1000 boundary is inside our just 316*0Sstevel@tonic-gate * allocated structure) and the distance modulo the size of xFILE 317*0Sstevel@tonic-gate * is identical to the offset of the first xmagic in the 318*0Sstevel@tonic-gate * structure (i.e., XXXXXX000 points to an xmagic field), 319*0Sstevel@tonic-gate * we need to use the reverse structure. 320*0Sstevel@tonic-gate */ 321*0Sstevel@tonic-gate if ((delta = 0x1000 - ((uintptr_t)pkgp & 0xfff)) <= 322*0Sstevel@tonic-gate offsetof(Pkg, Pkgn.iob[FILE_ARY_SZ-1].xmagic) && 323*0Sstevel@tonic-gate delta % sizeof (struct xFILE) == 324*0Sstevel@tonic-gate offsetof(Pkg, Pkgn.iob[0].xmagic)) { 325*0Sstevel@tonic-gate /* Use reversed structure */ 326*0Sstevel@tonic-gate hdr = &pkgp->Pkgr.hdr; 327*0Sstevel@tonic-gate hdr->iobp = &pkgp->Pkgr.iob[0]; 328*0Sstevel@tonic-gate } else { 329*0Sstevel@tonic-gate /* Use normal structure */ 330*0Sstevel@tonic-gate hdr = &pkgp->Pkgn.hdr; 331*0Sstevel@tonic-gate hdr->iobp = &pkgp->Pkgn.iob[0]; 332*0Sstevel@tonic-gate } 333*0Sstevel@tonic-gate #endif /* _LP64 */ 334*0Sstevel@tonic-gate 335*0Sstevel@tonic-gate hdr->niob = FILE_ARY_SZ; 336*0Sstevel@tonic-gate nchunks++; 337*0Sstevel@tonic-gate 338*0Sstevel@tonic-gate #ifdef _LP64 339*0Sstevel@tonic-gate fp = hdr->iobp; 340*0Sstevel@tonic-gate for (i = 0; i < FILE_ARY_SZ; i++) 341*0Sstevel@tonic-gate _private_mutex_init(&fp[i]._lock, 342*0Sstevel@tonic-gate USYNC_THREAD|LOCK_RECURSIVE, NULL); 343*0Sstevel@tonic-gate #else 344*0Sstevel@tonic-gate xfp = hdr->iobp; 345*0Sstevel@tonic-gate fp = &xfp->_iob; 346*0Sstevel@tonic-gate 347*0Sstevel@tonic-gate for (i = 0; i < FILE_ARY_SZ; i++) { 348*0Sstevel@tonic-gate xfp[i].xmagic = XMAGIC(&xfp[i]); 349*0Sstevel@tonic-gate _private_mutex_init(&xfp[i].xlock, 350*0Sstevel@tonic-gate USYNC_THREAD|LOCK_RECURSIVE, NULL); 351*0Sstevel@tonic-gate } 352*0Sstevel@tonic-gate #endif /* _LP64 */ 353*0Sstevel@tonic-gate 354*0Sstevel@tonic-gate lastlink = *prev = hdr; 355*0Sstevel@tonic-gate fp->_ptr = 0; 356*0Sstevel@tonic-gate fp->_base = 0; 357*0Sstevel@tonic-gate fp->_flag = 0377; /* claim the fp by setting low 8 bits */ 358*0Sstevel@tonic-gate if (__threaded) 359*0Sstevel@tonic-gate (void) __rw_unlock(&_first_link_lock); 360*0Sstevel@tonic-gate 361*0Sstevel@tonic-gate return (fp); 362*0Sstevel@tonic-gate } 363*0Sstevel@tonic-gate 364*0Sstevel@tonic-gate static void 365*0Sstevel@tonic-gate isseekable(FILE *iop) 366*0Sstevel@tonic-gate { 367*0Sstevel@tonic-gate struct stat64 fstatbuf; 368*0Sstevel@tonic-gate int save_errno; 369*0Sstevel@tonic-gate 370*0Sstevel@tonic-gate save_errno = errno; 371*0Sstevel@tonic-gate 372*0Sstevel@tonic-gate if (fstat64(iop->_file, &fstatbuf) != 0) { 373*0Sstevel@tonic-gate /* 374*0Sstevel@tonic-gate * when we don't know what it is we'll 375*0Sstevel@tonic-gate * do the old behaviour and flush 376*0Sstevel@tonic-gate * the stream 377*0Sstevel@tonic-gate */ 378*0Sstevel@tonic-gate SET_SEEKABLE(iop); 379*0Sstevel@tonic-gate errno = save_errno; 380*0Sstevel@tonic-gate return; 381*0Sstevel@tonic-gate } 382*0Sstevel@tonic-gate 383*0Sstevel@tonic-gate /* 384*0Sstevel@tonic-gate * check for what is non-SEEKABLE 385*0Sstevel@tonic-gate * otherwise assume it's SEEKABLE so we get the old 386*0Sstevel@tonic-gate * behaviour and flush the stream 387*0Sstevel@tonic-gate */ 388*0Sstevel@tonic-gate 389*0Sstevel@tonic-gate if (S_ISFIFO(fstatbuf.st_mode) || S_ISCHR(fstatbuf.st_mode) || 390*0Sstevel@tonic-gate S_ISSOCK(fstatbuf.st_mode) || S_ISDOOR(fstatbuf.st_mode)) { 391*0Sstevel@tonic-gate CLEAR_SEEKABLE(iop); 392*0Sstevel@tonic-gate } else { 393*0Sstevel@tonic-gate SET_SEEKABLE(iop); 394*0Sstevel@tonic-gate } 395*0Sstevel@tonic-gate 396*0Sstevel@tonic-gate errno = save_errno; 397*0Sstevel@tonic-gate } 398*0Sstevel@tonic-gate 399*0Sstevel@tonic-gate #ifdef _LP64 400*0Sstevel@tonic-gate void 401*0Sstevel@tonic-gate _setbufend(FILE *iop, Uchar *end) /* set the end pointer for this iop */ 402*0Sstevel@tonic-gate { 403*0Sstevel@tonic-gate iop->_end = end; 404*0Sstevel@tonic-gate 405*0Sstevel@tonic-gate isseekable(iop); 406*0Sstevel@tonic-gate } 407*0Sstevel@tonic-gate 408*0Sstevel@tonic-gate #undef _realbufend 409*0Sstevel@tonic-gate 410*0Sstevel@tonic-gate Uchar * 411*0Sstevel@tonic-gate _realbufend(FILE *iop) /* get the end pointer for this iop */ 412*0Sstevel@tonic-gate { 413*0Sstevel@tonic-gate return (iop->_end); 414*0Sstevel@tonic-gate } 415*0Sstevel@tonic-gate 416*0Sstevel@tonic-gate #else /* _LP64 */ 417*0Sstevel@tonic-gate 418*0Sstevel@tonic-gate /* 419*0Sstevel@tonic-gate * Awkward functions not needed for the sane 64 bit environment. 420*0Sstevel@tonic-gate */ 421*0Sstevel@tonic-gate /* 422*0Sstevel@tonic-gate * xmagic must not be aligned on a 4K boundary. We guarantee this in 423*0Sstevel@tonic-gate * _findiop(). 424*0Sstevel@tonic-gate */ 425*0Sstevel@tonic-gate #define VALIDXFILE(xfp) \ 426*0Sstevel@tonic-gate (((uintptr_t)&(xfp)->xmagic & 0xfff) && \ 427*0Sstevel@tonic-gate (xfp)->xmagic == XMAGIC(FILEx(xfp))) 428*0Sstevel@tonic-gate 429*0Sstevel@tonic-gate static struct xFILEdata * 430*0Sstevel@tonic-gate getxfdat(FILE *iop) 431*0Sstevel@tonic-gate { 432*0Sstevel@tonic-gate if (STDIOP(iop)) 433*0Sstevel@tonic-gate return (&_xftab[IOPIND(iop)]); 434*0Sstevel@tonic-gate else if (VALIDXFILE(FILEx(iop))) 435*0Sstevel@tonic-gate return (&FILEx(iop)->_xdat); 436*0Sstevel@tonic-gate else 437*0Sstevel@tonic-gate return (NULL); 438*0Sstevel@tonic-gate } 439*0Sstevel@tonic-gate 440*0Sstevel@tonic-gate void 441*0Sstevel@tonic-gate _setbufend(FILE *iop, Uchar *end) /* set the end pointer for this iop */ 442*0Sstevel@tonic-gate { 443*0Sstevel@tonic-gate struct xFILEdata *dat = getxfdat(iop); 444*0Sstevel@tonic-gate 445*0Sstevel@tonic-gate if (dat != NULL) 446*0Sstevel@tonic-gate dat->_end = end; 447*0Sstevel@tonic-gate 448*0Sstevel@tonic-gate isseekable(iop); 449*0Sstevel@tonic-gate 450*0Sstevel@tonic-gate /* 451*0Sstevel@tonic-gate * For binary compatibility with user programs using the 452*0Sstevel@tonic-gate * old _bufend macro. This is *so* broken, fileno() 453*0Sstevel@tonic-gate * is not the proper index. 454*0Sstevel@tonic-gate */ 455*0Sstevel@tonic-gate if (iop->_file < _NFILE) 456*0Sstevel@tonic-gate _bufendtab[iop->_file] = end; 457*0Sstevel@tonic-gate 458*0Sstevel@tonic-gate } 459*0Sstevel@tonic-gate 460*0Sstevel@tonic-gate Uchar * 461*0Sstevel@tonic-gate _realbufend(FILE *iop) /* get the end pointer for this iop */ 462*0Sstevel@tonic-gate { 463*0Sstevel@tonic-gate struct xFILEdata *dat = getxfdat(iop); 464*0Sstevel@tonic-gate 465*0Sstevel@tonic-gate if (dat != NULL) 466*0Sstevel@tonic-gate return (dat->_end); 467*0Sstevel@tonic-gate 468*0Sstevel@tonic-gate return (NULL); 469*0Sstevel@tonic-gate } 470*0Sstevel@tonic-gate 471*0Sstevel@tonic-gate /* 472*0Sstevel@tonic-gate * _reallock() is invoked in each stdio call through the IOB_LCK() macro, 473*0Sstevel@tonic-gate * it is therefor extremely performance sensitive. We get better performance 474*0Sstevel@tonic-gate * by inlining the STDIOP check in IOB_LCK and inlining a custom version 475*0Sstevel@tonic-gate * of getfxdat() here. 476*0Sstevel@tonic-gate */ 477*0Sstevel@tonic-gate rmutex_t * 478*0Sstevel@tonic-gate _reallock(FILE *iop) 479*0Sstevel@tonic-gate { 480*0Sstevel@tonic-gate if (VALIDXFILE(FILEx(iop))) 481*0Sstevel@tonic-gate return (&FILEx(iop)->xlock); 482*0Sstevel@tonic-gate 483*0Sstevel@tonic-gate return (NULL); 484*0Sstevel@tonic-gate } 485*0Sstevel@tonic-gate 486*0Sstevel@tonic-gate #endif /* _LP64 */ 487*0Sstevel@tonic-gate 488*0Sstevel@tonic-gate /* make sure _cnt, _ptr are correct */ 489*0Sstevel@tonic-gate void 490*0Sstevel@tonic-gate _bufsync(FILE *iop, Uchar *bufend) 491*0Sstevel@tonic-gate { 492*0Sstevel@tonic-gate ssize_t spaceleft; 493*0Sstevel@tonic-gate 494*0Sstevel@tonic-gate spaceleft = bufend - iop->_ptr; 495*0Sstevel@tonic-gate if (bufend < iop->_ptr) { 496*0Sstevel@tonic-gate iop->_ptr = bufend; 497*0Sstevel@tonic-gate iop->_cnt = 0; 498*0Sstevel@tonic-gate } else if (spaceleft < iop->_cnt) 499*0Sstevel@tonic-gate iop->_cnt = spaceleft; 500*0Sstevel@tonic-gate } 501*0Sstevel@tonic-gate 502*0Sstevel@tonic-gate /* really write out current buffer contents */ 503*0Sstevel@tonic-gate int 504*0Sstevel@tonic-gate _xflsbuf(FILE *iop) 505*0Sstevel@tonic-gate { 506*0Sstevel@tonic-gate ssize_t n; 507*0Sstevel@tonic-gate Uchar *base = iop->_base; 508*0Sstevel@tonic-gate Uchar *bufend; 509*0Sstevel@tonic-gate ssize_t num_wrote; 510*0Sstevel@tonic-gate 511*0Sstevel@tonic-gate /* 512*0Sstevel@tonic-gate * Hopefully, be stable with respect to interrupts... 513*0Sstevel@tonic-gate */ 514*0Sstevel@tonic-gate n = iop->_ptr - base; 515*0Sstevel@tonic-gate iop->_ptr = base; 516*0Sstevel@tonic-gate bufend = _bufend(iop); 517*0Sstevel@tonic-gate if (iop->_flag & (_IOLBF | _IONBF)) 518*0Sstevel@tonic-gate iop->_cnt = 0; /* always go to a flush */ 519*0Sstevel@tonic-gate else 520*0Sstevel@tonic-gate iop->_cnt = bufend - base; 521*0Sstevel@tonic-gate 522*0Sstevel@tonic-gate if (_needsync(iop, bufend)) /* recover from interrupts */ 523*0Sstevel@tonic-gate _bufsync(iop, bufend); 524*0Sstevel@tonic-gate 525*0Sstevel@tonic-gate if (n > 0) { 526*0Sstevel@tonic-gate while ((num_wrote = 527*0Sstevel@tonic-gate write(iop->_file, base, (size_t)n)) != n) { 528*0Sstevel@tonic-gate if (num_wrote <= 0) { 529*0Sstevel@tonic-gate iop->_flag |= _IOERR; 530*0Sstevel@tonic-gate return (EOF); 531*0Sstevel@tonic-gate } 532*0Sstevel@tonic-gate n -= num_wrote; 533*0Sstevel@tonic-gate base += num_wrote; 534*0Sstevel@tonic-gate } 535*0Sstevel@tonic-gate } 536*0Sstevel@tonic-gate return (0); 537*0Sstevel@tonic-gate } 538*0Sstevel@tonic-gate 539*0Sstevel@tonic-gate /* flush (write) buffer */ 540*0Sstevel@tonic-gate int 541*0Sstevel@tonic-gate fflush(FILE *iop) 542*0Sstevel@tonic-gate { 543*0Sstevel@tonic-gate int res; 544*0Sstevel@tonic-gate rmutex_t *lk; 545*0Sstevel@tonic-gate 546*0Sstevel@tonic-gate if (iop) { 547*0Sstevel@tonic-gate FLOCKFILE(lk, iop); 548*0Sstevel@tonic-gate res = _fflush_u(iop); 549*0Sstevel@tonic-gate FUNLOCKFILE(lk); 550*0Sstevel@tonic-gate } else { 551*0Sstevel@tonic-gate res = _fflush_u_iops(); /* flush all iops */ 552*0Sstevel@tonic-gate } 553*0Sstevel@tonic-gate return (res); 554*0Sstevel@tonic-gate } 555*0Sstevel@tonic-gate 556*0Sstevel@tonic-gate static int 557*0Sstevel@tonic-gate _fflush_u_iops(void) /* flush all buffers */ 558*0Sstevel@tonic-gate { 559*0Sstevel@tonic-gate FPDECL(iop); 560*0Sstevel@tonic-gate 561*0Sstevel@tonic-gate int i; 562*0Sstevel@tonic-gate struct _link_ *lp; 563*0Sstevel@tonic-gate int res = 0; 564*0Sstevel@tonic-gate 565*0Sstevel@tonic-gate if (__threaded) 566*0Sstevel@tonic-gate (void) __rw_rdlock(&_first_link_lock); 567*0Sstevel@tonic-gate 568*0Sstevel@tonic-gate lp = &__first_link; 569*0Sstevel@tonic-gate 570*0Sstevel@tonic-gate do { 571*0Sstevel@tonic-gate /* 572*0Sstevel@tonic-gate * Don't grab the locks for these file pointers 573*0Sstevel@tonic-gate * since they are supposed to be flushed anyway 574*0Sstevel@tonic-gate * It could also be the case in which the 2nd 575*0Sstevel@tonic-gate * portion (base and lock) are not initialized 576*0Sstevel@tonic-gate */ 577*0Sstevel@tonic-gate FIRSTFP(lp, iop); 578*0Sstevel@tonic-gate for (i = lp->niob; --i >= 0; NEXTFP(iop)) { 579*0Sstevel@tonic-gate if (!(iop->_flag & _IONBF)) { 580*0Sstevel@tonic-gate /* 581*0Sstevel@tonic-gate * don't need to worry about the _IORW case 582*0Sstevel@tonic-gate * since the iop will also marked with _IOREAD 583*0Sstevel@tonic-gate * or _IOWRT whichever we are really doing 584*0Sstevel@tonic-gate */ 585*0Sstevel@tonic-gate if (iop->_flag & _IOWRT) { /* flush write buffers */ 586*0Sstevel@tonic-gate res |= _fflush_u(iop); 587*0Sstevel@tonic-gate } else if (iop->_flag & _IOREAD) { 588*0Sstevel@tonic-gate /* 589*0Sstevel@tonic-gate * flush seekable read buffers 590*0Sstevel@tonic-gate * don't flush non-seekable read buffers 591*0Sstevel@tonic-gate */ 592*0Sstevel@tonic-gate if (GET_SEEKABLE(iop)) { 593*0Sstevel@tonic-gate res |= _fflush_u(iop); 594*0Sstevel@tonic-gate } 595*0Sstevel@tonic-gate } 596*0Sstevel@tonic-gate } 597*0Sstevel@tonic-gate } 598*0Sstevel@tonic-gate } while ((lp = lp->next) != NULL); 599*0Sstevel@tonic-gate if (__threaded) 600*0Sstevel@tonic-gate (void) __rw_unlock(&_first_link_lock); 601*0Sstevel@tonic-gate return (res); 602*0Sstevel@tonic-gate } 603*0Sstevel@tonic-gate 604*0Sstevel@tonic-gate /* flush buffer */ 605*0Sstevel@tonic-gate int 606*0Sstevel@tonic-gate _fflush_u(FILE *iop) 607*0Sstevel@tonic-gate { 608*0Sstevel@tonic-gate int res = 0; 609*0Sstevel@tonic-gate 610*0Sstevel@tonic-gate /* this portion is always assumed locked */ 611*0Sstevel@tonic-gate if (!(iop->_flag & _IOWRT)) { 612*0Sstevel@tonic-gate (void) lseek64(iop->_file, -iop->_cnt, SEEK_CUR); 613*0Sstevel@tonic-gate iop->_cnt = 0; 614*0Sstevel@tonic-gate /* needed for ungetc & multibyte pushbacks */ 615*0Sstevel@tonic-gate iop->_ptr = iop->_base; 616*0Sstevel@tonic-gate if (iop->_flag & _IORW) { 617*0Sstevel@tonic-gate iop->_flag &= ~_IOREAD; 618*0Sstevel@tonic-gate } 619*0Sstevel@tonic-gate return (0); 620*0Sstevel@tonic-gate } 621*0Sstevel@tonic-gate if (iop->_base != NULL && iop->_ptr > iop->_base) { 622*0Sstevel@tonic-gate res = _xflsbuf(iop); 623*0Sstevel@tonic-gate } 624*0Sstevel@tonic-gate if (iop->_flag & _IORW) { 625*0Sstevel@tonic-gate iop->_flag &= ~_IOWRT; 626*0Sstevel@tonic-gate iop->_cnt = 0; 627*0Sstevel@tonic-gate } 628*0Sstevel@tonic-gate return (res); 629*0Sstevel@tonic-gate } 630*0Sstevel@tonic-gate 631*0Sstevel@tonic-gate /* flush buffer and close stream */ 632*0Sstevel@tonic-gate int 633*0Sstevel@tonic-gate fclose(FILE *iop) 634*0Sstevel@tonic-gate { 635*0Sstevel@tonic-gate int res = 0; 636*0Sstevel@tonic-gate rmutex_t *lk; 637*0Sstevel@tonic-gate 638*0Sstevel@tonic-gate if (iop == NULL) { 639*0Sstevel@tonic-gate return (EOF); /* avoid passing zero to FLOCKFILE */ 640*0Sstevel@tonic-gate } 641*0Sstevel@tonic-gate 642*0Sstevel@tonic-gate FLOCKFILE(lk, iop); 643*0Sstevel@tonic-gate if (iop->_flag == 0) { 644*0Sstevel@tonic-gate FUNLOCKFILE(lk); 645*0Sstevel@tonic-gate return (EOF); 646*0Sstevel@tonic-gate } 647*0Sstevel@tonic-gate /* Is not unbuffered and opened for read and/or write ? */ 648*0Sstevel@tonic-gate if (!(iop->_flag & _IONBF) && (iop->_flag & (_IOWRT | _IOREAD | _IORW))) 649*0Sstevel@tonic-gate res = _fflush_u(iop); 650*0Sstevel@tonic-gate if (close(iop->_file) < 0) 651*0Sstevel@tonic-gate res = EOF; 652*0Sstevel@tonic-gate if (iop->_flag & _IOMYBUF) { 653*0Sstevel@tonic-gate (void) free((char *)iop->_base - PUSHBACK); 654*0Sstevel@tonic-gate } 655*0Sstevel@tonic-gate iop->_base = NULL; 656*0Sstevel@tonic-gate iop->_ptr = NULL; 657*0Sstevel@tonic-gate iop->_cnt = 0; 658*0Sstevel@tonic-gate iop->_flag = 0; /* marks it as available */ 659*0Sstevel@tonic-gate FUNLOCKFILE(lk); 660*0Sstevel@tonic-gate 661*0Sstevel@tonic-gate if (__threaded) 662*0Sstevel@tonic-gate (void) __rw_wrlock(&_first_link_lock); 663*0Sstevel@tonic-gate fcloses++; 664*0Sstevel@tonic-gate if (__threaded) 665*0Sstevel@tonic-gate (void) __rw_unlock(&_first_link_lock); 666*0Sstevel@tonic-gate 667*0Sstevel@tonic-gate return (res); 668*0Sstevel@tonic-gate } 669*0Sstevel@tonic-gate 670*0Sstevel@tonic-gate /* flush buffer, close fd but keep the stream used by freopen() */ 671*0Sstevel@tonic-gate int 672*0Sstevel@tonic-gate close_fd(FILE *iop) 673*0Sstevel@tonic-gate { 674*0Sstevel@tonic-gate int res = 0; 675*0Sstevel@tonic-gate mbstate_t *mb; 676*0Sstevel@tonic-gate 677*0Sstevel@tonic-gate if (iop == NULL || iop->_flag == 0) 678*0Sstevel@tonic-gate return (EOF); 679*0Sstevel@tonic-gate /* Is not unbuffered and opened for read and/or write ? */ 680*0Sstevel@tonic-gate if (!(iop->_flag & _IONBF) && (iop->_flag & (_IOWRT | _IOREAD | _IORW))) 681*0Sstevel@tonic-gate res = _fflush_u(iop); 682*0Sstevel@tonic-gate if (close(iop->_file) < 0) 683*0Sstevel@tonic-gate res = EOF; 684*0Sstevel@tonic-gate if (iop->_flag & _IOMYBUF) { 685*0Sstevel@tonic-gate (void) free((char *)iop->_base - PUSHBACK); 686*0Sstevel@tonic-gate } 687*0Sstevel@tonic-gate iop->_base = NULL; 688*0Sstevel@tonic-gate iop->_ptr = NULL; 689*0Sstevel@tonic-gate mb = _getmbstate(iop); 690*0Sstevel@tonic-gate if (mb != NULL) 691*0Sstevel@tonic-gate (void) memset(mb, 0, sizeof (mbstate_t)); 692*0Sstevel@tonic-gate iop->_cnt = 0; 693*0Sstevel@tonic-gate _setorientation(iop, _NO_MODE); 694*0Sstevel@tonic-gate return (res); 695*0Sstevel@tonic-gate } 696*0Sstevel@tonic-gate 697*0Sstevel@tonic-gate static FILE * 698*0Sstevel@tonic-gate getiop(FILE *fp, rmutex_t *lk, mbstate_t *mb) 699*0Sstevel@tonic-gate { 700*0Sstevel@tonic-gate if (lk != NULL && rmutex_trylock(lk)) 701*0Sstevel@tonic-gate return (NULL); /* locked: fp in use */ 702*0Sstevel@tonic-gate 703*0Sstevel@tonic-gate if (fp->_flag == 0) { /* unused */ 704*0Sstevel@tonic-gate #ifndef _LP64 705*0Sstevel@tonic-gate fp->__orientation = 0; 706*0Sstevel@tonic-gate #endif /* _LP64 */ 707*0Sstevel@tonic-gate fp->_cnt = 0; 708*0Sstevel@tonic-gate fp->_ptr = NULL; 709*0Sstevel@tonic-gate fp->_base = NULL; 710*0Sstevel@tonic-gate fp->_flag = 0377; /* claim the fp by setting low 8 bits */ 711*0Sstevel@tonic-gate (void) memset(mb, 0, sizeof (mbstate_t)); 712*0Sstevel@tonic-gate FUNLOCKFILE(lk); 713*0Sstevel@tonic-gate return (fp); 714*0Sstevel@tonic-gate } 715*0Sstevel@tonic-gate FUNLOCKFILE(lk); 716*0Sstevel@tonic-gate return (NULL); 717*0Sstevel@tonic-gate } 718*0Sstevel@tonic-gate 719*0Sstevel@tonic-gate #ifndef _LP64 720*0Sstevel@tonic-gate /* 721*0Sstevel@tonic-gate * DESCRIPTION: 722*0Sstevel@tonic-gate * This function gets the pointer to the mbstate_t structure associated 723*0Sstevel@tonic-gate * with the specified iop. 724*0Sstevel@tonic-gate * 725*0Sstevel@tonic-gate * RETURNS: 726*0Sstevel@tonic-gate * If the associated mbstate_t found, the pointer to the mbstate_t is 727*0Sstevel@tonic-gate * returned. Otherwise, NULL is returned. 728*0Sstevel@tonic-gate */ 729*0Sstevel@tonic-gate mbstate_t * 730*0Sstevel@tonic-gate _getmbstate(FILE *iop) 731*0Sstevel@tonic-gate { 732*0Sstevel@tonic-gate struct xFILEdata *dat = getxfdat(iop); 733*0Sstevel@tonic-gate 734*0Sstevel@tonic-gate if (dat != NULL) 735*0Sstevel@tonic-gate return (&dat->_state); 736*0Sstevel@tonic-gate 737*0Sstevel@tonic-gate return (NULL); 738*0Sstevel@tonic-gate } 739*0Sstevel@tonic-gate #endif 740