1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * Copyright (c) 2000-2004 Sendmail, Inc. and its suppliers. 3*0Sstevel@tonic-gate * All rights reserved. 4*0Sstevel@tonic-gate * Copyright (c) 1990, 1993 5*0Sstevel@tonic-gate * The Regents of the University of California. All rights reserved. 6*0Sstevel@tonic-gate * 7*0Sstevel@tonic-gate * This code is derived from software contributed to Berkeley by 8*0Sstevel@tonic-gate * Chris Torek. 9*0Sstevel@tonic-gate * 10*0Sstevel@tonic-gate * By using this file, you agree to the terms and conditions set 11*0Sstevel@tonic-gate * forth in the LICENSE file which can be found at the top level of 12*0Sstevel@tonic-gate * the sendmail distribution. 13*0Sstevel@tonic-gate */ 14*0Sstevel@tonic-gate 15*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 16*0Sstevel@tonic-gate 17*0Sstevel@tonic-gate #include <sm/gen.h> 18*0Sstevel@tonic-gate SM_RCSID("@(#)$Id: stdio.c,v 1.69 2004/08/03 20:46:34 ca Exp $") 19*0Sstevel@tonic-gate #include <unistd.h> 20*0Sstevel@tonic-gate #include <errno.h> 21*0Sstevel@tonic-gate #include <fcntl.h> 22*0Sstevel@tonic-gate #include <string.h> /* FreeBSD: FD_ZERO needs <string.h> */ 23*0Sstevel@tonic-gate #include <sys/stat.h> 24*0Sstevel@tonic-gate #include <sys/time.h> 25*0Sstevel@tonic-gate #include <sm/heap.h> 26*0Sstevel@tonic-gate #include <sm/assert.h> 27*0Sstevel@tonic-gate #include <sm/varargs.h> 28*0Sstevel@tonic-gate #include <sm/io.h> 29*0Sstevel@tonic-gate #include <sm/setjmp.h> 30*0Sstevel@tonic-gate #include <sm/conf.h> 31*0Sstevel@tonic-gate #include <sm/fdset.h> 32*0Sstevel@tonic-gate #include "local.h" 33*0Sstevel@tonic-gate 34*0Sstevel@tonic-gate static int sm_stdsetmode __P((SM_FILE_T *, const int *)); 35*0Sstevel@tonic-gate static int sm_stdgetmode __P((SM_FILE_T *, int *)); 36*0Sstevel@tonic-gate 37*0Sstevel@tonic-gate /* 38*0Sstevel@tonic-gate ** Overall: 39*0Sstevel@tonic-gate ** Small standard I/O/seek/close functions. 40*0Sstevel@tonic-gate ** These maintain the `known seek offset' for seek optimization. 41*0Sstevel@tonic-gate */ 42*0Sstevel@tonic-gate 43*0Sstevel@tonic-gate /* 44*0Sstevel@tonic-gate ** SM_STDOPEN -- open a file with stdio behavior 45*0Sstevel@tonic-gate ** 46*0Sstevel@tonic-gate ** Not associated with the system's stdio in libc. 47*0Sstevel@tonic-gate ** 48*0Sstevel@tonic-gate ** Parameters: 49*0Sstevel@tonic-gate ** fp -- file pointer to be associated with the open 50*0Sstevel@tonic-gate ** info -- pathname of the file to be opened 51*0Sstevel@tonic-gate ** flags -- indicates type of access methods 52*0Sstevel@tonic-gate ** rpool -- ignored 53*0Sstevel@tonic-gate ** 54*0Sstevel@tonic-gate ** Returns: 55*0Sstevel@tonic-gate ** Failure: -1 and set errno 56*0Sstevel@tonic-gate ** Success: 0 or greater (fd of file from open(2)). 57*0Sstevel@tonic-gate ** 58*0Sstevel@tonic-gate */ 59*0Sstevel@tonic-gate 60*0Sstevel@tonic-gate /* ARGSUSED3 */ 61*0Sstevel@tonic-gate int 62*0Sstevel@tonic-gate sm_stdopen(fp, info, flags, rpool) 63*0Sstevel@tonic-gate SM_FILE_T *fp; 64*0Sstevel@tonic-gate const void *info; 65*0Sstevel@tonic-gate int flags; 66*0Sstevel@tonic-gate const void *rpool; 67*0Sstevel@tonic-gate { 68*0Sstevel@tonic-gate char *path = (char *) info; 69*0Sstevel@tonic-gate int oflags; 70*0Sstevel@tonic-gate 71*0Sstevel@tonic-gate switch (SM_IO_MODE(flags)) 72*0Sstevel@tonic-gate { 73*0Sstevel@tonic-gate case SM_IO_RDWR: 74*0Sstevel@tonic-gate oflags = O_RDWR; 75*0Sstevel@tonic-gate break; 76*0Sstevel@tonic-gate case SM_IO_RDWRTR: 77*0Sstevel@tonic-gate oflags = O_RDWR | O_CREAT | O_TRUNC; 78*0Sstevel@tonic-gate break; 79*0Sstevel@tonic-gate case SM_IO_RDONLY: 80*0Sstevel@tonic-gate oflags = O_RDONLY; 81*0Sstevel@tonic-gate break; 82*0Sstevel@tonic-gate case SM_IO_WRONLY: 83*0Sstevel@tonic-gate oflags = O_WRONLY | O_CREAT | O_TRUNC; 84*0Sstevel@tonic-gate break; 85*0Sstevel@tonic-gate case SM_IO_APPEND: 86*0Sstevel@tonic-gate oflags = O_APPEND | O_WRONLY | O_CREAT; 87*0Sstevel@tonic-gate break; 88*0Sstevel@tonic-gate case SM_IO_APPENDRW: 89*0Sstevel@tonic-gate oflags = O_APPEND | O_RDWR | O_CREAT; 90*0Sstevel@tonic-gate break; 91*0Sstevel@tonic-gate default: 92*0Sstevel@tonic-gate errno = EINVAL; 93*0Sstevel@tonic-gate return -1; 94*0Sstevel@tonic-gate } 95*0Sstevel@tonic-gate #ifdef O_BINARY 96*0Sstevel@tonic-gate if (SM_IS_BINARY(flags)) 97*0Sstevel@tonic-gate oflags |= O_BINARY; 98*0Sstevel@tonic-gate #endif /* O_BINARY */ 99*0Sstevel@tonic-gate fp->f_file = open(path, oflags, 100*0Sstevel@tonic-gate S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH); 101*0Sstevel@tonic-gate if (fp->f_file < 0) 102*0Sstevel@tonic-gate return -1; /* errno set by open() */ 103*0Sstevel@tonic-gate 104*0Sstevel@tonic-gate if (oflags & O_APPEND) 105*0Sstevel@tonic-gate (void) (*fp->f_seek)((void *)fp, (off_t)0, SEEK_END); 106*0Sstevel@tonic-gate 107*0Sstevel@tonic-gate return fp->f_file; 108*0Sstevel@tonic-gate } 109*0Sstevel@tonic-gate 110*0Sstevel@tonic-gate /* 111*0Sstevel@tonic-gate ** SM_STDREAD -- read from the file 112*0Sstevel@tonic-gate ** 113*0Sstevel@tonic-gate ** Parameters: 114*0Sstevel@tonic-gate ** fp -- file pointer to read from 115*0Sstevel@tonic-gate ** buf -- location to place read data 116*0Sstevel@tonic-gate ** n -- number of bytes to read 117*0Sstevel@tonic-gate ** 118*0Sstevel@tonic-gate ** Returns: 119*0Sstevel@tonic-gate ** Failure: -1 and sets errno 120*0Sstevel@tonic-gate ** Success: number of bytes read 121*0Sstevel@tonic-gate ** 122*0Sstevel@tonic-gate ** Side Effects: 123*0Sstevel@tonic-gate ** Updates internal offset into file. 124*0Sstevel@tonic-gate */ 125*0Sstevel@tonic-gate 126*0Sstevel@tonic-gate ssize_t 127*0Sstevel@tonic-gate sm_stdread(fp, buf, n) 128*0Sstevel@tonic-gate SM_FILE_T *fp; 129*0Sstevel@tonic-gate char *buf; 130*0Sstevel@tonic-gate size_t n; 131*0Sstevel@tonic-gate { 132*0Sstevel@tonic-gate register int ret; 133*0Sstevel@tonic-gate 134*0Sstevel@tonic-gate ret = read(fp->f_file, buf, n); 135*0Sstevel@tonic-gate 136*0Sstevel@tonic-gate /* if the read succeeded, update the current offset */ 137*0Sstevel@tonic-gate if (ret > 0) 138*0Sstevel@tonic-gate fp->f_lseekoff += ret; 139*0Sstevel@tonic-gate return ret; 140*0Sstevel@tonic-gate } 141*0Sstevel@tonic-gate 142*0Sstevel@tonic-gate /* 143*0Sstevel@tonic-gate ** SM_STDWRITE -- write to the file 144*0Sstevel@tonic-gate ** 145*0Sstevel@tonic-gate ** Parameters: 146*0Sstevel@tonic-gate ** fp -- file pointer ro write to 147*0Sstevel@tonic-gate ** buf -- location of data to be written 148*0Sstevel@tonic-gate ** n - number of bytes to write 149*0Sstevel@tonic-gate ** 150*0Sstevel@tonic-gate ** Returns: 151*0Sstevel@tonic-gate ** Failure: -1 and sets errno 152*0Sstevel@tonic-gate ** Success: number of bytes written 153*0Sstevel@tonic-gate */ 154*0Sstevel@tonic-gate 155*0Sstevel@tonic-gate ssize_t 156*0Sstevel@tonic-gate sm_stdwrite(fp, buf, n) 157*0Sstevel@tonic-gate SM_FILE_T *fp; 158*0Sstevel@tonic-gate char const *buf; 159*0Sstevel@tonic-gate size_t n; 160*0Sstevel@tonic-gate { 161*0Sstevel@tonic-gate return write(fp->f_file, buf, n); 162*0Sstevel@tonic-gate } 163*0Sstevel@tonic-gate 164*0Sstevel@tonic-gate /* 165*0Sstevel@tonic-gate ** SM_STDSEEK -- set the file offset position 166*0Sstevel@tonic-gate ** 167*0Sstevel@tonic-gate ** Parmeters: 168*0Sstevel@tonic-gate ** fp -- file pointer to position 169*0Sstevel@tonic-gate ** offset -- how far to position from "base" (set by 'whence') 170*0Sstevel@tonic-gate ** whence -- indicates where the "base" of the 'offset' to start 171*0Sstevel@tonic-gate ** 172*0Sstevel@tonic-gate ** Results: 173*0Sstevel@tonic-gate ** Failure: -1 and sets errno 174*0Sstevel@tonic-gate ** Success: the current offset 175*0Sstevel@tonic-gate ** 176*0Sstevel@tonic-gate ** Side Effects: 177*0Sstevel@tonic-gate ** Updates the internal value of the offset. 178*0Sstevel@tonic-gate */ 179*0Sstevel@tonic-gate 180*0Sstevel@tonic-gate off_t 181*0Sstevel@tonic-gate sm_stdseek(fp, offset, whence) 182*0Sstevel@tonic-gate SM_FILE_T *fp; 183*0Sstevel@tonic-gate off_t offset; 184*0Sstevel@tonic-gate int whence; 185*0Sstevel@tonic-gate { 186*0Sstevel@tonic-gate register off_t ret; 187*0Sstevel@tonic-gate 188*0Sstevel@tonic-gate ret = lseek(fp->f_file, (off_t) offset, whence); 189*0Sstevel@tonic-gate if (ret != (off_t) -1) 190*0Sstevel@tonic-gate fp->f_lseekoff = ret; 191*0Sstevel@tonic-gate return ret; 192*0Sstevel@tonic-gate } 193*0Sstevel@tonic-gate 194*0Sstevel@tonic-gate /* 195*0Sstevel@tonic-gate ** SM_STDCLOSE -- close the file 196*0Sstevel@tonic-gate ** 197*0Sstevel@tonic-gate ** Parameters: 198*0Sstevel@tonic-gate ** fp -- the file pointer to close 199*0Sstevel@tonic-gate ** 200*0Sstevel@tonic-gate ** Returns: 201*0Sstevel@tonic-gate ** Success: 0 (zero) 202*0Sstevel@tonic-gate ** Failure: -1 and sets errno 203*0Sstevel@tonic-gate */ 204*0Sstevel@tonic-gate 205*0Sstevel@tonic-gate int 206*0Sstevel@tonic-gate sm_stdclose(fp) 207*0Sstevel@tonic-gate SM_FILE_T *fp; 208*0Sstevel@tonic-gate { 209*0Sstevel@tonic-gate return close(fp->f_file); 210*0Sstevel@tonic-gate } 211*0Sstevel@tonic-gate 212*0Sstevel@tonic-gate /* 213*0Sstevel@tonic-gate ** SM_STDSETMODE -- set the access mode for the file 214*0Sstevel@tonic-gate ** 215*0Sstevel@tonic-gate ** Called by sm_stdsetinfo(). 216*0Sstevel@tonic-gate ** 217*0Sstevel@tonic-gate ** Parameters: 218*0Sstevel@tonic-gate ** fp -- file pointer 219*0Sstevel@tonic-gate ** mode -- new mode to set the file access to 220*0Sstevel@tonic-gate ** 221*0Sstevel@tonic-gate ** Results: 222*0Sstevel@tonic-gate ** Success: 0 (zero); 223*0Sstevel@tonic-gate ** Failure: -1 and sets errno 224*0Sstevel@tonic-gate */ 225*0Sstevel@tonic-gate 226*0Sstevel@tonic-gate int 227*0Sstevel@tonic-gate sm_stdsetmode(fp, mode) 228*0Sstevel@tonic-gate SM_FILE_T *fp; 229*0Sstevel@tonic-gate const int *mode; 230*0Sstevel@tonic-gate { 231*0Sstevel@tonic-gate int flags = 0; 232*0Sstevel@tonic-gate 233*0Sstevel@tonic-gate switch (SM_IO_MODE(*mode)) 234*0Sstevel@tonic-gate { 235*0Sstevel@tonic-gate case SM_IO_RDWR: 236*0Sstevel@tonic-gate flags |= SMRW; 237*0Sstevel@tonic-gate break; 238*0Sstevel@tonic-gate case SM_IO_RDONLY: 239*0Sstevel@tonic-gate flags |= SMRD; 240*0Sstevel@tonic-gate break; 241*0Sstevel@tonic-gate case SM_IO_WRONLY: 242*0Sstevel@tonic-gate flags |= SMWR; 243*0Sstevel@tonic-gate break; 244*0Sstevel@tonic-gate case SM_IO_APPEND: 245*0Sstevel@tonic-gate default: 246*0Sstevel@tonic-gate errno = EINVAL; 247*0Sstevel@tonic-gate return -1; 248*0Sstevel@tonic-gate } 249*0Sstevel@tonic-gate fp->f_flags = fp->f_flags & ~SMMODEMASK; 250*0Sstevel@tonic-gate fp->f_flags |= flags; 251*0Sstevel@tonic-gate return 0; 252*0Sstevel@tonic-gate } 253*0Sstevel@tonic-gate 254*0Sstevel@tonic-gate /* 255*0Sstevel@tonic-gate ** SM_STDGETMODE -- for getinfo determine open mode 256*0Sstevel@tonic-gate ** 257*0Sstevel@tonic-gate ** Called by sm_stdgetinfo(). 258*0Sstevel@tonic-gate ** 259*0Sstevel@tonic-gate ** Parameters: 260*0Sstevel@tonic-gate ** fp -- the file mode being determined 261*0Sstevel@tonic-gate ** mode -- internal mode to map to external value 262*0Sstevel@tonic-gate ** 263*0Sstevel@tonic-gate ** Results: 264*0Sstevel@tonic-gate ** Failure: -1 and sets errno 265*0Sstevel@tonic-gate ** Success: external mode value 266*0Sstevel@tonic-gate */ 267*0Sstevel@tonic-gate 268*0Sstevel@tonic-gate static int 269*0Sstevel@tonic-gate sm_stdgetmode(fp, mode) 270*0Sstevel@tonic-gate SM_FILE_T *fp; 271*0Sstevel@tonic-gate int *mode; 272*0Sstevel@tonic-gate { 273*0Sstevel@tonic-gate switch (fp->f_flags & SMMODEMASK) 274*0Sstevel@tonic-gate { 275*0Sstevel@tonic-gate case SMRW: 276*0Sstevel@tonic-gate *mode = SM_IO_RDWR; 277*0Sstevel@tonic-gate break; 278*0Sstevel@tonic-gate case SMRD: 279*0Sstevel@tonic-gate *mode = SM_IO_RDONLY; 280*0Sstevel@tonic-gate break; 281*0Sstevel@tonic-gate case SMWR: 282*0Sstevel@tonic-gate *mode = SM_IO_WRONLY; 283*0Sstevel@tonic-gate break; 284*0Sstevel@tonic-gate default: 285*0Sstevel@tonic-gate errno = EINVAL; 286*0Sstevel@tonic-gate return -1; 287*0Sstevel@tonic-gate } 288*0Sstevel@tonic-gate return 0; 289*0Sstevel@tonic-gate } 290*0Sstevel@tonic-gate 291*0Sstevel@tonic-gate /* 292*0Sstevel@tonic-gate ** SM_STDSETINFO -- set/modify information for a file 293*0Sstevel@tonic-gate ** 294*0Sstevel@tonic-gate ** Parameters: 295*0Sstevel@tonic-gate ** fp -- file to set info for 296*0Sstevel@tonic-gate ** what -- type of info to set 297*0Sstevel@tonic-gate ** valp -- location of data used for setting 298*0Sstevel@tonic-gate ** 299*0Sstevel@tonic-gate ** Returns: 300*0Sstevel@tonic-gate ** Failure: -1 and sets errno 301*0Sstevel@tonic-gate ** Success: >=0 302*0Sstevel@tonic-gate */ 303*0Sstevel@tonic-gate 304*0Sstevel@tonic-gate int 305*0Sstevel@tonic-gate sm_stdsetinfo(fp, what, valp) 306*0Sstevel@tonic-gate SM_FILE_T *fp; 307*0Sstevel@tonic-gate int what; 308*0Sstevel@tonic-gate void *valp; 309*0Sstevel@tonic-gate { 310*0Sstevel@tonic-gate switch (what) 311*0Sstevel@tonic-gate { 312*0Sstevel@tonic-gate case SM_IO_WHAT_MODE: 313*0Sstevel@tonic-gate return sm_stdsetmode(fp, (const int *)valp); 314*0Sstevel@tonic-gate 315*0Sstevel@tonic-gate default: 316*0Sstevel@tonic-gate errno = EINVAL; 317*0Sstevel@tonic-gate return -1; 318*0Sstevel@tonic-gate } 319*0Sstevel@tonic-gate } 320*0Sstevel@tonic-gate 321*0Sstevel@tonic-gate /* 322*0Sstevel@tonic-gate ** SM_GETINFO -- get information about the open file 323*0Sstevel@tonic-gate ** 324*0Sstevel@tonic-gate ** Parameters: 325*0Sstevel@tonic-gate ** fp -- file to get info for 326*0Sstevel@tonic-gate ** what -- type of info to get 327*0Sstevel@tonic-gate ** valp -- location to place found info 328*0Sstevel@tonic-gate ** 329*0Sstevel@tonic-gate ** Returns: 330*0Sstevel@tonic-gate ** Success: may or may not place info in 'valp' depending 331*0Sstevel@tonic-gate ** on 'what' value, and returns values >=0. Return 332*0Sstevel@tonic-gate ** value may be the obtained info 333*0Sstevel@tonic-gate ** Failure: -1 and sets errno 334*0Sstevel@tonic-gate */ 335*0Sstevel@tonic-gate 336*0Sstevel@tonic-gate int 337*0Sstevel@tonic-gate sm_stdgetinfo(fp, what, valp) 338*0Sstevel@tonic-gate SM_FILE_T *fp; 339*0Sstevel@tonic-gate int what; 340*0Sstevel@tonic-gate void *valp; 341*0Sstevel@tonic-gate { 342*0Sstevel@tonic-gate switch (what) 343*0Sstevel@tonic-gate { 344*0Sstevel@tonic-gate case SM_IO_WHAT_MODE: 345*0Sstevel@tonic-gate return sm_stdgetmode(fp, (int *)valp); 346*0Sstevel@tonic-gate 347*0Sstevel@tonic-gate case SM_IO_WHAT_FD: 348*0Sstevel@tonic-gate return fp->f_file; 349*0Sstevel@tonic-gate 350*0Sstevel@tonic-gate case SM_IO_WHAT_SIZE: 351*0Sstevel@tonic-gate { 352*0Sstevel@tonic-gate struct stat st; 353*0Sstevel@tonic-gate 354*0Sstevel@tonic-gate if (fstat(fp->f_file, &st) == 0) 355*0Sstevel@tonic-gate return st.st_size; 356*0Sstevel@tonic-gate else 357*0Sstevel@tonic-gate return -1; 358*0Sstevel@tonic-gate } 359*0Sstevel@tonic-gate 360*0Sstevel@tonic-gate case SM_IO_IS_READABLE: 361*0Sstevel@tonic-gate { 362*0Sstevel@tonic-gate fd_set readfds; 363*0Sstevel@tonic-gate struct timeval timeout; 364*0Sstevel@tonic-gate 365*0Sstevel@tonic-gate if (SM_FD_SETSIZE > 0 && fp->f_file >= SM_FD_SETSIZE) 366*0Sstevel@tonic-gate { 367*0Sstevel@tonic-gate errno = EINVAL; 368*0Sstevel@tonic-gate return -1; 369*0Sstevel@tonic-gate } 370*0Sstevel@tonic-gate FD_ZERO(&readfds); 371*0Sstevel@tonic-gate SM_FD_SET(fp->f_file, &readfds); 372*0Sstevel@tonic-gate timeout.tv_sec = 0; 373*0Sstevel@tonic-gate timeout.tv_usec = 0; 374*0Sstevel@tonic-gate if (select(fp->f_file + 1, FDSET_CAST &readfds, 375*0Sstevel@tonic-gate NULL, NULL, &timeout) > 0 && 376*0Sstevel@tonic-gate SM_FD_ISSET(fp->f_file, &readfds)) 377*0Sstevel@tonic-gate return 1; 378*0Sstevel@tonic-gate return 0; 379*0Sstevel@tonic-gate } 380*0Sstevel@tonic-gate 381*0Sstevel@tonic-gate default: 382*0Sstevel@tonic-gate errno = EINVAL; 383*0Sstevel@tonic-gate return -1; 384*0Sstevel@tonic-gate } 385*0Sstevel@tonic-gate } 386*0Sstevel@tonic-gate 387*0Sstevel@tonic-gate /* 388*0Sstevel@tonic-gate ** SM_STDFDOPEN -- open file by primitive 'fd' rather than pathname 389*0Sstevel@tonic-gate ** 390*0Sstevel@tonic-gate ** I/O function to handle fdopen() stdio equivalence. The rest of 391*0Sstevel@tonic-gate ** the functions are the same as the sm_stdopen() above. 392*0Sstevel@tonic-gate ** 393*0Sstevel@tonic-gate ** Parameters: 394*0Sstevel@tonic-gate ** fp -- the file pointer to be associated with the open 395*0Sstevel@tonic-gate ** name -- the primitive file descriptor for association 396*0Sstevel@tonic-gate ** flags -- indicates type of access methods 397*0Sstevel@tonic-gate ** rpool -- ignored 398*0Sstevel@tonic-gate ** 399*0Sstevel@tonic-gate ** Results: 400*0Sstevel@tonic-gate ** Success: primitive file descriptor value 401*0Sstevel@tonic-gate ** Failure: -1 and sets errno 402*0Sstevel@tonic-gate */ 403*0Sstevel@tonic-gate 404*0Sstevel@tonic-gate /* ARGSUSED3 */ 405*0Sstevel@tonic-gate int 406*0Sstevel@tonic-gate sm_stdfdopen(fp, info, flags, rpool) 407*0Sstevel@tonic-gate SM_FILE_T *fp; 408*0Sstevel@tonic-gate const void *info; 409*0Sstevel@tonic-gate int flags; 410*0Sstevel@tonic-gate const void *rpool; 411*0Sstevel@tonic-gate { 412*0Sstevel@tonic-gate int oflags, tmp, fdflags, fd = *((int *) info); 413*0Sstevel@tonic-gate 414*0Sstevel@tonic-gate switch (SM_IO_MODE(flags)) 415*0Sstevel@tonic-gate { 416*0Sstevel@tonic-gate case SM_IO_RDWR: 417*0Sstevel@tonic-gate oflags = O_RDWR | O_CREAT; 418*0Sstevel@tonic-gate break; 419*0Sstevel@tonic-gate case SM_IO_RDONLY: 420*0Sstevel@tonic-gate oflags = O_RDONLY; 421*0Sstevel@tonic-gate break; 422*0Sstevel@tonic-gate case SM_IO_WRONLY: 423*0Sstevel@tonic-gate oflags = O_WRONLY | O_CREAT | O_TRUNC; 424*0Sstevel@tonic-gate break; 425*0Sstevel@tonic-gate case SM_IO_APPEND: 426*0Sstevel@tonic-gate oflags = O_APPEND | O_WRONLY | O_CREAT; 427*0Sstevel@tonic-gate break; 428*0Sstevel@tonic-gate case SM_IO_APPENDRW: 429*0Sstevel@tonic-gate oflags = O_APPEND | O_RDWR | O_CREAT; 430*0Sstevel@tonic-gate break; 431*0Sstevel@tonic-gate default: 432*0Sstevel@tonic-gate errno = EINVAL; 433*0Sstevel@tonic-gate return -1; 434*0Sstevel@tonic-gate } 435*0Sstevel@tonic-gate #ifdef O_BINARY 436*0Sstevel@tonic-gate if (SM_IS_BINARY(flags)) 437*0Sstevel@tonic-gate oflags |= O_BINARY; 438*0Sstevel@tonic-gate #endif /* O_BINARY */ 439*0Sstevel@tonic-gate 440*0Sstevel@tonic-gate /* Make sure the mode the user wants is a subset of the actual mode. */ 441*0Sstevel@tonic-gate if ((fdflags = fcntl(fd, F_GETFL, 0)) < 0) 442*0Sstevel@tonic-gate return -1; 443*0Sstevel@tonic-gate tmp = fdflags & O_ACCMODE; 444*0Sstevel@tonic-gate if (tmp != O_RDWR && (tmp != (oflags & O_ACCMODE))) 445*0Sstevel@tonic-gate { 446*0Sstevel@tonic-gate errno = EINVAL; 447*0Sstevel@tonic-gate return -1; 448*0Sstevel@tonic-gate } 449*0Sstevel@tonic-gate fp->f_file = fd; 450*0Sstevel@tonic-gate if (oflags & O_APPEND) 451*0Sstevel@tonic-gate (void) (*fp->f_seek)(fp, (off_t)0, SEEK_END); 452*0Sstevel@tonic-gate return fp->f_file; 453*0Sstevel@tonic-gate } 454*0Sstevel@tonic-gate 455*0Sstevel@tonic-gate /* 456*0Sstevel@tonic-gate ** SM_IO_FOPEN -- open a file 457*0Sstevel@tonic-gate ** 458*0Sstevel@tonic-gate ** Same interface and semantics as the open() system call, 459*0Sstevel@tonic-gate ** except that it returns SM_FILE_T* instead of a file descriptor. 460*0Sstevel@tonic-gate ** 461*0Sstevel@tonic-gate ** Parameters: 462*0Sstevel@tonic-gate ** pathname -- path of file to open 463*0Sstevel@tonic-gate ** flags -- flags controlling the open 464*0Sstevel@tonic-gate ** ... -- option "mode" for opening the file 465*0Sstevel@tonic-gate ** 466*0Sstevel@tonic-gate ** Returns: 467*0Sstevel@tonic-gate ** Raises an exception on heap exhaustion. 468*0Sstevel@tonic-gate ** Returns NULL and sets errno if open() fails. 469*0Sstevel@tonic-gate ** Returns an SM_FILE_T pointer on success. 470*0Sstevel@tonic-gate */ 471*0Sstevel@tonic-gate 472*0Sstevel@tonic-gate SM_FILE_T * 473*0Sstevel@tonic-gate #if SM_VA_STD 474*0Sstevel@tonic-gate sm_io_fopen(char *pathname, int flags, ...) 475*0Sstevel@tonic-gate #else /* SM_VA_STD */ 476*0Sstevel@tonic-gate sm_io_fopen(pathname, flags, va_alist) 477*0Sstevel@tonic-gate char *pathname; 478*0Sstevel@tonic-gate int flags; 479*0Sstevel@tonic-gate va_dcl 480*0Sstevel@tonic-gate #endif /* SM_VA_STD */ 481*0Sstevel@tonic-gate { 482*0Sstevel@tonic-gate MODE_T mode; 483*0Sstevel@tonic-gate SM_FILE_T *fp; 484*0Sstevel@tonic-gate int ioflags; 485*0Sstevel@tonic-gate 486*0Sstevel@tonic-gate if (flags & O_CREAT) 487*0Sstevel@tonic-gate { 488*0Sstevel@tonic-gate SM_VA_LOCAL_DECL 489*0Sstevel@tonic-gate 490*0Sstevel@tonic-gate SM_VA_START(ap, flags); 491*0Sstevel@tonic-gate mode = (MODE_T) SM_VA_ARG(ap, int); 492*0Sstevel@tonic-gate SM_VA_END(ap); 493*0Sstevel@tonic-gate } 494*0Sstevel@tonic-gate else 495*0Sstevel@tonic-gate mode = 0; 496*0Sstevel@tonic-gate 497*0Sstevel@tonic-gate switch (flags & O_ACCMODE) 498*0Sstevel@tonic-gate { 499*0Sstevel@tonic-gate case O_RDONLY: 500*0Sstevel@tonic-gate ioflags = SMRD; 501*0Sstevel@tonic-gate break; 502*0Sstevel@tonic-gate case O_WRONLY: 503*0Sstevel@tonic-gate ioflags = SMWR; 504*0Sstevel@tonic-gate break; 505*0Sstevel@tonic-gate case O_RDWR: 506*0Sstevel@tonic-gate ioflags = SMRW; 507*0Sstevel@tonic-gate break; 508*0Sstevel@tonic-gate default: 509*0Sstevel@tonic-gate sm_abort("sm_io_fopen: bad flags 0%o", flags); 510*0Sstevel@tonic-gate } 511*0Sstevel@tonic-gate 512*0Sstevel@tonic-gate fp = sm_fp(SmFtStdio, ioflags, NULL); 513*0Sstevel@tonic-gate fp->f_file = open(pathname, flags, mode); 514*0Sstevel@tonic-gate if (fp->f_file == -1) 515*0Sstevel@tonic-gate { 516*0Sstevel@tonic-gate fp->f_flags = 0; 517*0Sstevel@tonic-gate fp->sm_magic = NULL; 518*0Sstevel@tonic-gate return NULL; 519*0Sstevel@tonic-gate } 520*0Sstevel@tonic-gate return fp; 521*0Sstevel@tonic-gate } 522