1 /* 2 * Copyright (c) 2000-2005 Proofpoint, Inc. and its suppliers. 3 * All rights reserved. 4 * Copyright (c) 1990, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley by 8 * Chris Torek. 9 * 10 * By using this file, you agree to the terms and conditions set 11 * forth in the LICENSE file which can be found at the top level of 12 * the sendmail distribution. 13 */ 14 15 #include <sm/gen.h> 16 SM_RCSID("@(#)$Id: stdio.c,v 1.72 2013-11-22 20:51:43 ca Exp $") 17 #include <unistd.h> 18 #include <errno.h> 19 #include <fcntl.h> 20 #include <string.h> /* FreeBSD: FD_ZERO needs <string.h> */ 21 #include <sys/stat.h> 22 #include <sm/time.h> 23 #include <sm/heap.h> 24 #include <sm/assert.h> 25 #include <sm/varargs.h> 26 #include <sm/io.h> 27 #include <sm/setjmp.h> 28 #include <sm/conf.h> 29 #include <sm/fdset.h> 30 #include "local.h" 31 32 static int sm_stdsetmode __P((SM_FILE_T *, const int *)); 33 static int sm_stdgetmode __P((SM_FILE_T *, int *)); 34 35 /* 36 ** Overall: 37 ** Small standard I/O/seek/close functions. 38 ** These maintain the `known seek offset' for seek optimization. 39 */ 40 41 /* 42 ** SM_STDOPEN -- open a file with stdio behavior 43 ** 44 ** Not associated with the system's stdio in libc. 45 ** 46 ** Parameters: 47 ** fp -- file pointer to be associated with the open 48 ** info -- pathname of the file to be opened 49 ** flags -- indicates type of access methods 50 ** rpool -- ignored 51 ** 52 ** Returns: 53 ** Failure: -1 and set errno 54 ** Success: 0 or greater (fd of file from open(2)). 55 ** 56 */ 57 58 /* ARGSUSED3 */ 59 int 60 sm_stdopen(fp, info, flags, rpool) 61 SM_FILE_T *fp; 62 const void *info; 63 int flags; 64 const void *rpool; 65 { 66 char *path = (char *) info; 67 int oflags; 68 69 switch (SM_IO_MODE(flags)) 70 { 71 case SM_IO_RDWR: 72 oflags = O_RDWR; 73 break; 74 case SM_IO_RDWRTR: 75 oflags = O_RDWR | O_CREAT | O_TRUNC; 76 break; 77 case SM_IO_RDONLY: 78 oflags = O_RDONLY; 79 break; 80 case SM_IO_WRONLY: 81 oflags = O_WRONLY | O_CREAT | O_TRUNC; 82 break; 83 case SM_IO_APPEND: 84 oflags = O_APPEND | O_WRONLY | O_CREAT; 85 break; 86 case SM_IO_APPENDRW: 87 oflags = O_APPEND | O_RDWR | O_CREAT; 88 break; 89 default: 90 errno = EINVAL; 91 return -1; 92 } 93 #ifdef O_BINARY 94 if (SM_IS_BINARY(flags)) 95 oflags |= O_BINARY; 96 #endif 97 fp->f_file = open(path, oflags, 98 S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH); 99 if (fp->f_file < 0) 100 return -1; /* errno set by open() */ 101 102 if (oflags & O_APPEND) 103 (void) (*fp->f_seek)((void *)fp, (off_t)0, SEEK_END); 104 105 return fp->f_file; 106 } 107 108 /* 109 ** SM_STDREAD -- read from the file 110 ** 111 ** Parameters: 112 ** fp -- file pointer to read from 113 ** buf -- location to place read data 114 ** n -- number of bytes to read 115 ** 116 ** Returns: 117 ** Failure: -1 and sets errno 118 ** Success: number of bytes read 119 ** 120 ** Side Effects: 121 ** Updates internal offset for file. 122 */ 123 124 ssize_t 125 sm_stdread(fp, buf, n) 126 SM_FILE_T *fp; 127 char *buf; 128 size_t n; 129 { 130 register int ret; 131 132 ret = read(fp->f_file, buf, n); 133 134 /* if the read succeeded, update the current offset */ 135 if (ret > 0) 136 fp->f_lseekoff += ret; 137 return ret; 138 } 139 140 /* 141 ** SM_STDWRITE -- write to the file 142 ** 143 ** Parameters: 144 ** fp -- file pointer ro write to 145 ** buf -- location of data to be written 146 ** n - number of bytes to write 147 ** 148 ** Returns: 149 ** Failure: -1 and sets errno 150 ** Success: number of bytes written 151 */ 152 153 ssize_t 154 sm_stdwrite(fp, buf, n) 155 SM_FILE_T *fp; 156 char const *buf; 157 size_t n; 158 { 159 return write(fp->f_file, buf, n); 160 } 161 162 /* 163 ** SM_STDSEEK -- set the file offset position 164 ** 165 ** Parmeters: 166 ** fp -- file pointer to position 167 ** offset -- how far to position from "base" (set by 'whence') 168 ** whence -- indicates where the "base" of the 'offset' to start 169 ** 170 ** Results: 171 ** Failure: -1 and sets errno 172 ** Success: the current offset 173 ** 174 ** Side Effects: 175 ** Updates the internal value of the offset. 176 */ 177 178 off_t 179 sm_stdseek(fp, offset, whence) 180 SM_FILE_T *fp; 181 off_t offset; 182 int whence; 183 { 184 register off_t ret; 185 186 ret = lseek(fp->f_file, (off_t) offset, whence); 187 if (ret != (off_t) -1) 188 fp->f_lseekoff = ret; 189 return ret; 190 } 191 192 /* 193 ** SM_STDCLOSE -- close the file 194 ** 195 ** Parameters: 196 ** fp -- the file pointer to close 197 ** 198 ** Returns: 199 ** Success: 0 (zero) 200 ** Failure: -1 and sets errno 201 */ 202 203 int 204 sm_stdclose(fp) 205 SM_FILE_T *fp; 206 { 207 return close(fp->f_file); 208 } 209 210 /* 211 ** SM_STDSETMODE -- set the access mode for the file 212 ** 213 ** Called by sm_stdsetinfo(). 214 ** 215 ** Parameters: 216 ** fp -- file pointer 217 ** mode -- new mode to set the file access to 218 ** 219 ** Results: 220 ** Success: 0 (zero); 221 ** Failure: -1 and sets errno 222 */ 223 224 static int 225 sm_stdsetmode(fp, mode) 226 SM_FILE_T *fp; 227 const int *mode; 228 { 229 int flags = 0; 230 231 switch (SM_IO_MODE(*mode)) 232 { 233 case SM_IO_RDWR: 234 flags |= SMRW; 235 break; 236 case SM_IO_RDONLY: 237 flags |= SMRD; 238 break; 239 case SM_IO_WRONLY: 240 flags |= SMWR; 241 break; 242 case SM_IO_APPEND: 243 default: 244 errno = EINVAL; 245 return -1; 246 } 247 fp->f_flags = fp->f_flags & ~SMMODEMASK; 248 fp->f_flags |= flags; 249 return 0; 250 } 251 252 /* 253 ** SM_STDGETMODE -- for getinfo determine open mode 254 ** 255 ** Called by sm_stdgetinfo(). 256 ** 257 ** Parameters: 258 ** fp -- the file mode being determined 259 ** mode -- internal mode to map to external value 260 ** 261 ** Results: 262 ** Failure: -1 and sets errno 263 ** Success: external mode value 264 */ 265 266 static int 267 sm_stdgetmode(fp, mode) 268 SM_FILE_T *fp; 269 int *mode; 270 { 271 switch (fp->f_flags & SMMODEMASK) 272 { 273 case SMRW: 274 *mode = SM_IO_RDWR; 275 break; 276 case SMRD: 277 *mode = SM_IO_RDONLY; 278 break; 279 case SMWR: 280 *mode = SM_IO_WRONLY; 281 break; 282 default: 283 errno = EINVAL; 284 return -1; 285 } 286 return 0; 287 } 288 289 /* 290 ** SM_STDSETINFO -- set/modify information for a file 291 ** 292 ** Parameters: 293 ** fp -- file to set info for 294 ** what -- type of info to set 295 ** valp -- location of data used for setting 296 ** 297 ** Returns: 298 ** Failure: -1 and sets errno 299 ** Success: >=0 300 */ 301 302 int 303 sm_stdsetinfo(fp, what, valp) 304 SM_FILE_T *fp; 305 int what; 306 void *valp; 307 { 308 switch (what) 309 { 310 case SM_IO_WHAT_MODE: 311 return sm_stdsetmode(fp, (const int *)valp); 312 313 default: 314 errno = EINVAL; 315 return -1; 316 } 317 } 318 319 /* 320 ** SM_STDGETINFO -- get information about the open file 321 ** 322 ** Parameters: 323 ** fp -- file to get info for 324 ** what -- type of info to get 325 ** valp -- location to place found info 326 ** 327 ** Returns: 328 ** Success: may or may not place info in 'valp' depending 329 ** on 'what' value, and returns values >=0. Return 330 ** value may be the obtained info 331 ** Failure: -1 and sets errno 332 */ 333 334 int 335 sm_stdgetinfo(fp, what, valp) 336 SM_FILE_T *fp; 337 int what; 338 void *valp; 339 { 340 switch (what) 341 { 342 case SM_IO_WHAT_MODE: 343 return sm_stdgetmode(fp, (int *)valp); 344 345 case SM_IO_WHAT_FD: 346 return fp->f_file; 347 348 case SM_IO_WHAT_SIZE: 349 { 350 struct stat st; 351 352 if (fstat(fp->f_file, &st) == 0) 353 return st.st_size; 354 else 355 return -1; 356 } 357 358 case SM_IO_IS_READABLE: 359 { 360 fd_set readfds; 361 struct timeval timeout; 362 363 if (SM_FD_SETSIZE > 0 && fp->f_file >= SM_FD_SETSIZE) 364 { 365 errno = EINVAL; 366 return -1; 367 } 368 FD_ZERO(&readfds); 369 SM_FD_SET(fp->f_file, &readfds); 370 timeout.tv_sec = 0; 371 timeout.tv_usec = 0; 372 if (select(fp->f_file + 1, FDSET_CAST &readfds, 373 NULL, NULL, &timeout) > 0 && 374 SM_FD_ISSET(fp->f_file, &readfds)) 375 return 1; 376 return 0; 377 } 378 379 default: 380 errno = EINVAL; 381 return -1; 382 } 383 } 384 385 /* 386 ** SM_STDFDOPEN -- open file by primitive 'fd' rather than pathname 387 ** 388 ** I/O function to handle fdopen() stdio equivalence. The rest of 389 ** the functions are the same as the sm_stdopen() above. 390 ** 391 ** Parameters: 392 ** fp -- the file pointer to be associated with the open 393 ** name -- the primitive file descriptor for association 394 ** flags -- indicates type of access methods 395 ** rpool -- ignored 396 ** 397 ** Results: 398 ** Success: primitive file descriptor value 399 ** Failure: -1 and sets errno 400 */ 401 402 /* ARGSUSED3 */ 403 int 404 sm_stdfdopen(fp, info, flags, rpool) 405 SM_FILE_T *fp; 406 const void *info; 407 int flags; 408 const void *rpool; 409 { 410 int oflags, tmp, fdflags, fd = *((int *) info); 411 412 switch (SM_IO_MODE(flags)) 413 { 414 case SM_IO_RDWR: 415 oflags = O_RDWR | O_CREAT; 416 break; 417 case SM_IO_RDONLY: 418 oflags = O_RDONLY; 419 break; 420 case SM_IO_WRONLY: 421 oflags = O_WRONLY | O_CREAT | O_TRUNC; 422 break; 423 case SM_IO_APPEND: 424 oflags = O_APPEND | O_WRONLY | O_CREAT; 425 break; 426 case SM_IO_APPENDRW: 427 oflags = O_APPEND | O_RDWR | O_CREAT; 428 break; 429 default: 430 errno = EINVAL; 431 return -1; 432 } 433 #ifdef O_BINARY 434 if (SM_IS_BINARY(flags)) 435 oflags |= O_BINARY; 436 #endif 437 438 /* Make sure the mode the user wants is a subset of the actual mode. */ 439 if ((fdflags = fcntl(fd, F_GETFL, 0)) < 0) 440 return -1; 441 tmp = fdflags & O_ACCMODE; 442 if (tmp != O_RDWR && (tmp != (oflags & O_ACCMODE))) 443 { 444 errno = EINVAL; 445 return -1; 446 } 447 fp->f_file = fd; 448 if (oflags & O_APPEND) 449 (void) (*fp->f_seek)(fp, (off_t)0, SEEK_END); 450 return fp->f_file; 451 } 452 453 /* 454 ** SM_IO_FOPEN -- open a file 455 ** 456 ** Same interface and semantics as the open() system call, 457 ** except that it returns SM_FILE_T* instead of a file descriptor. 458 ** 459 ** Parameters: 460 ** pathname -- path of file to open 461 ** flags -- flags controlling the open 462 ** ... -- option "mode" for opening the file 463 ** 464 ** Returns: 465 ** Raises an exception on heap exhaustion. 466 ** Returns NULL and sets errno if open() fails. 467 ** Returns an SM_FILE_T pointer on success. 468 */ 469 470 SM_FILE_T * 471 #if SM_VA_STD 472 sm_io_fopen(char *pathname, int flags, ...) 473 #else /* SM_VA_STD */ 474 sm_io_fopen(pathname, flags, va_alist) 475 char *pathname; 476 int flags; 477 va_dcl 478 #endif /* SM_VA_STD */ 479 { 480 MODE_T mode; 481 SM_FILE_T *fp; 482 int ioflags; 483 484 if (flags & O_CREAT) 485 { 486 SM_VA_LOCAL_DECL 487 488 SM_VA_START(ap, flags); 489 mode = (MODE_T) SM_VA_ARG(ap, int); 490 SM_VA_END(ap); 491 } 492 else 493 mode = 0; 494 495 switch (flags & O_ACCMODE) 496 { 497 case O_RDONLY: 498 ioflags = SMRD; 499 break; 500 case O_WRONLY: 501 ioflags = SMWR; 502 break; 503 case O_RDWR: 504 ioflags = SMRW; 505 break; 506 default: 507 sm_abort("sm_io_fopen: bad flags 0%o", flags); 508 } 509 510 fp = sm_fp(SmFtStdio, ioflags, NULL); 511 fp->f_file = open(pathname, flags, mode); 512 if (fp->f_file == -1) 513 { 514 fp->f_flags = 0; 515 fp->sm_magic = NULL; 516 return NULL; 517 } 518 return fp; 519 } 520