1/* 2 * Copyright (c) 2000-2002, 2004 Proofpoint, Inc. and its suppliers. 3 * All rights reserved. 4 * 5 * By using this file, you agree to the terms and conditions set 6 * forth in the LICENSE file which can be found at the top level of 7 * the sendmail distribution. 8 */ 9 10#include <sm/gen.h> 11SM_IDSTR(id, "@(#)$Id: smstdio.c,v 1.35 2013-11-22 20:51:43 ca Exp $") 12#include <unistd.h> 13#include <stdio.h> 14#include <fcntl.h> 15#include <errno.h> 16#include <sys/stat.h> 17#include <sm/assert.h> 18#include <sm/io.h> 19#include <sm/string.h> 20#include "local.h" 21 22static void setup __P((SM_FILE_T *)); 23 24/* 25** Overall: 26** This is a file type which implements a layer on top of the system 27** stdio. fp->f_cookie is the FILE* of stdio. The cookie may be 28** "bound late" because of the manner which Linux implements stdio. 29** When binding late (when fp->f_cookie==NULL) then the value of 30** fp->f_ival is used (0, 1 or 2) to map to stdio's stdin, stdout or 31** stderr. 32*/ 33 34/* 35** SM_STDIOOPEN -- open a file to system stdio implementation 36** 37** Parameters: 38** fp -- file pointer assign for this open 39** info -- info about file to open 40** flags -- indicating method of opening 41** rpool -- ignored 42** 43** Returns: 44** Failure: -1 45** Success: 0 (zero) 46*/ 47 48/* ARGSUSED3 */ 49int 50sm_stdioopen(fp, info, flags, rpool) 51 SM_FILE_T *fp; 52 const void *info; 53 int flags; 54 const void *rpool; 55{ 56 register FILE *s; 57 char *stdiomode; 58 59 switch (flags) 60 { 61 case SM_IO_RDONLY: 62 stdiomode = "r"; 63 break; 64 case SM_IO_WRONLY: 65 stdiomode = "w"; 66 break; 67 case SM_IO_APPEND: 68 stdiomode = "a"; 69 break; 70 case SM_IO_APPENDRW: 71 stdiomode = "a+"; 72 break; 73#if SM_IO_BINARY != 0 74 case SM_IO_RDONLY_B: 75 stdiomode = "rb"; 76 break; 77 case SM_IO_WRONLY_B: 78 stdiomode = "wb"; 79 break; 80 case SM_IO_APPEND_B: 81 stdiomode = "ab"; 82 break; 83 case SM_IO_APPENDRW_B: 84 stdiomode = "a+b"; 85 break; 86 case SM_IO_RDWR_B: 87 stdiomode = "r+b"; 88 break; 89#endif /* SM_IO_BINARY != 0 */ 90 case SM_IO_RDWR: 91 default: 92 stdiomode = "r+"; 93 break; 94 } 95 96 if ((s = fopen((char *)info, stdiomode)) == NULL) 97 return -1; 98 fp->f_cookie = s; 99 return 0; 100} 101 102/* 103** SETUP -- assign file type cookie when not already assigned 104** 105** Parameters: 106** fp - the file pointer to get the cookie assigned 107** 108** Return: 109** none. 110*/ 111 112static void 113setup(fp) 114 SM_FILE_T *fp; 115{ 116 if (fp->f_cookie == NULL) 117 { 118 switch (fp->f_ival) 119 { 120 case 0: 121 fp->f_cookie = stdin; 122 break; 123 case 1: 124 fp->f_cookie = stdout; 125 break; 126 case 2: 127 fp->f_cookie = stderr; 128 break; 129 default: 130 sm_abort("fp->f_ival=%d: out of range (0...2)", fp->f_ival); 131 break; 132 } 133 } 134} 135 136/* 137** SM_STDIOREAD -- read from the file 138** 139** Parameters: 140** fp -- the file pointer 141** buf -- location to place the read data 142** n - number of bytes to read 143** 144** Returns: 145** result from fread(). 146*/ 147 148ssize_t 149sm_stdioread(fp, buf, n) 150 SM_FILE_T *fp; 151 char *buf; 152 size_t n; 153{ 154 register FILE *s; 155 156 if (fp->f_cookie == NULL) 157 setup(fp); 158 s = fp->f_cookie; 159 return fread(buf, 1, n, s); 160} 161 162/* 163** SM_STDIOWRITE -- write to the file 164** 165** Parameters: 166** fp -- the file pointer 167** buf -- location of data to write 168** n - number of bytes to write 169** 170** Returns: 171** result from fwrite(). 172*/ 173 174ssize_t 175sm_stdiowrite(fp, buf, n) 176 SM_FILE_T *fp; 177 char const *buf; 178 size_t n; 179{ 180 register FILE *s; 181 182 if (fp->f_cookie == NULL) 183 setup(fp); 184 s = fp->f_cookie; 185 return fwrite(buf, 1, n, s); 186} 187 188/* 189** SM_STDIOSEEK -- set position within file 190** 191** Parameters: 192** fp -- the file pointer 193** offset -- new location based on 'whence' 194** whence -- indicates "base" for 'offset' 195** 196** Returns: 197** result from fseek(). 198*/ 199 200off_t 201sm_stdioseek(fp, offset, whence) 202 SM_FILE_T *fp; 203 off_t offset; 204 int whence; 205{ 206 register FILE *s; 207 208 if (fp->f_cookie == NULL) 209 setup(fp); 210 s = fp->f_cookie; 211 return fseek(s, offset, whence); 212} 213 214/* 215** SM_STDIOCLOSE -- close the file 216** 217** Parameters: 218** fp -- close file pointer 219** 220** Return: 221** status from fclose() 222*/ 223 224int 225sm_stdioclose(fp) 226 SM_FILE_T *fp; 227{ 228 register FILE *s; 229 230 if (fp->f_cookie == NULL) 231 setup(fp); 232 s = fp->f_cookie; 233 return fclose(s); 234} 235 236/* 237** SM_STDIOSETINFO -- set info for this open file 238** 239** Parameters: 240** fp -- the file pointer 241** what -- type of information setting 242** valp -- memory location of info to set 243** 244** Return: 245** Failure: -1 and sets errno 246** Success: none (currently). 247*/ 248 249/* ARGSUSED2 */ 250int 251sm_stdiosetinfo(fp, what, valp) 252 SM_FILE_T *fp; 253 int what; 254 void *valp; 255{ 256 switch (what) 257 { 258 case SM_IO_WHAT_MODE: 259 default: 260 errno = EINVAL; 261 return -1; 262 } 263} 264 265/* 266** SM_STDIOGETINFO -- get info for this open file 267** 268** Parameters: 269** fp -- the file pointer 270** what -- type of information request 271** valp -- memory location to place info 272** 273** Return: 274** Failure: -1 and sets errno 275** Success: none (currently). 276*/ 277 278/* ARGSUSED2 */ 279int 280sm_stdiogetinfo(fp, what, valp) 281 SM_FILE_T *fp; 282 int what; 283 void *valp; 284{ 285 switch (what) 286 { 287 case SM_IO_WHAT_SIZE: 288 { 289 int fd; 290 struct stat st; 291 292 if (fp->f_cookie == NULL) 293 setup(fp); 294 fd = fileno((FILE *) fp->f_cookie); 295 if (fd < 0) 296 return -1; 297 if (fstat(fd, &st) == 0) 298 return st.st_size; 299 else 300 return -1; 301 } 302 303 case SM_IO_WHAT_MODE: 304 default: 305 errno = EINVAL; 306 return -1; 307 } 308} 309 310/* 311** SM_IO_STDIOOPEN -- create an SM_FILE which interfaces to a stdio FILE 312** 313** Parameters: 314** stream -- an open stdio stream, as returned by fopen() 315** mode -- the mode argument to fopen() which describes stream 316** 317** Return: 318** On success, return a pointer to an SM_FILE object which 319** can be used for reading and writing 'stream'. 320** Abort if mode is gibberish or stream is bad. 321** Raise an exception if we can't allocate memory. 322*/ 323 324SM_FILE_T * 325sm_io_stdioopen(stream, mode) 326 FILE *stream; 327 char *mode; 328{ 329 int fd; 330 bool r, w; 331 int ioflags; 332 SM_FILE_T *fp; 333 334 fd = fileno(stream); 335 SM_REQUIRE(fd >= 0); 336 337 r = w = false; 338 switch (mode[0]) 339 { 340 case 'r': 341 r = true; 342 break; 343 case 'w': 344 case 'a': 345 w = true; 346 break; 347 default: 348 sm_abort("sm_io_stdioopen: mode '%s' is bad", mode); 349 } 350 if (strchr(&mode[1], '+') != NULL) 351 r = w = true; 352 if (r && w) 353 ioflags = SMRW; 354 else if (r) 355 ioflags = SMRD; 356 else 357 ioflags = SMWR; 358 359 fp = sm_fp(SmFtRealStdio, ioflags, NULL); 360 fp->f_file = fd; 361 fp->f_cookie = stream; 362 return fp; 363} 364