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