stdio.c revision 285303
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> 16SM_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 32static int sm_stdsetmode __P((SM_FILE_T *, const int *)); 33static 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 */ 59int 60sm_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 /* O_BINARY */ 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 into file. 122*/ 123 124ssize_t 125sm_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 153ssize_t 154sm_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 178off_t 179sm_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 203int 204sm_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 224static int 225sm_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 266static int 267sm_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 302int 303sm_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 334int 335sm_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 */ 403int 404sm_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 /* O_BINARY */ 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 470SM_FILE_T * 471#if SM_VA_STD 472sm_io_fopen(char *pathname, int flags, ...) 473#else /* SM_VA_STD */ 474sm_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