10Sstevel@tonic-gate /*
2*616Sjbeck * Copyright (c) 2000-2005 Sendmail, Inc. and its suppliers.
30Sstevel@tonic-gate * All rights reserved.
40Sstevel@tonic-gate * Copyright (c) 1990, 1993
50Sstevel@tonic-gate * The Regents of the University of California. All rights reserved.
60Sstevel@tonic-gate *
70Sstevel@tonic-gate * This code is derived from software contributed to Berkeley by
80Sstevel@tonic-gate * Chris Torek.
90Sstevel@tonic-gate *
100Sstevel@tonic-gate * By using this file, you agree to the terms and conditions set
110Sstevel@tonic-gate * forth in the LICENSE file which can be found at the top level of
120Sstevel@tonic-gate * the sendmail distribution.
130Sstevel@tonic-gate */
140Sstevel@tonic-gate
150Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
160Sstevel@tonic-gate
170Sstevel@tonic-gate #include <sm/gen.h>
18*616Sjbeck SM_RCSID("@(#)$Id: stdio.c,v 1.71 2005/06/14 23:07:20 ca Exp $")
190Sstevel@tonic-gate #include <unistd.h>
200Sstevel@tonic-gate #include <errno.h>
210Sstevel@tonic-gate #include <fcntl.h>
220Sstevel@tonic-gate #include <string.h> /* FreeBSD: FD_ZERO needs <string.h> */
230Sstevel@tonic-gate #include <sys/stat.h>
24*616Sjbeck #include <sm/time.h>
250Sstevel@tonic-gate #include <sm/heap.h>
260Sstevel@tonic-gate #include <sm/assert.h>
270Sstevel@tonic-gate #include <sm/varargs.h>
280Sstevel@tonic-gate #include <sm/io.h>
290Sstevel@tonic-gate #include <sm/setjmp.h>
300Sstevel@tonic-gate #include <sm/conf.h>
310Sstevel@tonic-gate #include <sm/fdset.h>
320Sstevel@tonic-gate #include "local.h"
330Sstevel@tonic-gate
340Sstevel@tonic-gate static int sm_stdsetmode __P((SM_FILE_T *, const int *));
350Sstevel@tonic-gate static int sm_stdgetmode __P((SM_FILE_T *, int *));
360Sstevel@tonic-gate
370Sstevel@tonic-gate /*
380Sstevel@tonic-gate ** Overall:
390Sstevel@tonic-gate ** Small standard I/O/seek/close functions.
400Sstevel@tonic-gate ** These maintain the `known seek offset' for seek optimization.
410Sstevel@tonic-gate */
420Sstevel@tonic-gate
430Sstevel@tonic-gate /*
440Sstevel@tonic-gate ** SM_STDOPEN -- open a file with stdio behavior
450Sstevel@tonic-gate **
460Sstevel@tonic-gate ** Not associated with the system's stdio in libc.
470Sstevel@tonic-gate **
480Sstevel@tonic-gate ** Parameters:
490Sstevel@tonic-gate ** fp -- file pointer to be associated with the open
500Sstevel@tonic-gate ** info -- pathname of the file to be opened
510Sstevel@tonic-gate ** flags -- indicates type of access methods
520Sstevel@tonic-gate ** rpool -- ignored
530Sstevel@tonic-gate **
540Sstevel@tonic-gate ** Returns:
550Sstevel@tonic-gate ** Failure: -1 and set errno
560Sstevel@tonic-gate ** Success: 0 or greater (fd of file from open(2)).
570Sstevel@tonic-gate **
580Sstevel@tonic-gate */
590Sstevel@tonic-gate
600Sstevel@tonic-gate /* ARGSUSED3 */
610Sstevel@tonic-gate int
sm_stdopen(fp,info,flags,rpool)620Sstevel@tonic-gate sm_stdopen(fp, info, flags, rpool)
630Sstevel@tonic-gate SM_FILE_T *fp;
640Sstevel@tonic-gate const void *info;
650Sstevel@tonic-gate int flags;
660Sstevel@tonic-gate const void *rpool;
670Sstevel@tonic-gate {
680Sstevel@tonic-gate char *path = (char *) info;
690Sstevel@tonic-gate int oflags;
700Sstevel@tonic-gate
710Sstevel@tonic-gate switch (SM_IO_MODE(flags))
720Sstevel@tonic-gate {
730Sstevel@tonic-gate case SM_IO_RDWR:
740Sstevel@tonic-gate oflags = O_RDWR;
750Sstevel@tonic-gate break;
760Sstevel@tonic-gate case SM_IO_RDWRTR:
770Sstevel@tonic-gate oflags = O_RDWR | O_CREAT | O_TRUNC;
780Sstevel@tonic-gate break;
790Sstevel@tonic-gate case SM_IO_RDONLY:
800Sstevel@tonic-gate oflags = O_RDONLY;
810Sstevel@tonic-gate break;
820Sstevel@tonic-gate case SM_IO_WRONLY:
830Sstevel@tonic-gate oflags = O_WRONLY | O_CREAT | O_TRUNC;
840Sstevel@tonic-gate break;
850Sstevel@tonic-gate case SM_IO_APPEND:
860Sstevel@tonic-gate oflags = O_APPEND | O_WRONLY | O_CREAT;
870Sstevel@tonic-gate break;
880Sstevel@tonic-gate case SM_IO_APPENDRW:
890Sstevel@tonic-gate oflags = O_APPEND | O_RDWR | O_CREAT;
900Sstevel@tonic-gate break;
910Sstevel@tonic-gate default:
920Sstevel@tonic-gate errno = EINVAL;
930Sstevel@tonic-gate return -1;
940Sstevel@tonic-gate }
950Sstevel@tonic-gate #ifdef O_BINARY
960Sstevel@tonic-gate if (SM_IS_BINARY(flags))
970Sstevel@tonic-gate oflags |= O_BINARY;
980Sstevel@tonic-gate #endif /* O_BINARY */
990Sstevel@tonic-gate fp->f_file = open(path, oflags,
1000Sstevel@tonic-gate S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
1010Sstevel@tonic-gate if (fp->f_file < 0)
1020Sstevel@tonic-gate return -1; /* errno set by open() */
1030Sstevel@tonic-gate
1040Sstevel@tonic-gate if (oflags & O_APPEND)
1050Sstevel@tonic-gate (void) (*fp->f_seek)((void *)fp, (off_t)0, SEEK_END);
1060Sstevel@tonic-gate
1070Sstevel@tonic-gate return fp->f_file;
1080Sstevel@tonic-gate }
1090Sstevel@tonic-gate
1100Sstevel@tonic-gate /*
1110Sstevel@tonic-gate ** SM_STDREAD -- read from the file
1120Sstevel@tonic-gate **
1130Sstevel@tonic-gate ** Parameters:
1140Sstevel@tonic-gate ** fp -- file pointer to read from
1150Sstevel@tonic-gate ** buf -- location to place read data
1160Sstevel@tonic-gate ** n -- number of bytes to read
1170Sstevel@tonic-gate **
1180Sstevel@tonic-gate ** Returns:
1190Sstevel@tonic-gate ** Failure: -1 and sets errno
1200Sstevel@tonic-gate ** Success: number of bytes read
1210Sstevel@tonic-gate **
1220Sstevel@tonic-gate ** Side Effects:
1230Sstevel@tonic-gate ** Updates internal offset into file.
1240Sstevel@tonic-gate */
1250Sstevel@tonic-gate
1260Sstevel@tonic-gate ssize_t
sm_stdread(fp,buf,n)1270Sstevel@tonic-gate sm_stdread(fp, buf, n)
1280Sstevel@tonic-gate SM_FILE_T *fp;
1290Sstevel@tonic-gate char *buf;
1300Sstevel@tonic-gate size_t n;
1310Sstevel@tonic-gate {
1320Sstevel@tonic-gate register int ret;
1330Sstevel@tonic-gate
1340Sstevel@tonic-gate ret = read(fp->f_file, buf, n);
1350Sstevel@tonic-gate
1360Sstevel@tonic-gate /* if the read succeeded, update the current offset */
1370Sstevel@tonic-gate if (ret > 0)
1380Sstevel@tonic-gate fp->f_lseekoff += ret;
1390Sstevel@tonic-gate return ret;
1400Sstevel@tonic-gate }
1410Sstevel@tonic-gate
1420Sstevel@tonic-gate /*
1430Sstevel@tonic-gate ** SM_STDWRITE -- write to the file
1440Sstevel@tonic-gate **
1450Sstevel@tonic-gate ** Parameters:
1460Sstevel@tonic-gate ** fp -- file pointer ro write to
1470Sstevel@tonic-gate ** buf -- location of data to be written
1480Sstevel@tonic-gate ** n - number of bytes to write
1490Sstevel@tonic-gate **
1500Sstevel@tonic-gate ** Returns:
1510Sstevel@tonic-gate ** Failure: -1 and sets errno
1520Sstevel@tonic-gate ** Success: number of bytes written
1530Sstevel@tonic-gate */
1540Sstevel@tonic-gate
1550Sstevel@tonic-gate ssize_t
sm_stdwrite(fp,buf,n)1560Sstevel@tonic-gate sm_stdwrite(fp, buf, n)
1570Sstevel@tonic-gate SM_FILE_T *fp;
1580Sstevel@tonic-gate char const *buf;
1590Sstevel@tonic-gate size_t n;
1600Sstevel@tonic-gate {
1610Sstevel@tonic-gate return write(fp->f_file, buf, n);
1620Sstevel@tonic-gate }
1630Sstevel@tonic-gate
1640Sstevel@tonic-gate /*
1650Sstevel@tonic-gate ** SM_STDSEEK -- set the file offset position
1660Sstevel@tonic-gate **
1670Sstevel@tonic-gate ** Parmeters:
1680Sstevel@tonic-gate ** fp -- file pointer to position
1690Sstevel@tonic-gate ** offset -- how far to position from "base" (set by 'whence')
1700Sstevel@tonic-gate ** whence -- indicates where the "base" of the 'offset' to start
1710Sstevel@tonic-gate **
1720Sstevel@tonic-gate ** Results:
1730Sstevel@tonic-gate ** Failure: -1 and sets errno
1740Sstevel@tonic-gate ** Success: the current offset
1750Sstevel@tonic-gate **
1760Sstevel@tonic-gate ** Side Effects:
1770Sstevel@tonic-gate ** Updates the internal value of the offset.
1780Sstevel@tonic-gate */
1790Sstevel@tonic-gate
1800Sstevel@tonic-gate off_t
sm_stdseek(fp,offset,whence)1810Sstevel@tonic-gate sm_stdseek(fp, offset, whence)
1820Sstevel@tonic-gate SM_FILE_T *fp;
1830Sstevel@tonic-gate off_t offset;
1840Sstevel@tonic-gate int whence;
1850Sstevel@tonic-gate {
1860Sstevel@tonic-gate register off_t ret;
1870Sstevel@tonic-gate
1880Sstevel@tonic-gate ret = lseek(fp->f_file, (off_t) offset, whence);
1890Sstevel@tonic-gate if (ret != (off_t) -1)
1900Sstevel@tonic-gate fp->f_lseekoff = ret;
1910Sstevel@tonic-gate return ret;
1920Sstevel@tonic-gate }
1930Sstevel@tonic-gate
1940Sstevel@tonic-gate /*
1950Sstevel@tonic-gate ** SM_STDCLOSE -- close the file
1960Sstevel@tonic-gate **
1970Sstevel@tonic-gate ** Parameters:
1980Sstevel@tonic-gate ** fp -- the file pointer to close
1990Sstevel@tonic-gate **
2000Sstevel@tonic-gate ** Returns:
2010Sstevel@tonic-gate ** Success: 0 (zero)
2020Sstevel@tonic-gate ** Failure: -1 and sets errno
2030Sstevel@tonic-gate */
2040Sstevel@tonic-gate
2050Sstevel@tonic-gate int
sm_stdclose(fp)2060Sstevel@tonic-gate sm_stdclose(fp)
2070Sstevel@tonic-gate SM_FILE_T *fp;
2080Sstevel@tonic-gate {
2090Sstevel@tonic-gate return close(fp->f_file);
2100Sstevel@tonic-gate }
2110Sstevel@tonic-gate
2120Sstevel@tonic-gate /*
2130Sstevel@tonic-gate ** SM_STDSETMODE -- set the access mode for the file
2140Sstevel@tonic-gate **
2150Sstevel@tonic-gate ** Called by sm_stdsetinfo().
2160Sstevel@tonic-gate **
2170Sstevel@tonic-gate ** Parameters:
2180Sstevel@tonic-gate ** fp -- file pointer
2190Sstevel@tonic-gate ** mode -- new mode to set the file access to
2200Sstevel@tonic-gate **
2210Sstevel@tonic-gate ** Results:
2220Sstevel@tonic-gate ** Success: 0 (zero);
2230Sstevel@tonic-gate ** Failure: -1 and sets errno
2240Sstevel@tonic-gate */
2250Sstevel@tonic-gate
226*616Sjbeck static int
sm_stdsetmode(fp,mode)2270Sstevel@tonic-gate sm_stdsetmode(fp, mode)
2280Sstevel@tonic-gate SM_FILE_T *fp;
2290Sstevel@tonic-gate const int *mode;
2300Sstevel@tonic-gate {
2310Sstevel@tonic-gate int flags = 0;
2320Sstevel@tonic-gate
2330Sstevel@tonic-gate switch (SM_IO_MODE(*mode))
2340Sstevel@tonic-gate {
2350Sstevel@tonic-gate case SM_IO_RDWR:
2360Sstevel@tonic-gate flags |= SMRW;
2370Sstevel@tonic-gate break;
2380Sstevel@tonic-gate case SM_IO_RDONLY:
2390Sstevel@tonic-gate flags |= SMRD;
2400Sstevel@tonic-gate break;
2410Sstevel@tonic-gate case SM_IO_WRONLY:
2420Sstevel@tonic-gate flags |= SMWR;
2430Sstevel@tonic-gate break;
2440Sstevel@tonic-gate case SM_IO_APPEND:
2450Sstevel@tonic-gate default:
2460Sstevel@tonic-gate errno = EINVAL;
2470Sstevel@tonic-gate return -1;
2480Sstevel@tonic-gate }
2490Sstevel@tonic-gate fp->f_flags = fp->f_flags & ~SMMODEMASK;
2500Sstevel@tonic-gate fp->f_flags |= flags;
2510Sstevel@tonic-gate return 0;
2520Sstevel@tonic-gate }
2530Sstevel@tonic-gate
2540Sstevel@tonic-gate /*
2550Sstevel@tonic-gate ** SM_STDGETMODE -- for getinfo determine open mode
2560Sstevel@tonic-gate **
2570Sstevel@tonic-gate ** Called by sm_stdgetinfo().
2580Sstevel@tonic-gate **
2590Sstevel@tonic-gate ** Parameters:
2600Sstevel@tonic-gate ** fp -- the file mode being determined
2610Sstevel@tonic-gate ** mode -- internal mode to map to external value
2620Sstevel@tonic-gate **
2630Sstevel@tonic-gate ** Results:
2640Sstevel@tonic-gate ** Failure: -1 and sets errno
2650Sstevel@tonic-gate ** Success: external mode value
2660Sstevel@tonic-gate */
2670Sstevel@tonic-gate
2680Sstevel@tonic-gate static int
sm_stdgetmode(fp,mode)2690Sstevel@tonic-gate sm_stdgetmode(fp, mode)
2700Sstevel@tonic-gate SM_FILE_T *fp;
2710Sstevel@tonic-gate int *mode;
2720Sstevel@tonic-gate {
2730Sstevel@tonic-gate switch (fp->f_flags & SMMODEMASK)
2740Sstevel@tonic-gate {
2750Sstevel@tonic-gate case SMRW:
2760Sstevel@tonic-gate *mode = SM_IO_RDWR;
2770Sstevel@tonic-gate break;
2780Sstevel@tonic-gate case SMRD:
2790Sstevel@tonic-gate *mode = SM_IO_RDONLY;
2800Sstevel@tonic-gate break;
2810Sstevel@tonic-gate case SMWR:
2820Sstevel@tonic-gate *mode = SM_IO_WRONLY;
2830Sstevel@tonic-gate break;
2840Sstevel@tonic-gate default:
2850Sstevel@tonic-gate errno = EINVAL;
2860Sstevel@tonic-gate return -1;
2870Sstevel@tonic-gate }
2880Sstevel@tonic-gate return 0;
2890Sstevel@tonic-gate }
2900Sstevel@tonic-gate
2910Sstevel@tonic-gate /*
2920Sstevel@tonic-gate ** SM_STDSETINFO -- set/modify information for a file
2930Sstevel@tonic-gate **
2940Sstevel@tonic-gate ** Parameters:
2950Sstevel@tonic-gate ** fp -- file to set info for
2960Sstevel@tonic-gate ** what -- type of info to set
2970Sstevel@tonic-gate ** valp -- location of data used for setting
2980Sstevel@tonic-gate **
2990Sstevel@tonic-gate ** Returns:
3000Sstevel@tonic-gate ** Failure: -1 and sets errno
3010Sstevel@tonic-gate ** Success: >=0
3020Sstevel@tonic-gate */
3030Sstevel@tonic-gate
3040Sstevel@tonic-gate int
sm_stdsetinfo(fp,what,valp)3050Sstevel@tonic-gate sm_stdsetinfo(fp, what, valp)
3060Sstevel@tonic-gate SM_FILE_T *fp;
3070Sstevel@tonic-gate int what;
3080Sstevel@tonic-gate void *valp;
3090Sstevel@tonic-gate {
3100Sstevel@tonic-gate switch (what)
3110Sstevel@tonic-gate {
3120Sstevel@tonic-gate case SM_IO_WHAT_MODE:
3130Sstevel@tonic-gate return sm_stdsetmode(fp, (const int *)valp);
3140Sstevel@tonic-gate
3150Sstevel@tonic-gate default:
3160Sstevel@tonic-gate errno = EINVAL;
3170Sstevel@tonic-gate return -1;
3180Sstevel@tonic-gate }
3190Sstevel@tonic-gate }
3200Sstevel@tonic-gate
3210Sstevel@tonic-gate /*
3220Sstevel@tonic-gate ** SM_GETINFO -- get information about the open file
3230Sstevel@tonic-gate **
3240Sstevel@tonic-gate ** Parameters:
3250Sstevel@tonic-gate ** fp -- file to get info for
3260Sstevel@tonic-gate ** what -- type of info to get
3270Sstevel@tonic-gate ** valp -- location to place found info
3280Sstevel@tonic-gate **
3290Sstevel@tonic-gate ** Returns:
3300Sstevel@tonic-gate ** Success: may or may not place info in 'valp' depending
3310Sstevel@tonic-gate ** on 'what' value, and returns values >=0. Return
3320Sstevel@tonic-gate ** value may be the obtained info
3330Sstevel@tonic-gate ** Failure: -1 and sets errno
3340Sstevel@tonic-gate */
3350Sstevel@tonic-gate
3360Sstevel@tonic-gate int
sm_stdgetinfo(fp,what,valp)3370Sstevel@tonic-gate sm_stdgetinfo(fp, what, valp)
3380Sstevel@tonic-gate SM_FILE_T *fp;
3390Sstevel@tonic-gate int what;
3400Sstevel@tonic-gate void *valp;
3410Sstevel@tonic-gate {
3420Sstevel@tonic-gate switch (what)
3430Sstevel@tonic-gate {
3440Sstevel@tonic-gate case SM_IO_WHAT_MODE:
3450Sstevel@tonic-gate return sm_stdgetmode(fp, (int *)valp);
3460Sstevel@tonic-gate
3470Sstevel@tonic-gate case SM_IO_WHAT_FD:
3480Sstevel@tonic-gate return fp->f_file;
3490Sstevel@tonic-gate
3500Sstevel@tonic-gate case SM_IO_WHAT_SIZE:
3510Sstevel@tonic-gate {
3520Sstevel@tonic-gate struct stat st;
3530Sstevel@tonic-gate
3540Sstevel@tonic-gate if (fstat(fp->f_file, &st) == 0)
3550Sstevel@tonic-gate return st.st_size;
3560Sstevel@tonic-gate else
3570Sstevel@tonic-gate return -1;
3580Sstevel@tonic-gate }
3590Sstevel@tonic-gate
3600Sstevel@tonic-gate case SM_IO_IS_READABLE:
3610Sstevel@tonic-gate {
3620Sstevel@tonic-gate fd_set readfds;
3630Sstevel@tonic-gate struct timeval timeout;
3640Sstevel@tonic-gate
3650Sstevel@tonic-gate if (SM_FD_SETSIZE > 0 && fp->f_file >= SM_FD_SETSIZE)
3660Sstevel@tonic-gate {
3670Sstevel@tonic-gate errno = EINVAL;
3680Sstevel@tonic-gate return -1;
3690Sstevel@tonic-gate }
3700Sstevel@tonic-gate FD_ZERO(&readfds);
3710Sstevel@tonic-gate SM_FD_SET(fp->f_file, &readfds);
3720Sstevel@tonic-gate timeout.tv_sec = 0;
3730Sstevel@tonic-gate timeout.tv_usec = 0;
3740Sstevel@tonic-gate if (select(fp->f_file + 1, FDSET_CAST &readfds,
3750Sstevel@tonic-gate NULL, NULL, &timeout) > 0 &&
3760Sstevel@tonic-gate SM_FD_ISSET(fp->f_file, &readfds))
3770Sstevel@tonic-gate return 1;
3780Sstevel@tonic-gate return 0;
3790Sstevel@tonic-gate }
3800Sstevel@tonic-gate
3810Sstevel@tonic-gate default:
3820Sstevel@tonic-gate errno = EINVAL;
3830Sstevel@tonic-gate return -1;
3840Sstevel@tonic-gate }
3850Sstevel@tonic-gate }
3860Sstevel@tonic-gate
3870Sstevel@tonic-gate /*
3880Sstevel@tonic-gate ** SM_STDFDOPEN -- open file by primitive 'fd' rather than pathname
3890Sstevel@tonic-gate **
3900Sstevel@tonic-gate ** I/O function to handle fdopen() stdio equivalence. The rest of
3910Sstevel@tonic-gate ** the functions are the same as the sm_stdopen() above.
3920Sstevel@tonic-gate **
3930Sstevel@tonic-gate ** Parameters:
3940Sstevel@tonic-gate ** fp -- the file pointer to be associated with the open
3950Sstevel@tonic-gate ** name -- the primitive file descriptor for association
3960Sstevel@tonic-gate ** flags -- indicates type of access methods
3970Sstevel@tonic-gate ** rpool -- ignored
3980Sstevel@tonic-gate **
3990Sstevel@tonic-gate ** Results:
4000Sstevel@tonic-gate ** Success: primitive file descriptor value
4010Sstevel@tonic-gate ** Failure: -1 and sets errno
4020Sstevel@tonic-gate */
4030Sstevel@tonic-gate
4040Sstevel@tonic-gate /* ARGSUSED3 */
4050Sstevel@tonic-gate int
sm_stdfdopen(fp,info,flags,rpool)4060Sstevel@tonic-gate sm_stdfdopen(fp, info, flags, rpool)
4070Sstevel@tonic-gate SM_FILE_T *fp;
4080Sstevel@tonic-gate const void *info;
4090Sstevel@tonic-gate int flags;
4100Sstevel@tonic-gate const void *rpool;
4110Sstevel@tonic-gate {
4120Sstevel@tonic-gate int oflags, tmp, fdflags, fd = *((int *) info);
4130Sstevel@tonic-gate
4140Sstevel@tonic-gate switch (SM_IO_MODE(flags))
4150Sstevel@tonic-gate {
4160Sstevel@tonic-gate case SM_IO_RDWR:
4170Sstevel@tonic-gate oflags = O_RDWR | O_CREAT;
4180Sstevel@tonic-gate break;
4190Sstevel@tonic-gate case SM_IO_RDONLY:
4200Sstevel@tonic-gate oflags = O_RDONLY;
4210Sstevel@tonic-gate break;
4220Sstevel@tonic-gate case SM_IO_WRONLY:
4230Sstevel@tonic-gate oflags = O_WRONLY | O_CREAT | O_TRUNC;
4240Sstevel@tonic-gate break;
4250Sstevel@tonic-gate case SM_IO_APPEND:
4260Sstevel@tonic-gate oflags = O_APPEND | O_WRONLY | O_CREAT;
4270Sstevel@tonic-gate break;
4280Sstevel@tonic-gate case SM_IO_APPENDRW:
4290Sstevel@tonic-gate oflags = O_APPEND | O_RDWR | O_CREAT;
4300Sstevel@tonic-gate break;
4310Sstevel@tonic-gate default:
4320Sstevel@tonic-gate errno = EINVAL;
4330Sstevel@tonic-gate return -1;
4340Sstevel@tonic-gate }
4350Sstevel@tonic-gate #ifdef O_BINARY
4360Sstevel@tonic-gate if (SM_IS_BINARY(flags))
4370Sstevel@tonic-gate oflags |= O_BINARY;
4380Sstevel@tonic-gate #endif /* O_BINARY */
4390Sstevel@tonic-gate
4400Sstevel@tonic-gate /* Make sure the mode the user wants is a subset of the actual mode. */
4410Sstevel@tonic-gate if ((fdflags = fcntl(fd, F_GETFL, 0)) < 0)
4420Sstevel@tonic-gate return -1;
4430Sstevel@tonic-gate tmp = fdflags & O_ACCMODE;
4440Sstevel@tonic-gate if (tmp != O_RDWR && (tmp != (oflags & O_ACCMODE)))
4450Sstevel@tonic-gate {
4460Sstevel@tonic-gate errno = EINVAL;
4470Sstevel@tonic-gate return -1;
4480Sstevel@tonic-gate }
4490Sstevel@tonic-gate fp->f_file = fd;
4500Sstevel@tonic-gate if (oflags & O_APPEND)
4510Sstevel@tonic-gate (void) (*fp->f_seek)(fp, (off_t)0, SEEK_END);
4520Sstevel@tonic-gate return fp->f_file;
4530Sstevel@tonic-gate }
4540Sstevel@tonic-gate
4550Sstevel@tonic-gate /*
4560Sstevel@tonic-gate ** SM_IO_FOPEN -- open a file
4570Sstevel@tonic-gate **
4580Sstevel@tonic-gate ** Same interface and semantics as the open() system call,
4590Sstevel@tonic-gate ** except that it returns SM_FILE_T* instead of a file descriptor.
4600Sstevel@tonic-gate **
4610Sstevel@tonic-gate ** Parameters:
4620Sstevel@tonic-gate ** pathname -- path of file to open
4630Sstevel@tonic-gate ** flags -- flags controlling the open
4640Sstevel@tonic-gate ** ... -- option "mode" for opening the file
4650Sstevel@tonic-gate **
4660Sstevel@tonic-gate ** Returns:
4670Sstevel@tonic-gate ** Raises an exception on heap exhaustion.
4680Sstevel@tonic-gate ** Returns NULL and sets errno if open() fails.
4690Sstevel@tonic-gate ** Returns an SM_FILE_T pointer on success.
4700Sstevel@tonic-gate */
4710Sstevel@tonic-gate
4720Sstevel@tonic-gate SM_FILE_T *
4730Sstevel@tonic-gate #if SM_VA_STD
sm_io_fopen(char * pathname,int flags,...)4740Sstevel@tonic-gate sm_io_fopen(char *pathname, int flags, ...)
4750Sstevel@tonic-gate #else /* SM_VA_STD */
4760Sstevel@tonic-gate sm_io_fopen(pathname, flags, va_alist)
4770Sstevel@tonic-gate char *pathname;
4780Sstevel@tonic-gate int flags;
4790Sstevel@tonic-gate va_dcl
4800Sstevel@tonic-gate #endif /* SM_VA_STD */
4810Sstevel@tonic-gate {
4820Sstevel@tonic-gate MODE_T mode;
4830Sstevel@tonic-gate SM_FILE_T *fp;
4840Sstevel@tonic-gate int ioflags;
4850Sstevel@tonic-gate
4860Sstevel@tonic-gate if (flags & O_CREAT)
4870Sstevel@tonic-gate {
4880Sstevel@tonic-gate SM_VA_LOCAL_DECL
4890Sstevel@tonic-gate
4900Sstevel@tonic-gate SM_VA_START(ap, flags);
4910Sstevel@tonic-gate mode = (MODE_T) SM_VA_ARG(ap, int);
4920Sstevel@tonic-gate SM_VA_END(ap);
4930Sstevel@tonic-gate }
4940Sstevel@tonic-gate else
4950Sstevel@tonic-gate mode = 0;
4960Sstevel@tonic-gate
4970Sstevel@tonic-gate switch (flags & O_ACCMODE)
4980Sstevel@tonic-gate {
4990Sstevel@tonic-gate case O_RDONLY:
5000Sstevel@tonic-gate ioflags = SMRD;
5010Sstevel@tonic-gate break;
5020Sstevel@tonic-gate case O_WRONLY:
5030Sstevel@tonic-gate ioflags = SMWR;
5040Sstevel@tonic-gate break;
5050Sstevel@tonic-gate case O_RDWR:
5060Sstevel@tonic-gate ioflags = SMRW;
5070Sstevel@tonic-gate break;
5080Sstevel@tonic-gate default:
5090Sstevel@tonic-gate sm_abort("sm_io_fopen: bad flags 0%o", flags);
5100Sstevel@tonic-gate }
5110Sstevel@tonic-gate
5120Sstevel@tonic-gate fp = sm_fp(SmFtStdio, ioflags, NULL);
5130Sstevel@tonic-gate fp->f_file = open(pathname, flags, mode);
5140Sstevel@tonic-gate if (fp->f_file == -1)
5150Sstevel@tonic-gate {
5160Sstevel@tonic-gate fp->f_flags = 0;
5170Sstevel@tonic-gate fp->sm_magic = NULL;
5180Sstevel@tonic-gate return NULL;
5190Sstevel@tonic-gate }
5200Sstevel@tonic-gate return fp;
5210Sstevel@tonic-gate }
522