1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * Copyright (c) 2000-2002, 2004 Sendmail, Inc. and its suppliers. 3*7c478bd9Sstevel@tonic-gate * All rights reserved. 4*7c478bd9Sstevel@tonic-gate * Copyright (c) 1990, 1993 5*7c478bd9Sstevel@tonic-gate * The Regents of the University of California. All rights reserved. 6*7c478bd9Sstevel@tonic-gate * 7*7c478bd9Sstevel@tonic-gate * This code is derived from software contributed to Berkeley by 8*7c478bd9Sstevel@tonic-gate * Chris Torek. 9*7c478bd9Sstevel@tonic-gate * 10*7c478bd9Sstevel@tonic-gate * By using this file, you agree to the terms and conditions set 11*7c478bd9Sstevel@tonic-gate * forth in the LICENSE file which can be found at the top level of 12*7c478bd9Sstevel@tonic-gate * the sendmail distribution. 13*7c478bd9Sstevel@tonic-gate */ 14*7c478bd9Sstevel@tonic-gate 15*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 16*7c478bd9Sstevel@tonic-gate 17*7c478bd9Sstevel@tonic-gate #include <sm/gen.h> 18*7c478bd9Sstevel@tonic-gate SM_RCSID("@(#)$Id: fopen.c,v 1.61 2004/08/03 20:17:38 ca Exp $") 19*7c478bd9Sstevel@tonic-gate #include <errno.h> 20*7c478bd9Sstevel@tonic-gate #include <setjmp.h> 21*7c478bd9Sstevel@tonic-gate #include <sys/time.h> 22*7c478bd9Sstevel@tonic-gate #include <sm/heap.h> 23*7c478bd9Sstevel@tonic-gate #include <sm/signal.h> 24*7c478bd9Sstevel@tonic-gate #include <sm/assert.h> 25*7c478bd9Sstevel@tonic-gate #include <sm/io.h> 26*7c478bd9Sstevel@tonic-gate #include <sm/clock.h> 27*7c478bd9Sstevel@tonic-gate #include "local.h" 28*7c478bd9Sstevel@tonic-gate 29*7c478bd9Sstevel@tonic-gate static void openalrm __P((int)); 30*7c478bd9Sstevel@tonic-gate static void reopenalrm __P((int)); 31*7c478bd9Sstevel@tonic-gate extern int sm_io_fclose __P((SM_FILE_T *)); 32*7c478bd9Sstevel@tonic-gate 33*7c478bd9Sstevel@tonic-gate static jmp_buf OpenTimeOut, ReopenTimeOut; 34*7c478bd9Sstevel@tonic-gate 35*7c478bd9Sstevel@tonic-gate /* 36*7c478bd9Sstevel@tonic-gate ** OPENALRM -- handler when timeout activated for sm_io_open() 37*7c478bd9Sstevel@tonic-gate ** 38*7c478bd9Sstevel@tonic-gate ** Returns flow of control to where setjmp(OpenTimeOut) was set. 39*7c478bd9Sstevel@tonic-gate ** 40*7c478bd9Sstevel@tonic-gate ** Parameters: 41*7c478bd9Sstevel@tonic-gate ** sig -- unused 42*7c478bd9Sstevel@tonic-gate ** 43*7c478bd9Sstevel@tonic-gate ** Returns: 44*7c478bd9Sstevel@tonic-gate ** does not return 45*7c478bd9Sstevel@tonic-gate ** 46*7c478bd9Sstevel@tonic-gate ** Side Effects: 47*7c478bd9Sstevel@tonic-gate ** returns flow of control to setjmp(OpenTimeOut). 48*7c478bd9Sstevel@tonic-gate ** 49*7c478bd9Sstevel@tonic-gate ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 50*7c478bd9Sstevel@tonic-gate ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 51*7c478bd9Sstevel@tonic-gate ** DOING. 52*7c478bd9Sstevel@tonic-gate */ 53*7c478bd9Sstevel@tonic-gate 54*7c478bd9Sstevel@tonic-gate /* ARGSUSED0 */ 55*7c478bd9Sstevel@tonic-gate static void 56*7c478bd9Sstevel@tonic-gate openalrm(sig) 57*7c478bd9Sstevel@tonic-gate int sig; 58*7c478bd9Sstevel@tonic-gate { 59*7c478bd9Sstevel@tonic-gate longjmp(OpenTimeOut, 1); 60*7c478bd9Sstevel@tonic-gate } 61*7c478bd9Sstevel@tonic-gate /* 62*7c478bd9Sstevel@tonic-gate ** REOPENALRM -- handler when timeout activated for sm_io_reopen() 63*7c478bd9Sstevel@tonic-gate ** 64*7c478bd9Sstevel@tonic-gate ** Returns flow of control to where setjmp(ReopenTimeOut) was set. 65*7c478bd9Sstevel@tonic-gate ** 66*7c478bd9Sstevel@tonic-gate ** Parameters: 67*7c478bd9Sstevel@tonic-gate ** sig -- unused 68*7c478bd9Sstevel@tonic-gate ** 69*7c478bd9Sstevel@tonic-gate ** Returns: 70*7c478bd9Sstevel@tonic-gate ** does not return 71*7c478bd9Sstevel@tonic-gate ** 72*7c478bd9Sstevel@tonic-gate ** Side Effects: 73*7c478bd9Sstevel@tonic-gate ** returns flow of control to setjmp(ReopenTimeOut). 74*7c478bd9Sstevel@tonic-gate ** 75*7c478bd9Sstevel@tonic-gate ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 76*7c478bd9Sstevel@tonic-gate ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 77*7c478bd9Sstevel@tonic-gate ** DOING. 78*7c478bd9Sstevel@tonic-gate */ 79*7c478bd9Sstevel@tonic-gate 80*7c478bd9Sstevel@tonic-gate /* ARGSUSED0 */ 81*7c478bd9Sstevel@tonic-gate static void 82*7c478bd9Sstevel@tonic-gate reopenalrm(sig) 83*7c478bd9Sstevel@tonic-gate int sig; 84*7c478bd9Sstevel@tonic-gate { 85*7c478bd9Sstevel@tonic-gate longjmp(ReopenTimeOut, 1); 86*7c478bd9Sstevel@tonic-gate } 87*7c478bd9Sstevel@tonic-gate 88*7c478bd9Sstevel@tonic-gate /* 89*7c478bd9Sstevel@tonic-gate ** SM_IO_OPEN -- open a file of a specific type 90*7c478bd9Sstevel@tonic-gate ** 91*7c478bd9Sstevel@tonic-gate ** Parameters: 92*7c478bd9Sstevel@tonic-gate ** type -- type of file to open 93*7c478bd9Sstevel@tonic-gate ** timeout -- time to complete the open 94*7c478bd9Sstevel@tonic-gate ** info -- info describing what is to be opened (type dependant) 95*7c478bd9Sstevel@tonic-gate ** flags -- user selected flags 96*7c478bd9Sstevel@tonic-gate ** rpool -- pointer to rpool to be used for this open 97*7c478bd9Sstevel@tonic-gate ** 98*7c478bd9Sstevel@tonic-gate ** Returns: 99*7c478bd9Sstevel@tonic-gate ** Raises exception on heap exhaustion. 100*7c478bd9Sstevel@tonic-gate ** Aborts if type is invalid. 101*7c478bd9Sstevel@tonic-gate ** Returns NULL and sets errno 102*7c478bd9Sstevel@tonic-gate ** - when the type specific open fails 103*7c478bd9Sstevel@tonic-gate ** - when open vector errors 104*7c478bd9Sstevel@tonic-gate ** - when flags not set or invalid 105*7c478bd9Sstevel@tonic-gate ** Success returns a file pointer to the opened file type. 106*7c478bd9Sstevel@tonic-gate */ 107*7c478bd9Sstevel@tonic-gate 108*7c478bd9Sstevel@tonic-gate SM_FILE_T * 109*7c478bd9Sstevel@tonic-gate sm_io_open(type, timeout, info, flags, rpool) 110*7c478bd9Sstevel@tonic-gate const SM_FILE_T *type; 111*7c478bd9Sstevel@tonic-gate int SM_NONVOLATILE timeout; /* this is not the file type timeout */ 112*7c478bd9Sstevel@tonic-gate const void *info; 113*7c478bd9Sstevel@tonic-gate int flags; 114*7c478bd9Sstevel@tonic-gate const void *rpool; 115*7c478bd9Sstevel@tonic-gate { 116*7c478bd9Sstevel@tonic-gate register SM_FILE_T *fp; 117*7c478bd9Sstevel@tonic-gate int ioflags; 118*7c478bd9Sstevel@tonic-gate SM_EVENT *evt = NULL; 119*7c478bd9Sstevel@tonic-gate 120*7c478bd9Sstevel@tonic-gate ioflags = sm_flags(flags); 121*7c478bd9Sstevel@tonic-gate 122*7c478bd9Sstevel@tonic-gate if (ioflags == 0) 123*7c478bd9Sstevel@tonic-gate { 124*7c478bd9Sstevel@tonic-gate /* must give some indication/intent */ 125*7c478bd9Sstevel@tonic-gate errno = EINVAL; 126*7c478bd9Sstevel@tonic-gate return NULL; 127*7c478bd9Sstevel@tonic-gate } 128*7c478bd9Sstevel@tonic-gate 129*7c478bd9Sstevel@tonic-gate if (timeout == SM_TIME_DEFAULT) 130*7c478bd9Sstevel@tonic-gate timeout = SM_TIME_FOREVER; 131*7c478bd9Sstevel@tonic-gate if (timeout == SM_TIME_IMMEDIATE) 132*7c478bd9Sstevel@tonic-gate { 133*7c478bd9Sstevel@tonic-gate errno = EAGAIN; 134*7c478bd9Sstevel@tonic-gate return NULL; 135*7c478bd9Sstevel@tonic-gate } 136*7c478bd9Sstevel@tonic-gate 137*7c478bd9Sstevel@tonic-gate fp = sm_fp(type, ioflags, NULL); 138*7c478bd9Sstevel@tonic-gate 139*7c478bd9Sstevel@tonic-gate /* Okay, this is where we set the timeout. */ 140*7c478bd9Sstevel@tonic-gate if (timeout != SM_TIME_FOREVER) 141*7c478bd9Sstevel@tonic-gate { 142*7c478bd9Sstevel@tonic-gate if (setjmp(OpenTimeOut) != 0) 143*7c478bd9Sstevel@tonic-gate { 144*7c478bd9Sstevel@tonic-gate errno = EAGAIN; 145*7c478bd9Sstevel@tonic-gate return NULL; 146*7c478bd9Sstevel@tonic-gate } 147*7c478bd9Sstevel@tonic-gate evt = sm_seteventm(timeout, openalrm, 0); 148*7c478bd9Sstevel@tonic-gate } 149*7c478bd9Sstevel@tonic-gate 150*7c478bd9Sstevel@tonic-gate if ((*fp->f_open)(fp, info, flags, rpool) < 0) 151*7c478bd9Sstevel@tonic-gate { 152*7c478bd9Sstevel@tonic-gate fp->f_flags = 0; /* release */ 153*7c478bd9Sstevel@tonic-gate fp->sm_magic = NULL; /* release */ 154*7c478bd9Sstevel@tonic-gate return NULL; 155*7c478bd9Sstevel@tonic-gate } 156*7c478bd9Sstevel@tonic-gate 157*7c478bd9Sstevel@tonic-gate /* We're back. So undo our timeout and handler */ 158*7c478bd9Sstevel@tonic-gate if (evt != NULL) 159*7c478bd9Sstevel@tonic-gate sm_clrevent(evt); 160*7c478bd9Sstevel@tonic-gate 161*7c478bd9Sstevel@tonic-gate #if SM_RPOOL 162*7c478bd9Sstevel@tonic-gate if (rpool != NULL) 163*7c478bd9Sstevel@tonic-gate sm_rpool_attach_x(rpool, sm_io_fclose, fp); 164*7c478bd9Sstevel@tonic-gate #endif /* SM_RPOOL */ 165*7c478bd9Sstevel@tonic-gate 166*7c478bd9Sstevel@tonic-gate return fp; 167*7c478bd9Sstevel@tonic-gate } 168*7c478bd9Sstevel@tonic-gate /* 169*7c478bd9Sstevel@tonic-gate ** SM_IO_DUP -- duplicate a file pointer 170*7c478bd9Sstevel@tonic-gate ** 171*7c478bd9Sstevel@tonic-gate ** Parameters: 172*7c478bd9Sstevel@tonic-gate ** fp -- file pointer to duplicate 173*7c478bd9Sstevel@tonic-gate ** 174*7c478bd9Sstevel@tonic-gate ** Returns: 175*7c478bd9Sstevel@tonic-gate ** Success - the duplicated file pointer 176*7c478bd9Sstevel@tonic-gate ** Failure - NULL (was an invalid file pointer or too many open) 177*7c478bd9Sstevel@tonic-gate ** 178*7c478bd9Sstevel@tonic-gate ** Increments the duplicate counter (dup_cnt) for the open file pointer. 179*7c478bd9Sstevel@tonic-gate ** The counter counts the number of duplicates. When the duplicate 180*7c478bd9Sstevel@tonic-gate ** counter is 0 (zero) then the file pointer is the only one left 181*7c478bd9Sstevel@tonic-gate ** (no duplicates, it is the only one). 182*7c478bd9Sstevel@tonic-gate */ 183*7c478bd9Sstevel@tonic-gate 184*7c478bd9Sstevel@tonic-gate SM_FILE_T * 185*7c478bd9Sstevel@tonic-gate sm_io_dup(fp) 186*7c478bd9Sstevel@tonic-gate SM_FILE_T *fp; 187*7c478bd9Sstevel@tonic-gate { 188*7c478bd9Sstevel@tonic-gate 189*7c478bd9Sstevel@tonic-gate SM_REQUIRE_ISA(fp, SmFileMagic); 190*7c478bd9Sstevel@tonic-gate if (fp->sm_magic != SmFileMagic) 191*7c478bd9Sstevel@tonic-gate { 192*7c478bd9Sstevel@tonic-gate errno = EBADF; 193*7c478bd9Sstevel@tonic-gate return NULL; 194*7c478bd9Sstevel@tonic-gate } 195*7c478bd9Sstevel@tonic-gate if (fp->f_dup_cnt >= INT_MAX - 1) 196*7c478bd9Sstevel@tonic-gate { 197*7c478bd9Sstevel@tonic-gate /* Can't let f_dup_cnt wrap! */ 198*7c478bd9Sstevel@tonic-gate errno = EMFILE; 199*7c478bd9Sstevel@tonic-gate return NULL; 200*7c478bd9Sstevel@tonic-gate } 201*7c478bd9Sstevel@tonic-gate fp->f_dup_cnt++; 202*7c478bd9Sstevel@tonic-gate return fp; 203*7c478bd9Sstevel@tonic-gate } 204*7c478bd9Sstevel@tonic-gate /* 205*7c478bd9Sstevel@tonic-gate ** SM_IO_REOPEN -- open a new file using the old file pointer 206*7c478bd9Sstevel@tonic-gate ** 207*7c478bd9Sstevel@tonic-gate ** Parameters: 208*7c478bd9Sstevel@tonic-gate ** type -- file type to be opened 209*7c478bd9Sstevel@tonic-gate ** timeout -- time to complete the reopen 210*7c478bd9Sstevel@tonic-gate ** info -- infomation about what is to be "re-opened" (type dep.) 211*7c478bd9Sstevel@tonic-gate ** flags -- user flags to map to internal flags 212*7c478bd9Sstevel@tonic-gate ** rpool -- rpool file to be associated with 213*7c478bd9Sstevel@tonic-gate ** fp -- the file pointer to reuse 214*7c478bd9Sstevel@tonic-gate ** 215*7c478bd9Sstevel@tonic-gate ** Returns: 216*7c478bd9Sstevel@tonic-gate ** Raises an exception on heap exhaustion. 217*7c478bd9Sstevel@tonic-gate ** Aborts if type is invalid. 218*7c478bd9Sstevel@tonic-gate ** Failure: returns NULL 219*7c478bd9Sstevel@tonic-gate ** Success: returns "reopened" file pointer 220*7c478bd9Sstevel@tonic-gate */ 221*7c478bd9Sstevel@tonic-gate 222*7c478bd9Sstevel@tonic-gate SM_FILE_T * 223*7c478bd9Sstevel@tonic-gate sm_io_reopen(type, timeout, info, flags, rpool, fp) 224*7c478bd9Sstevel@tonic-gate const SM_FILE_T *type; 225*7c478bd9Sstevel@tonic-gate int SM_NONVOLATILE timeout; 226*7c478bd9Sstevel@tonic-gate const void *info; 227*7c478bd9Sstevel@tonic-gate int flags; 228*7c478bd9Sstevel@tonic-gate const void *rpool; 229*7c478bd9Sstevel@tonic-gate SM_FILE_T *fp; 230*7c478bd9Sstevel@tonic-gate { 231*7c478bd9Sstevel@tonic-gate int ioflags, ret; 232*7c478bd9Sstevel@tonic-gate SM_FILE_T *fp2; 233*7c478bd9Sstevel@tonic-gate SM_EVENT *evt = NULL; 234*7c478bd9Sstevel@tonic-gate 235*7c478bd9Sstevel@tonic-gate if ((ioflags = sm_flags(flags)) == 0) 236*7c478bd9Sstevel@tonic-gate { 237*7c478bd9Sstevel@tonic-gate (void) sm_io_close(fp, timeout); 238*7c478bd9Sstevel@tonic-gate return NULL; 239*7c478bd9Sstevel@tonic-gate } 240*7c478bd9Sstevel@tonic-gate 241*7c478bd9Sstevel@tonic-gate if (!Sm_IO_DidInit) 242*7c478bd9Sstevel@tonic-gate sm_init(); 243*7c478bd9Sstevel@tonic-gate 244*7c478bd9Sstevel@tonic-gate if (timeout == SM_TIME_DEFAULT) 245*7c478bd9Sstevel@tonic-gate timeout = SM_TIME_FOREVER; 246*7c478bd9Sstevel@tonic-gate if (timeout == SM_TIME_IMMEDIATE) 247*7c478bd9Sstevel@tonic-gate { 248*7c478bd9Sstevel@tonic-gate /* 249*7c478bd9Sstevel@tonic-gate ** Filling the buffer will take time and we are wanted to 250*7c478bd9Sstevel@tonic-gate ** return immediately. So... 251*7c478bd9Sstevel@tonic-gate */ 252*7c478bd9Sstevel@tonic-gate 253*7c478bd9Sstevel@tonic-gate errno = EAGAIN; 254*7c478bd9Sstevel@tonic-gate return NULL; 255*7c478bd9Sstevel@tonic-gate } 256*7c478bd9Sstevel@tonic-gate /* Okay, this is where we set the timeout. */ 257*7c478bd9Sstevel@tonic-gate if (timeout != SM_TIME_FOREVER) 258*7c478bd9Sstevel@tonic-gate { 259*7c478bd9Sstevel@tonic-gate if (setjmp(ReopenTimeOut) != 0) 260*7c478bd9Sstevel@tonic-gate { 261*7c478bd9Sstevel@tonic-gate errno = EAGAIN; 262*7c478bd9Sstevel@tonic-gate return NULL; 263*7c478bd9Sstevel@tonic-gate } 264*7c478bd9Sstevel@tonic-gate 265*7c478bd9Sstevel@tonic-gate evt = sm_seteventm(timeout, reopenalrm, 0); 266*7c478bd9Sstevel@tonic-gate } 267*7c478bd9Sstevel@tonic-gate 268*7c478bd9Sstevel@tonic-gate /* 269*7c478bd9Sstevel@tonic-gate ** There are actually programs that depend on being able to "reopen" 270*7c478bd9Sstevel@tonic-gate ** descriptors that weren't originally open. Keep this from breaking. 271*7c478bd9Sstevel@tonic-gate ** Remember whether the stream was open to begin with, and which file 272*7c478bd9Sstevel@tonic-gate ** descriptor (if any) was associated with it. If it was attached to 273*7c478bd9Sstevel@tonic-gate ** a descriptor, defer closing it; reopen("/dev/stdin", "r", stdin) 274*7c478bd9Sstevel@tonic-gate ** should work. This is unnecessary if it was not a Unix file. 275*7c478bd9Sstevel@tonic-gate */ 276*7c478bd9Sstevel@tonic-gate 277*7c478bd9Sstevel@tonic-gate if (fp != NULL) 278*7c478bd9Sstevel@tonic-gate { 279*7c478bd9Sstevel@tonic-gate if (fp->sm_magic != SmFileMagic) 280*7c478bd9Sstevel@tonic-gate fp->f_flags = SMFEOF; /* hold on to it */ 281*7c478bd9Sstevel@tonic-gate else 282*7c478bd9Sstevel@tonic-gate { 283*7c478bd9Sstevel@tonic-gate /* flush the stream; ANSI doesn't require this. */ 284*7c478bd9Sstevel@tonic-gate (void) sm_io_flush(fp, SM_TIME_FOREVER); 285*7c478bd9Sstevel@tonic-gate (void) sm_io_close(fp, SM_TIME_FOREVER); 286*7c478bd9Sstevel@tonic-gate } 287*7c478bd9Sstevel@tonic-gate } 288*7c478bd9Sstevel@tonic-gate 289*7c478bd9Sstevel@tonic-gate fp2 = sm_fp(type, ioflags, fp); 290*7c478bd9Sstevel@tonic-gate ret = (*fp2->f_open)(fp2, info, flags, rpool); 291*7c478bd9Sstevel@tonic-gate 292*7c478bd9Sstevel@tonic-gate /* We're back. So undo our timeout and handler */ 293*7c478bd9Sstevel@tonic-gate if (evt != NULL) 294*7c478bd9Sstevel@tonic-gate sm_clrevent(evt); 295*7c478bd9Sstevel@tonic-gate 296*7c478bd9Sstevel@tonic-gate if (ret < 0) 297*7c478bd9Sstevel@tonic-gate { 298*7c478bd9Sstevel@tonic-gate fp2->f_flags = 0; /* release */ 299*7c478bd9Sstevel@tonic-gate fp2->sm_magic = NULL; /* release */ 300*7c478bd9Sstevel@tonic-gate return NULL; 301*7c478bd9Sstevel@tonic-gate } 302*7c478bd9Sstevel@tonic-gate 303*7c478bd9Sstevel@tonic-gate /* 304*7c478bd9Sstevel@tonic-gate ** We're not preserving this logic (below) for sm_io because it is now 305*7c478bd9Sstevel@tonic-gate ** abstracted at least one "layer" away. By closing and reopening 306*7c478bd9Sstevel@tonic-gate ** the 1st fd used should be the just released one (when Unix 307*7c478bd9Sstevel@tonic-gate ** behavior followed). Old comment:: 308*7c478bd9Sstevel@tonic-gate ** If reopening something that was open before on a real file, try 309*7c478bd9Sstevel@tonic-gate ** to maintain the descriptor. Various C library routines (perror) 310*7c478bd9Sstevel@tonic-gate ** assume stderr is always fd STDERR_FILENO, even if being reopen'd. 311*7c478bd9Sstevel@tonic-gate */ 312*7c478bd9Sstevel@tonic-gate 313*7c478bd9Sstevel@tonic-gate #if SM_RPOOL 314*7c478bd9Sstevel@tonic-gate if (rpool != NULL) 315*7c478bd9Sstevel@tonic-gate sm_rpool_attach_x(rpool, sm_io_close, fp2); 316*7c478bd9Sstevel@tonic-gate #endif /* SM_RPOOL */ 317*7c478bd9Sstevel@tonic-gate 318*7c478bd9Sstevel@tonic-gate return fp2; 319*7c478bd9Sstevel@tonic-gate } 320*7c478bd9Sstevel@tonic-gate /* 321*7c478bd9Sstevel@tonic-gate ** SM_IO_AUTOFLUSH -- link another file to this for auto-flushing 322*7c478bd9Sstevel@tonic-gate ** 323*7c478bd9Sstevel@tonic-gate ** When a read occurs on fp, fp2 will be flushed iff there is no 324*7c478bd9Sstevel@tonic-gate ** data waiting on fp. 325*7c478bd9Sstevel@tonic-gate ** 326*7c478bd9Sstevel@tonic-gate ** Parameters: 327*7c478bd9Sstevel@tonic-gate ** fp -- the file opened for reading. 328*7c478bd9Sstevel@tonic-gate ** fp2 -- the file opened for writing. 329*7c478bd9Sstevel@tonic-gate ** 330*7c478bd9Sstevel@tonic-gate ** Returns: 331*7c478bd9Sstevel@tonic-gate ** The old flush file pointer. 332*7c478bd9Sstevel@tonic-gate */ 333*7c478bd9Sstevel@tonic-gate 334*7c478bd9Sstevel@tonic-gate SM_FILE_T * 335*7c478bd9Sstevel@tonic-gate sm_io_autoflush(fp, fp2) 336*7c478bd9Sstevel@tonic-gate SM_FILE_T *fp; 337*7c478bd9Sstevel@tonic-gate SM_FILE_T *fp2; 338*7c478bd9Sstevel@tonic-gate { 339*7c478bd9Sstevel@tonic-gate SM_FILE_T *savefp; 340*7c478bd9Sstevel@tonic-gate 341*7c478bd9Sstevel@tonic-gate SM_REQUIRE_ISA(fp, SmFileMagic); 342*7c478bd9Sstevel@tonic-gate if (fp2 != NULL) 343*7c478bd9Sstevel@tonic-gate SM_REQUIRE_ISA(fp2, SmFileMagic); 344*7c478bd9Sstevel@tonic-gate 345*7c478bd9Sstevel@tonic-gate savefp = fp->f_flushfp; 346*7c478bd9Sstevel@tonic-gate fp->f_flushfp = fp2; 347*7c478bd9Sstevel@tonic-gate return savefp; 348*7c478bd9Sstevel@tonic-gate } 349*7c478bd9Sstevel@tonic-gate /* 350*7c478bd9Sstevel@tonic-gate ** SM_IO_AUTOMODE -- link another file to this for auto-moding 351*7c478bd9Sstevel@tonic-gate ** 352*7c478bd9Sstevel@tonic-gate ** When the mode (blocking or non-blocking) changes for fp1 then 353*7c478bd9Sstevel@tonic-gate ** update fp2's mode at the same time. This is to be used when 354*7c478bd9Sstevel@tonic-gate ** a system dup() has generated a second file descriptor for 355*7c478bd9Sstevel@tonic-gate ** another sm_io_open() by file descriptor. The modes have been 356*7c478bd9Sstevel@tonic-gate ** linked in the system and this formalizes it for sm_io internally. 357*7c478bd9Sstevel@tonic-gate ** 358*7c478bd9Sstevel@tonic-gate ** Parameters: 359*7c478bd9Sstevel@tonic-gate ** fp1 -- the first file 360*7c478bd9Sstevel@tonic-gate ** fp2 -- the second file 361*7c478bd9Sstevel@tonic-gate ** 362*7c478bd9Sstevel@tonic-gate ** Returns: 363*7c478bd9Sstevel@tonic-gate ** nothing 364*7c478bd9Sstevel@tonic-gate */ 365*7c478bd9Sstevel@tonic-gate 366*7c478bd9Sstevel@tonic-gate void 367*7c478bd9Sstevel@tonic-gate sm_io_automode(fp1, fp2) 368*7c478bd9Sstevel@tonic-gate SM_FILE_T *fp1; 369*7c478bd9Sstevel@tonic-gate SM_FILE_T *fp2; 370*7c478bd9Sstevel@tonic-gate { 371*7c478bd9Sstevel@tonic-gate SM_REQUIRE_ISA(fp1, SmFileMagic); 372*7c478bd9Sstevel@tonic-gate SM_REQUIRE_ISA(fp2, SmFileMagic); 373*7c478bd9Sstevel@tonic-gate 374*7c478bd9Sstevel@tonic-gate fp1->f_modefp = fp2; 375*7c478bd9Sstevel@tonic-gate fp2->f_modefp = fp1; 376*7c478bd9Sstevel@tonic-gate } 377