190792Sgshapiro/* 2261363Sgshapiro * Copyright (c) 2000-2005 Proofpoint, Inc. and its suppliers. 390792Sgshapiro * All rights reserved. 490792Sgshapiro * Copyright (c) 1990, 1993 590792Sgshapiro * The Regents of the University of California. All rights reserved. 690792Sgshapiro * 790792Sgshapiro * This code is derived from software contributed to Berkeley by 890792Sgshapiro * Chris Torek. 990792Sgshapiro * 1090792Sgshapiro * By using this file, you agree to the terms and conditions set 1190792Sgshapiro * forth in the LICENSE file which can be found at the top level of 1290792Sgshapiro * the sendmail distribution. 1390792Sgshapiro */ 1490792Sgshapiro 1590792Sgshapiro#include <sm/gen.h> 16266692SgshapiroSM_RCSID("@(#)$Id: stdio.c,v 1.72 2013-11-22 20:51:43 ca Exp $") 1790792Sgshapiro#include <unistd.h> 1890792Sgshapiro#include <errno.h> 1990792Sgshapiro#include <fcntl.h> 2090792Sgshapiro#include <string.h> /* FreeBSD: FD_ZERO needs <string.h> */ 2190792Sgshapiro#include <sys/stat.h> 22157001Sgshapiro#include <sm/time.h> 2390792Sgshapiro#include <sm/heap.h> 2490792Sgshapiro#include <sm/assert.h> 2590792Sgshapiro#include <sm/varargs.h> 2690792Sgshapiro#include <sm/io.h> 2790792Sgshapiro#include <sm/setjmp.h> 2890792Sgshapiro#include <sm/conf.h> 29110560Sgshapiro#include <sm/fdset.h> 3090792Sgshapiro#include "local.h" 3190792Sgshapiro 32141858Sgshapirostatic int sm_stdsetmode __P((SM_FILE_T *, const int *)); 33141858Sgshapirostatic int sm_stdgetmode __P((SM_FILE_T *, int *)); 34141858Sgshapiro 3590792Sgshapiro/* 3690792Sgshapiro** Overall: 3790792Sgshapiro** Small standard I/O/seek/close functions. 3890792Sgshapiro** These maintain the `known seek offset' for seek optimization. 3990792Sgshapiro*/ 4090792Sgshapiro 4190792Sgshapiro/* 4290792Sgshapiro** SM_STDOPEN -- open a file with stdio behavior 4390792Sgshapiro** 4490792Sgshapiro** Not associated with the system's stdio in libc. 4590792Sgshapiro** 4690792Sgshapiro** Parameters: 4790792Sgshapiro** fp -- file pointer to be associated with the open 4890792Sgshapiro** info -- pathname of the file to be opened 4990792Sgshapiro** flags -- indicates type of access methods 5090792Sgshapiro** rpool -- ignored 5190792Sgshapiro** 5290792Sgshapiro** Returns: 5390792Sgshapiro** Failure: -1 and set errno 5490792Sgshapiro** Success: 0 or greater (fd of file from open(2)). 5590792Sgshapiro** 5690792Sgshapiro*/ 5790792Sgshapiro 5890792Sgshapiro/* ARGSUSED3 */ 5990792Sgshapiroint 6090792Sgshapirosm_stdopen(fp, info, flags, rpool) 6190792Sgshapiro SM_FILE_T *fp; 6290792Sgshapiro const void *info; 6390792Sgshapiro int flags; 6490792Sgshapiro const void *rpool; 6590792Sgshapiro{ 6690792Sgshapiro char *path = (char *) info; 6790792Sgshapiro int oflags; 6890792Sgshapiro 69120256Sgshapiro switch (SM_IO_MODE(flags)) 7090792Sgshapiro { 7190792Sgshapiro case SM_IO_RDWR: 7290792Sgshapiro oflags = O_RDWR; 7390792Sgshapiro break; 7490792Sgshapiro case SM_IO_RDWRTR: 7590792Sgshapiro oflags = O_RDWR | O_CREAT | O_TRUNC; 7690792Sgshapiro break; 7790792Sgshapiro case SM_IO_RDONLY: 7890792Sgshapiro oflags = O_RDONLY; 7990792Sgshapiro break; 8090792Sgshapiro case SM_IO_WRONLY: 8190792Sgshapiro oflags = O_WRONLY | O_CREAT | O_TRUNC; 8290792Sgshapiro break; 8390792Sgshapiro case SM_IO_APPEND: 8490792Sgshapiro oflags = O_APPEND | O_WRONLY | O_CREAT; 8590792Sgshapiro break; 8690792Sgshapiro case SM_IO_APPENDRW: 8790792Sgshapiro oflags = O_APPEND | O_RDWR | O_CREAT; 8890792Sgshapiro break; 8990792Sgshapiro default: 9090792Sgshapiro errno = EINVAL; 9190792Sgshapiro return -1; 9290792Sgshapiro } 93120256Sgshapiro#ifdef O_BINARY 94120256Sgshapiro if (SM_IS_BINARY(flags)) 95120256Sgshapiro oflags |= O_BINARY; 96120256Sgshapiro#endif /* O_BINARY */ 9790792Sgshapiro fp->f_file = open(path, oflags, 9890792Sgshapiro S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH); 9990792Sgshapiro if (fp->f_file < 0) 10090792Sgshapiro return -1; /* errno set by open() */ 10190792Sgshapiro 10290792Sgshapiro if (oflags & O_APPEND) 10390792Sgshapiro (void) (*fp->f_seek)((void *)fp, (off_t)0, SEEK_END); 10490792Sgshapiro 10590792Sgshapiro return fp->f_file; 10690792Sgshapiro} 10790792Sgshapiro 10890792Sgshapiro/* 10990792Sgshapiro** SM_STDREAD -- read from the file 11090792Sgshapiro** 11190792Sgshapiro** Parameters: 11290792Sgshapiro** fp -- file pointer to read from 11390792Sgshapiro** buf -- location to place read data 11490792Sgshapiro** n -- number of bytes to read 11590792Sgshapiro** 11690792Sgshapiro** Returns: 11790792Sgshapiro** Failure: -1 and sets errno 11890792Sgshapiro** Success: number of bytes read 11990792Sgshapiro** 12090792Sgshapiro** Side Effects: 12190792Sgshapiro** Updates internal offset into file. 12290792Sgshapiro*/ 12390792Sgshapiro 12490792Sgshapirossize_t 12590792Sgshapirosm_stdread(fp, buf, n) 12690792Sgshapiro SM_FILE_T *fp; 12790792Sgshapiro char *buf; 12890792Sgshapiro size_t n; 12990792Sgshapiro{ 13090792Sgshapiro register int ret; 13190792Sgshapiro 13290792Sgshapiro ret = read(fp->f_file, buf, n); 13390792Sgshapiro 13490792Sgshapiro /* if the read succeeded, update the current offset */ 13590792Sgshapiro if (ret > 0) 13690792Sgshapiro fp->f_lseekoff += ret; 13790792Sgshapiro return ret; 13890792Sgshapiro} 13990792Sgshapiro 14090792Sgshapiro/* 14190792Sgshapiro** SM_STDWRITE -- write to the file 14290792Sgshapiro** 14390792Sgshapiro** Parameters: 14490792Sgshapiro** fp -- file pointer ro write to 14590792Sgshapiro** buf -- location of data to be written 14690792Sgshapiro** n - number of bytes to write 14790792Sgshapiro** 14890792Sgshapiro** Returns: 14990792Sgshapiro** Failure: -1 and sets errno 15090792Sgshapiro** Success: number of bytes written 15190792Sgshapiro*/ 15290792Sgshapiro 15390792Sgshapirossize_t 15490792Sgshapirosm_stdwrite(fp, buf, n) 15590792Sgshapiro SM_FILE_T *fp; 15690792Sgshapiro char const *buf; 15790792Sgshapiro size_t n; 15890792Sgshapiro{ 15990792Sgshapiro return write(fp->f_file, buf, n); 16090792Sgshapiro} 16190792Sgshapiro 16290792Sgshapiro/* 16390792Sgshapiro** SM_STDSEEK -- set the file offset position 16490792Sgshapiro** 16590792Sgshapiro** Parmeters: 16690792Sgshapiro** fp -- file pointer to position 16790792Sgshapiro** offset -- how far to position from "base" (set by 'whence') 16890792Sgshapiro** whence -- indicates where the "base" of the 'offset' to start 16990792Sgshapiro** 17090792Sgshapiro** Results: 17190792Sgshapiro** Failure: -1 and sets errno 17290792Sgshapiro** Success: the current offset 17390792Sgshapiro** 17490792Sgshapiro** Side Effects: 17590792Sgshapiro** Updates the internal value of the offset. 17690792Sgshapiro*/ 17790792Sgshapiro 17890792Sgshapirooff_t 17990792Sgshapirosm_stdseek(fp, offset, whence) 18090792Sgshapiro SM_FILE_T *fp; 18190792Sgshapiro off_t offset; 18290792Sgshapiro int whence; 18390792Sgshapiro{ 18490792Sgshapiro register off_t ret; 18590792Sgshapiro 18690792Sgshapiro ret = lseek(fp->f_file, (off_t) offset, whence); 18790792Sgshapiro if (ret != (off_t) -1) 18890792Sgshapiro fp->f_lseekoff = ret; 18990792Sgshapiro return ret; 19090792Sgshapiro} 19190792Sgshapiro 19290792Sgshapiro/* 19390792Sgshapiro** SM_STDCLOSE -- close the file 19490792Sgshapiro** 19590792Sgshapiro** Parameters: 19690792Sgshapiro** fp -- the file pointer to close 19790792Sgshapiro** 19890792Sgshapiro** Returns: 19990792Sgshapiro** Success: 0 (zero) 20090792Sgshapiro** Failure: -1 and sets errno 20190792Sgshapiro*/ 20290792Sgshapiro 20390792Sgshapiroint 20490792Sgshapirosm_stdclose(fp) 20590792Sgshapiro SM_FILE_T *fp; 20690792Sgshapiro{ 20790792Sgshapiro return close(fp->f_file); 20890792Sgshapiro} 20990792Sgshapiro 21090792Sgshapiro/* 21190792Sgshapiro** SM_STDSETMODE -- set the access mode for the file 21290792Sgshapiro** 21390792Sgshapiro** Called by sm_stdsetinfo(). 21490792Sgshapiro** 21590792Sgshapiro** Parameters: 21690792Sgshapiro** fp -- file pointer 21790792Sgshapiro** mode -- new mode to set the file access to 21890792Sgshapiro** 21990792Sgshapiro** Results: 22090792Sgshapiro** Success: 0 (zero); 22190792Sgshapiro** Failure: -1 and sets errno 22290792Sgshapiro*/ 22390792Sgshapiro 224157001Sgshapirostatic int 22590792Sgshapirosm_stdsetmode(fp, mode) 22690792Sgshapiro SM_FILE_T *fp; 22790792Sgshapiro const int *mode; 22890792Sgshapiro{ 22990792Sgshapiro int flags = 0; 23090792Sgshapiro 231120256Sgshapiro switch (SM_IO_MODE(*mode)) 23290792Sgshapiro { 23390792Sgshapiro case SM_IO_RDWR: 23490792Sgshapiro flags |= SMRW; 23590792Sgshapiro break; 23690792Sgshapiro case SM_IO_RDONLY: 23790792Sgshapiro flags |= SMRD; 23890792Sgshapiro break; 23990792Sgshapiro case SM_IO_WRONLY: 24090792Sgshapiro flags |= SMWR; 24190792Sgshapiro break; 24290792Sgshapiro case SM_IO_APPEND: 24390792Sgshapiro default: 24490792Sgshapiro errno = EINVAL; 24590792Sgshapiro return -1; 24690792Sgshapiro } 24790792Sgshapiro fp->f_flags = fp->f_flags & ~SMMODEMASK; 24890792Sgshapiro fp->f_flags |= flags; 24990792Sgshapiro return 0; 25090792Sgshapiro} 25190792Sgshapiro 25290792Sgshapiro/* 25390792Sgshapiro** SM_STDGETMODE -- for getinfo determine open mode 25490792Sgshapiro** 25590792Sgshapiro** Called by sm_stdgetinfo(). 25690792Sgshapiro** 25790792Sgshapiro** Parameters: 25890792Sgshapiro** fp -- the file mode being determined 25990792Sgshapiro** mode -- internal mode to map to external value 26090792Sgshapiro** 26190792Sgshapiro** Results: 26290792Sgshapiro** Failure: -1 and sets errno 26390792Sgshapiro** Success: external mode value 26490792Sgshapiro*/ 26590792Sgshapiro 266141858Sgshapirostatic int 26790792Sgshapirosm_stdgetmode(fp, mode) 26890792Sgshapiro SM_FILE_T *fp; 26990792Sgshapiro int *mode; 27090792Sgshapiro{ 27190792Sgshapiro switch (fp->f_flags & SMMODEMASK) 27290792Sgshapiro { 27390792Sgshapiro case SMRW: 27490792Sgshapiro *mode = SM_IO_RDWR; 27590792Sgshapiro break; 27690792Sgshapiro case SMRD: 27790792Sgshapiro *mode = SM_IO_RDONLY; 27890792Sgshapiro break; 27990792Sgshapiro case SMWR: 28090792Sgshapiro *mode = SM_IO_WRONLY; 28190792Sgshapiro break; 28290792Sgshapiro default: 28390792Sgshapiro errno = EINVAL; 28490792Sgshapiro return -1; 28590792Sgshapiro } 28690792Sgshapiro return 0; 28790792Sgshapiro} 28890792Sgshapiro 28990792Sgshapiro/* 29090792Sgshapiro** SM_STDSETINFO -- set/modify information for a file 29190792Sgshapiro** 29290792Sgshapiro** Parameters: 29390792Sgshapiro** fp -- file to set info for 29490792Sgshapiro** what -- type of info to set 29590792Sgshapiro** valp -- location of data used for setting 29690792Sgshapiro** 29790792Sgshapiro** Returns: 29890792Sgshapiro** Failure: -1 and sets errno 29990792Sgshapiro** Success: >=0 30090792Sgshapiro*/ 30190792Sgshapiro 30290792Sgshapiroint 30390792Sgshapirosm_stdsetinfo(fp, what, valp) 30490792Sgshapiro SM_FILE_T *fp; 30590792Sgshapiro int what; 30690792Sgshapiro void *valp; 30790792Sgshapiro{ 30890792Sgshapiro switch (what) 30990792Sgshapiro { 31090792Sgshapiro case SM_IO_WHAT_MODE: 31190792Sgshapiro return sm_stdsetmode(fp, (const int *)valp); 31290792Sgshapiro 31390792Sgshapiro default: 31490792Sgshapiro errno = EINVAL; 31590792Sgshapiro return -1; 31690792Sgshapiro } 31790792Sgshapiro} 31890792Sgshapiro 31990792Sgshapiro/* 320285303Sgshapiro** SM_STDGETINFO -- get information about the open file 32190792Sgshapiro** 32290792Sgshapiro** Parameters: 32390792Sgshapiro** fp -- file to get info for 32490792Sgshapiro** what -- type of info to get 32590792Sgshapiro** valp -- location to place found info 32690792Sgshapiro** 32790792Sgshapiro** Returns: 32890792Sgshapiro** Success: may or may not place info in 'valp' depending 32990792Sgshapiro** on 'what' value, and returns values >=0. Return 33090792Sgshapiro** value may be the obtained info 33190792Sgshapiro** Failure: -1 and sets errno 33290792Sgshapiro*/ 33390792Sgshapiro 33490792Sgshapiroint 33590792Sgshapirosm_stdgetinfo(fp, what, valp) 33690792Sgshapiro SM_FILE_T *fp; 33790792Sgshapiro int what; 33890792Sgshapiro void *valp; 33990792Sgshapiro{ 34090792Sgshapiro switch (what) 34190792Sgshapiro { 34290792Sgshapiro case SM_IO_WHAT_MODE: 34390792Sgshapiro return sm_stdgetmode(fp, (int *)valp); 34490792Sgshapiro 34590792Sgshapiro case SM_IO_WHAT_FD: 34690792Sgshapiro return fp->f_file; 34790792Sgshapiro 34894334Sgshapiro case SM_IO_WHAT_SIZE: 34994334Sgshapiro { 35094334Sgshapiro struct stat st; 35194334Sgshapiro 35294334Sgshapiro if (fstat(fp->f_file, &st) == 0) 35394334Sgshapiro return st.st_size; 35494334Sgshapiro else 35594334Sgshapiro return -1; 35694334Sgshapiro } 35794334Sgshapiro 35890792Sgshapiro case SM_IO_IS_READABLE: 35994334Sgshapiro { 36094334Sgshapiro fd_set readfds; 36194334Sgshapiro struct timeval timeout; 36290792Sgshapiro 363110560Sgshapiro if (SM_FD_SETSIZE > 0 && fp->f_file >= SM_FD_SETSIZE) 364110560Sgshapiro { 365110560Sgshapiro errno = EINVAL; 366110560Sgshapiro return -1; 367110560Sgshapiro } 36894334Sgshapiro FD_ZERO(&readfds); 36994334Sgshapiro SM_FD_SET(fp->f_file, &readfds); 37094334Sgshapiro timeout.tv_sec = 0; 37194334Sgshapiro timeout.tv_usec = 0; 37294334Sgshapiro if (select(fp->f_file + 1, FDSET_CAST &readfds, 37394334Sgshapiro NULL, NULL, &timeout) > 0 && 37494334Sgshapiro SM_FD_ISSET(fp->f_file, &readfds)) 37594334Sgshapiro return 1; 37694334Sgshapiro return 0; 37794334Sgshapiro } 37890792Sgshapiro 37990792Sgshapiro default: 38090792Sgshapiro errno = EINVAL; 38190792Sgshapiro return -1; 38290792Sgshapiro } 38390792Sgshapiro} 38490792Sgshapiro 38590792Sgshapiro/* 38694334Sgshapiro** SM_STDFDOPEN -- open file by primitive 'fd' rather than pathname 38790792Sgshapiro** 38890792Sgshapiro** I/O function to handle fdopen() stdio equivalence. The rest of 38990792Sgshapiro** the functions are the same as the sm_stdopen() above. 39090792Sgshapiro** 39190792Sgshapiro** Parameters: 39290792Sgshapiro** fp -- the file pointer to be associated with the open 39394334Sgshapiro** name -- the primitive file descriptor for association 39490792Sgshapiro** flags -- indicates type of access methods 39590792Sgshapiro** rpool -- ignored 39690792Sgshapiro** 39790792Sgshapiro** Results: 39894334Sgshapiro** Success: primitive file descriptor value 39990792Sgshapiro** Failure: -1 and sets errno 40090792Sgshapiro*/ 40190792Sgshapiro 40290792Sgshapiro/* ARGSUSED3 */ 40390792Sgshapiroint 40490792Sgshapirosm_stdfdopen(fp, info, flags, rpool) 40590792Sgshapiro SM_FILE_T *fp; 40690792Sgshapiro const void *info; 40790792Sgshapiro int flags; 40890792Sgshapiro const void *rpool; 40990792Sgshapiro{ 41090792Sgshapiro int oflags, tmp, fdflags, fd = *((int *) info); 41190792Sgshapiro 412120256Sgshapiro switch (SM_IO_MODE(flags)) 41390792Sgshapiro { 41490792Sgshapiro case SM_IO_RDWR: 41590792Sgshapiro oflags = O_RDWR | O_CREAT; 41690792Sgshapiro break; 41790792Sgshapiro case SM_IO_RDONLY: 41890792Sgshapiro oflags = O_RDONLY; 41990792Sgshapiro break; 42090792Sgshapiro case SM_IO_WRONLY: 42190792Sgshapiro oflags = O_WRONLY | O_CREAT | O_TRUNC; 42290792Sgshapiro break; 42390792Sgshapiro case SM_IO_APPEND: 42490792Sgshapiro oflags = O_APPEND | O_WRONLY | O_CREAT; 42590792Sgshapiro break; 42690792Sgshapiro case SM_IO_APPENDRW: 42790792Sgshapiro oflags = O_APPEND | O_RDWR | O_CREAT; 42890792Sgshapiro break; 42990792Sgshapiro default: 43090792Sgshapiro errno = EINVAL; 43190792Sgshapiro return -1; 43290792Sgshapiro } 433120256Sgshapiro#ifdef O_BINARY 434120256Sgshapiro if (SM_IS_BINARY(flags)) 435120256Sgshapiro oflags |= O_BINARY; 436120256Sgshapiro#endif /* O_BINARY */ 43790792Sgshapiro 43890792Sgshapiro /* Make sure the mode the user wants is a subset of the actual mode. */ 43990792Sgshapiro if ((fdflags = fcntl(fd, F_GETFL, 0)) < 0) 44090792Sgshapiro return -1; 44190792Sgshapiro tmp = fdflags & O_ACCMODE; 44290792Sgshapiro if (tmp != O_RDWR && (tmp != (oflags & O_ACCMODE))) 44390792Sgshapiro { 44490792Sgshapiro errno = EINVAL; 44590792Sgshapiro return -1; 44690792Sgshapiro } 44790792Sgshapiro fp->f_file = fd; 44890792Sgshapiro if (oflags & O_APPEND) 44990792Sgshapiro (void) (*fp->f_seek)(fp, (off_t)0, SEEK_END); 45090792Sgshapiro return fp->f_file; 45190792Sgshapiro} 45290792Sgshapiro 45390792Sgshapiro/* 45490792Sgshapiro** SM_IO_FOPEN -- open a file 45590792Sgshapiro** 45690792Sgshapiro** Same interface and semantics as the open() system call, 45790792Sgshapiro** except that it returns SM_FILE_T* instead of a file descriptor. 45890792Sgshapiro** 45990792Sgshapiro** Parameters: 46090792Sgshapiro** pathname -- path of file to open 46190792Sgshapiro** flags -- flags controlling the open 46290792Sgshapiro** ... -- option "mode" for opening the file 46390792Sgshapiro** 46490792Sgshapiro** Returns: 46590792Sgshapiro** Raises an exception on heap exhaustion. 46690792Sgshapiro** Returns NULL and sets errno if open() fails. 46790792Sgshapiro** Returns an SM_FILE_T pointer on success. 46890792Sgshapiro*/ 46990792Sgshapiro 47090792SgshapiroSM_FILE_T * 47190792Sgshapiro#if SM_VA_STD 47290792Sgshapirosm_io_fopen(char *pathname, int flags, ...) 47390792Sgshapiro#else /* SM_VA_STD */ 47490792Sgshapirosm_io_fopen(pathname, flags, va_alist) 47590792Sgshapiro char *pathname; 47690792Sgshapiro int flags; 47790792Sgshapiro va_dcl 47890792Sgshapiro#endif /* SM_VA_STD */ 47990792Sgshapiro{ 48090792Sgshapiro MODE_T mode; 48190792Sgshapiro SM_FILE_T *fp; 48290792Sgshapiro int ioflags; 48390792Sgshapiro 48490792Sgshapiro if (flags & O_CREAT) 48590792Sgshapiro { 48690792Sgshapiro SM_VA_LOCAL_DECL 48790792Sgshapiro 48890792Sgshapiro SM_VA_START(ap, flags); 48990792Sgshapiro mode = (MODE_T) SM_VA_ARG(ap, int); 49090792Sgshapiro SM_VA_END(ap); 49190792Sgshapiro } 49290792Sgshapiro else 49390792Sgshapiro mode = 0; 49490792Sgshapiro 49590792Sgshapiro switch (flags & O_ACCMODE) 49690792Sgshapiro { 49790792Sgshapiro case O_RDONLY: 49890792Sgshapiro ioflags = SMRD; 49990792Sgshapiro break; 50090792Sgshapiro case O_WRONLY: 50190792Sgshapiro ioflags = SMWR; 50290792Sgshapiro break; 50390792Sgshapiro case O_RDWR: 50490792Sgshapiro ioflags = SMRW; 50590792Sgshapiro break; 50690792Sgshapiro default: 50790792Sgshapiro sm_abort("sm_io_fopen: bad flags 0%o", flags); 50890792Sgshapiro } 50990792Sgshapiro 51090792Sgshapiro fp = sm_fp(SmFtStdio, ioflags, NULL); 51190792Sgshapiro fp->f_file = open(pathname, flags, mode); 51290792Sgshapiro if (fp->f_file == -1) 51390792Sgshapiro { 51490792Sgshapiro fp->f_flags = 0; 51590792Sgshapiro fp->sm_magic = NULL; 51690792Sgshapiro return NULL; 51790792Sgshapiro } 51890792Sgshapiro return fp; 51990792Sgshapiro} 520