190792Sgshapiro/* 2132943Sgshapiro * Copyright (c) 2000-2002, 2004 Sendmail, Inc. and its suppliers. 390792Sgshapiro * All rights reserved. 490792Sgshapiro * 590792Sgshapiro * By using this file, you agree to the terms and conditions set 690792Sgshapiro * forth in the LICENSE file which can be found at the top level of 790792Sgshapiro * the sendmail distribution. 890792Sgshapiro */ 990792Sgshapiro 1090792Sgshapiro#include <sm/gen.h> 11141858SgshapiroSM_IDSTR(id, "@(#)$Id: smstdio.c,v 1.34 2004/08/03 20:46:34 ca Exp $") 1290792Sgshapiro#include <unistd.h> 1390792Sgshapiro#include <stdio.h> 1490792Sgshapiro#include <fcntl.h> 1590792Sgshapiro#include <errno.h> 1694334Sgshapiro#include <sys/stat.h> 1790792Sgshapiro#include <sm/assert.h> 1890792Sgshapiro#include <sm/io.h> 1990792Sgshapiro#include <sm/string.h> 2090792Sgshapiro#include "local.h" 2190792Sgshapiro 22141858Sgshapirostatic void setup __P((SM_FILE_T *)); 23141858Sgshapiro 2490792Sgshapiro/* 2590792Sgshapiro** Overall: 2690792Sgshapiro** This is a file type which implements a layer on top of the system 2790792Sgshapiro** stdio. fp->f_cookie is the FILE* of stdio. The cookie may be 2890792Sgshapiro** "bound late" because of the manner which Linux implements stdio. 2990792Sgshapiro** When binding late (when fp->f_cookie==NULL) then the value of 3090792Sgshapiro** fp->f_ival is used (0, 1 or 2) to map to stdio's stdin, stdout or 3190792Sgshapiro** stderr. 3290792Sgshapiro*/ 3390792Sgshapiro 3490792Sgshapiro/* 3590792Sgshapiro** SM_STDIOOPEN -- open a file to system stdio implementation 3690792Sgshapiro** 3790792Sgshapiro** Parameters: 3890792Sgshapiro** fp -- file pointer assign for this open 3990792Sgshapiro** info -- info about file to open 4090792Sgshapiro** flags -- indicating method of opening 4190792Sgshapiro** rpool -- ignored 4290792Sgshapiro** 4390792Sgshapiro** Returns: 4490792Sgshapiro** Failure: -1 4590792Sgshapiro** Success: 0 (zero) 4690792Sgshapiro*/ 4790792Sgshapiro 4890792Sgshapiro/* ARGSUSED3 */ 4990792Sgshapiroint 5090792Sgshapirosm_stdioopen(fp, info, flags, rpool) 5190792Sgshapiro SM_FILE_T *fp; 5290792Sgshapiro const void *info; 5390792Sgshapiro int flags; 5490792Sgshapiro const void *rpool; 5590792Sgshapiro{ 5690792Sgshapiro register FILE *s; 5790792Sgshapiro char *stdiomode; 5890792Sgshapiro 5990792Sgshapiro switch (flags) 6090792Sgshapiro { 6190792Sgshapiro case SM_IO_RDONLY: 6290792Sgshapiro stdiomode = "r"; 6390792Sgshapiro break; 6490792Sgshapiro case SM_IO_WRONLY: 6590792Sgshapiro stdiomode = "w"; 6690792Sgshapiro break; 6790792Sgshapiro case SM_IO_APPEND: 6890792Sgshapiro stdiomode = "a"; 6990792Sgshapiro break; 7090792Sgshapiro case SM_IO_APPENDRW: 7190792Sgshapiro stdiomode = "a+"; 7290792Sgshapiro break; 73120256Sgshapiro#if SM_IO_BINARY != 0 74120256Sgshapiro case SM_IO_RDONLY_B: 75120256Sgshapiro stdiomode = "rb"; 76120256Sgshapiro break; 77120256Sgshapiro case SM_IO_WRONLY_B: 78120256Sgshapiro stdiomode = "wb"; 79120256Sgshapiro break; 80120256Sgshapiro case SM_IO_APPEND_B: 81120256Sgshapiro stdiomode = "ab"; 82120256Sgshapiro break; 83120256Sgshapiro case SM_IO_APPENDRW_B: 84120256Sgshapiro stdiomode = "a+b"; 85120256Sgshapiro break; 86120256Sgshapiro case SM_IO_RDWR_B: 87120256Sgshapiro stdiomode = "r+b"; 88120256Sgshapiro break; 89120256Sgshapiro#endif /* SM_IO_BINARY != 0 */ 9090792Sgshapiro case SM_IO_RDWR: 9190792Sgshapiro default: 9290792Sgshapiro stdiomode = "r+"; 9390792Sgshapiro break; 9490792Sgshapiro } 9590792Sgshapiro 9690792Sgshapiro if ((s = fopen((char *)info, stdiomode)) == NULL) 9790792Sgshapiro return -1; 9890792Sgshapiro fp->f_cookie = s; 9990792Sgshapiro return 0; 10090792Sgshapiro} 10190792Sgshapiro 10290792Sgshapiro/* 10390792Sgshapiro** SETUP -- assign file type cookie when not already assigned 10490792Sgshapiro** 10590792Sgshapiro** Parameters: 10690792Sgshapiro** fp - the file pointer to get the cookie assigned 10790792Sgshapiro** 10890792Sgshapiro** Return: 10990792Sgshapiro** none. 11090792Sgshapiro*/ 11190792Sgshapiro 11290792Sgshapirostatic void 11390792Sgshapirosetup(fp) 11490792Sgshapiro SM_FILE_T *fp; 11590792Sgshapiro{ 11690792Sgshapiro if (fp->f_cookie == NULL) 11790792Sgshapiro { 11890792Sgshapiro switch (fp->f_ival) 11990792Sgshapiro { 12090792Sgshapiro case 0: 12190792Sgshapiro fp->f_cookie = stdin; 12290792Sgshapiro break; 12390792Sgshapiro case 1: 12490792Sgshapiro fp->f_cookie = stdout; 12590792Sgshapiro break; 12690792Sgshapiro case 2: 12790792Sgshapiro fp->f_cookie = stderr; 12890792Sgshapiro break; 12990792Sgshapiro default: 13090792Sgshapiro sm_abort("fp->f_ival=%d: out of range (0...2)", fp->f_ival); 13190792Sgshapiro break; 13290792Sgshapiro } 13390792Sgshapiro } 13490792Sgshapiro} 13590792Sgshapiro 13690792Sgshapiro/* 13790792Sgshapiro** SM_STDIOREAD -- read from the file 13890792Sgshapiro** 13990792Sgshapiro** Parameters: 14090792Sgshapiro** fp -- the file pointer 14190792Sgshapiro** buf -- location to place the read data 14290792Sgshapiro** n - number of bytes to read 14390792Sgshapiro** 14490792Sgshapiro** Returns: 14590792Sgshapiro** result from fread(). 14690792Sgshapiro*/ 14790792Sgshapiro 14890792Sgshapirossize_t 14990792Sgshapirosm_stdioread(fp, buf, n) 15090792Sgshapiro SM_FILE_T *fp; 15190792Sgshapiro char *buf; 15290792Sgshapiro size_t n; 15390792Sgshapiro{ 15490792Sgshapiro register FILE *s; 15590792Sgshapiro 15690792Sgshapiro if (fp->f_cookie == NULL) 15790792Sgshapiro setup(fp); 15890792Sgshapiro s = fp->f_cookie; 15990792Sgshapiro return fread(buf, 1, n, s); 16090792Sgshapiro} 16190792Sgshapiro 16290792Sgshapiro/* 16390792Sgshapiro** SM_STDIOWRITE -- write to the file 16490792Sgshapiro** 16590792Sgshapiro** Parameters: 16690792Sgshapiro** fp -- the file pointer 16790792Sgshapiro** buf -- location of data to write 16890792Sgshapiro** n - number of bytes to write 16990792Sgshapiro** 17090792Sgshapiro** Returns: 17190792Sgshapiro** result from fwrite(). 17290792Sgshapiro*/ 17390792Sgshapiro 17490792Sgshapirossize_t 17590792Sgshapirosm_stdiowrite(fp, buf, n) 17690792Sgshapiro SM_FILE_T *fp; 17790792Sgshapiro char const *buf; 17890792Sgshapiro size_t n; 17990792Sgshapiro{ 18090792Sgshapiro register FILE *s; 18190792Sgshapiro 18290792Sgshapiro if (fp->f_cookie == NULL) 18390792Sgshapiro setup(fp); 18490792Sgshapiro s = fp->f_cookie; 18590792Sgshapiro return fwrite(buf, 1, n, s); 18690792Sgshapiro} 18790792Sgshapiro 18890792Sgshapiro/* 18990792Sgshapiro** SM_STDIOSEEK -- set position within file 19090792Sgshapiro** 19190792Sgshapiro** Parameters: 19290792Sgshapiro** fp -- the file pointer 19390792Sgshapiro** offset -- new location based on 'whence' 19490792Sgshapiro** whence -- indicates "base" for 'offset' 19590792Sgshapiro** 19690792Sgshapiro** Returns: 19790792Sgshapiro** result from fseek(). 19890792Sgshapiro*/ 19990792Sgshapiro 20090792Sgshapirooff_t 20190792Sgshapirosm_stdioseek(fp, offset, whence) 20290792Sgshapiro SM_FILE_T *fp; 20390792Sgshapiro off_t offset; 20490792Sgshapiro int whence; 20590792Sgshapiro{ 20690792Sgshapiro register FILE *s; 20790792Sgshapiro 20890792Sgshapiro if (fp->f_cookie == NULL) 20990792Sgshapiro setup(fp); 21090792Sgshapiro s = fp->f_cookie; 21190792Sgshapiro return fseek(s, offset, whence); 21290792Sgshapiro} 21390792Sgshapiro 21490792Sgshapiro/* 21590792Sgshapiro** SM_STDIOCLOSE -- close the file 21690792Sgshapiro** 21790792Sgshapiro** Parameters: 21890792Sgshapiro** fp -- close file pointer 21990792Sgshapiro** 22090792Sgshapiro** Return: 22190792Sgshapiro** status from fclose() 22290792Sgshapiro*/ 22390792Sgshapiro 22490792Sgshapiroint 22590792Sgshapirosm_stdioclose(fp) 22690792Sgshapiro SM_FILE_T *fp; 22790792Sgshapiro{ 22890792Sgshapiro register FILE *s; 22990792Sgshapiro 23090792Sgshapiro if (fp->f_cookie == NULL) 23190792Sgshapiro setup(fp); 23290792Sgshapiro s = fp->f_cookie; 23390792Sgshapiro return fclose(s); 23490792Sgshapiro} 23590792Sgshapiro 23690792Sgshapiro/* 23790792Sgshapiro** SM_STDIOSETINFO -- set info for this open file 23890792Sgshapiro** 23990792Sgshapiro** Parameters: 24090792Sgshapiro** fp -- the file pointer 24190792Sgshapiro** what -- type of information setting 24290792Sgshapiro** valp -- memory location of info to set 24390792Sgshapiro** 24490792Sgshapiro** Return: 24590792Sgshapiro** Failure: -1 and sets errno 24690792Sgshapiro** Success: none (currently). 24790792Sgshapiro*/ 24890792Sgshapiro 24990792Sgshapiro/* ARGSUSED2 */ 25090792Sgshapiroint 25190792Sgshapirosm_stdiosetinfo(fp, what, valp) 25290792Sgshapiro SM_FILE_T *fp; 25390792Sgshapiro int what; 25490792Sgshapiro void *valp; 25590792Sgshapiro{ 25690792Sgshapiro switch (what) 25790792Sgshapiro { 25890792Sgshapiro case SM_IO_WHAT_MODE: 25990792Sgshapiro default: 26090792Sgshapiro errno = EINVAL; 26190792Sgshapiro return -1; 26290792Sgshapiro } 26390792Sgshapiro} 26490792Sgshapiro 26590792Sgshapiro/* 26690792Sgshapiro** SM_STDIOGETINFO -- get info for this open file 26790792Sgshapiro** 26890792Sgshapiro** Parameters: 26990792Sgshapiro** fp -- the file pointer 27090792Sgshapiro** what -- type of information request 27190792Sgshapiro** valp -- memory location to place info 27290792Sgshapiro** 27390792Sgshapiro** Return: 27490792Sgshapiro** Failure: -1 and sets errno 27590792Sgshapiro** Success: none (currently). 27690792Sgshapiro*/ 27790792Sgshapiro 27890792Sgshapiro/* ARGSUSED2 */ 27990792Sgshapiroint 28090792Sgshapirosm_stdiogetinfo(fp, what, valp) 28190792Sgshapiro SM_FILE_T *fp; 28290792Sgshapiro int what; 28390792Sgshapiro void *valp; 28490792Sgshapiro{ 28590792Sgshapiro switch (what) 28690792Sgshapiro { 28794334Sgshapiro case SM_IO_WHAT_SIZE: 28894334Sgshapiro { 28994334Sgshapiro int fd; 29094334Sgshapiro struct stat st; 29194334Sgshapiro 29294334Sgshapiro if (fp->f_cookie == NULL) 29394334Sgshapiro setup(fp); 29494334Sgshapiro fd = fileno((FILE *) fp->f_cookie); 29594334Sgshapiro if (fd < 0) 29694334Sgshapiro return -1; 29794334Sgshapiro if (fstat(fd, &st) == 0) 29894334Sgshapiro return st.st_size; 29994334Sgshapiro else 30094334Sgshapiro return -1; 30194334Sgshapiro } 30294334Sgshapiro 30390792Sgshapiro case SM_IO_WHAT_MODE: 30490792Sgshapiro default: 30590792Sgshapiro errno = EINVAL; 30690792Sgshapiro return -1; 30790792Sgshapiro } 30890792Sgshapiro} 30990792Sgshapiro 31090792Sgshapiro/* 31190792Sgshapiro** SM_IO_STDIOOPEN -- create an SM_FILE which interfaces to a stdio FILE 31290792Sgshapiro** 31390792Sgshapiro** Parameters: 31490792Sgshapiro** stream -- an open stdio stream, as returned by fopen() 31590792Sgshapiro** mode -- the mode argument to fopen() which describes stream 31690792Sgshapiro** 31790792Sgshapiro** Return: 31890792Sgshapiro** On success, return a pointer to an SM_FILE object which 31990792Sgshapiro** can be used for reading and writing 'stream'. 32090792Sgshapiro** Abort if mode is gibberish or stream is bad. 32190792Sgshapiro** Raise an exception if we can't allocate memory. 32290792Sgshapiro*/ 32390792Sgshapiro 32490792SgshapiroSM_FILE_T * 32590792Sgshapirosm_io_stdioopen(stream, mode) 32690792Sgshapiro FILE *stream; 32790792Sgshapiro char *mode; 32890792Sgshapiro{ 32990792Sgshapiro int fd; 33090792Sgshapiro bool r, w; 33190792Sgshapiro int ioflags; 33290792Sgshapiro SM_FILE_T *fp; 33390792Sgshapiro 33490792Sgshapiro fd = fileno(stream); 33590792Sgshapiro SM_REQUIRE(fd >= 0); 33690792Sgshapiro 33790792Sgshapiro r = w = false; 33890792Sgshapiro switch (mode[0]) 33990792Sgshapiro { 34090792Sgshapiro case 'r': 34190792Sgshapiro r = true; 34290792Sgshapiro break; 34390792Sgshapiro case 'w': 34490792Sgshapiro case 'a': 34590792Sgshapiro w = true; 34690792Sgshapiro break; 34790792Sgshapiro default: 34890792Sgshapiro sm_abort("sm_io_stdioopen: mode '%s' is bad", mode); 34990792Sgshapiro } 35090792Sgshapiro if (strchr(&mode[1], '+') != NULL) 35190792Sgshapiro r = w = true; 35290792Sgshapiro if (r && w) 35390792Sgshapiro ioflags = SMRW; 35490792Sgshapiro else if (r) 35590792Sgshapiro ioflags = SMRD; 35690792Sgshapiro else 35790792Sgshapiro ioflags = SMWR; 35890792Sgshapiro 35990792Sgshapiro fp = sm_fp(SmFtRealStdio, ioflags, NULL); 36090792Sgshapiro fp->f_file = fd; 36190792Sgshapiro fp->f_cookie = stream; 36290792Sgshapiro return fp; 36390792Sgshapiro} 364