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