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> 11 SM_IDSTR(id, "@(#)$Id: smstdio.c,v 1.32.2.2 2003/09/05 20:35:28 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 */ 47 int 48 sm_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 110 static void 111 setup(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 146 ssize_t 147 sm_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 172 ssize_t 173 sm_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 198 off_t 199 sm_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 222 int 223 sm_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 */ 248 int 249 sm_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 */ 277 int 278 sm_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 322 SM_FILE_T * 323 sm_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