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