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> 11 SM_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 22 static 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 */ 49 int 50 sm_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 112 static void 113 setup(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 148 ssize_t 149 sm_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 174 ssize_t 175 sm_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 200 off_t 201 sm_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 224 int 225 sm_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 */ 250 int 251 sm_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 */ 279 int 280 sm_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 324 SM_FILE_T * 325 sm_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