smstdio.c revision 98121
1/* 2 * Copyright (c) 2000-2002 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.32 2002/02/23 20:18:36 gshapiro 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 case SM_IO_RDWR: 72 default: 73 stdiomode = "r+"; 74 break; 75 } 76 77 if ((s = fopen((char *)info, stdiomode)) == NULL) 78 return -1; 79 fp->f_cookie = s; 80 return 0; 81} 82 83/* 84** SETUP -- assign file type cookie when not already assigned 85** 86** Parameters: 87** fp - the file pointer to get the cookie assigned 88** 89** Return: 90** none. 91*/ 92 93static void 94setup(fp) 95 SM_FILE_T *fp; 96{ 97 if (fp->f_cookie == NULL) 98 { 99 switch (fp->f_ival) 100 { 101 case 0: 102 fp->f_cookie = stdin; 103 break; 104 case 1: 105 fp->f_cookie = stdout; 106 break; 107 case 2: 108 fp->f_cookie = stderr; 109 break; 110 default: 111 sm_abort("fp->f_ival=%d: out of range (0...2)", fp->f_ival); 112 break; 113 } 114 } 115} 116 117/* 118** SM_STDIOREAD -- read from the file 119** 120** Parameters: 121** fp -- the file pointer 122** buf -- location to place the read data 123** n - number of bytes to read 124** 125** Returns: 126** result from fread(). 127*/ 128 129ssize_t 130sm_stdioread(fp, buf, n) 131 SM_FILE_T *fp; 132 char *buf; 133 size_t n; 134{ 135 register FILE *s; 136 137 if (fp->f_cookie == NULL) 138 setup(fp); 139 s = fp->f_cookie; 140 return fread(buf, 1, n, s); 141} 142 143/* 144** SM_STDIOWRITE -- write to the file 145** 146** Parameters: 147** fp -- the file pointer 148** buf -- location of data to write 149** n - number of bytes to write 150** 151** Returns: 152** result from fwrite(). 153*/ 154 155ssize_t 156sm_stdiowrite(fp, buf, n) 157 SM_FILE_T *fp; 158 char const *buf; 159 size_t n; 160{ 161 register FILE *s; 162 163 if (fp->f_cookie == NULL) 164 setup(fp); 165 s = fp->f_cookie; 166 return fwrite(buf, 1, n, s); 167} 168 169/* 170** SM_STDIOSEEK -- set position within file 171** 172** Parameters: 173** fp -- the file pointer 174** offset -- new location based on 'whence' 175** whence -- indicates "base" for 'offset' 176** 177** Returns: 178** result from fseek(). 179*/ 180 181off_t 182sm_stdioseek(fp, offset, whence) 183 SM_FILE_T *fp; 184 off_t offset; 185 int whence; 186{ 187 register FILE *s; 188 189 if (fp->f_cookie == NULL) 190 setup(fp); 191 s = fp->f_cookie; 192 return fseek(s, offset, whence); 193} 194 195/* 196** SM_STDIOCLOSE -- close the file 197** 198** Parameters: 199** fp -- close file pointer 200** 201** Return: 202** status from fclose() 203*/ 204 205int 206sm_stdioclose(fp) 207 SM_FILE_T *fp; 208{ 209 register FILE *s; 210 211 if (fp->f_cookie == NULL) 212 setup(fp); 213 s = fp->f_cookie; 214 return fclose(s); 215} 216 217/* 218** SM_STDIOSETINFO -- set info for this open file 219** 220** Parameters: 221** fp -- the file pointer 222** what -- type of information setting 223** valp -- memory location of info to set 224** 225** Return: 226** Failure: -1 and sets errno 227** Success: none (currently). 228*/ 229 230/* ARGSUSED2 */ 231int 232sm_stdiosetinfo(fp, what, valp) 233 SM_FILE_T *fp; 234 int what; 235 void *valp; 236{ 237 switch (what) 238 { 239 case SM_IO_WHAT_MODE: 240 default: 241 errno = EINVAL; 242 return -1; 243 } 244} 245 246/* 247** SM_STDIOGETINFO -- get info for this open file 248** 249** Parameters: 250** fp -- the file pointer 251** what -- type of information request 252** valp -- memory location to place info 253** 254** Return: 255** Failure: -1 and sets errno 256** Success: none (currently). 257*/ 258 259/* ARGSUSED2 */ 260int 261sm_stdiogetinfo(fp, what, valp) 262 SM_FILE_T *fp; 263 int what; 264 void *valp; 265{ 266 switch (what) 267 { 268 case SM_IO_WHAT_SIZE: 269 { 270 int fd; 271 struct stat st; 272 273 if (fp->f_cookie == NULL) 274 setup(fp); 275 fd = fileno((FILE *) fp->f_cookie); 276 if (fd < 0) 277 return -1; 278 if (fstat(fd, &st) == 0) 279 return st.st_size; 280 else 281 return -1; 282 } 283 284 case SM_IO_WHAT_MODE: 285 default: 286 errno = EINVAL; 287 return -1; 288 } 289} 290 291/* 292** SM_IO_STDIOOPEN -- create an SM_FILE which interfaces to a stdio FILE 293** 294** Parameters: 295** stream -- an open stdio stream, as returned by fopen() 296** mode -- the mode argument to fopen() which describes stream 297** 298** Return: 299** On success, return a pointer to an SM_FILE object which 300** can be used for reading and writing 'stream'. 301** Abort if mode is gibberish or stream is bad. 302** Raise an exception if we can't allocate memory. 303*/ 304 305SM_FILE_T * 306sm_io_stdioopen(stream, mode) 307 FILE *stream; 308 char *mode; 309{ 310 int fd; 311 bool r, w; 312 int ioflags; 313 SM_FILE_T *fp; 314 315 fd = fileno(stream); 316 SM_REQUIRE(fd >= 0); 317 318 r = w = false; 319 switch (mode[0]) 320 { 321 case 'r': 322 r = true; 323 break; 324 case 'w': 325 case 'a': 326 w = true; 327 break; 328 default: 329 sm_abort("sm_io_stdioopen: mode '%s' is bad", mode); 330 } 331 if (strchr(&mode[1], '+') != NULL) 332 r = w = true; 333 if (r && w) 334 ioflags = SMRW; 335 else if (r) 336 ioflags = SMRD; 337 else 338 ioflags = SMWR; 339 340 fp = sm_fp(SmFtRealStdio, ioflags, NULL); 341 fp->f_file = fd; 342 fp->f_cookie = stream; 343 return fp; 344} 345