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> 16 SM_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 */ 56 int 57 sm_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 121 ssize_t 122 sm_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 150 ssize_t 151 sm_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 175 off_t 176 sm_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 200 int 201 sm_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 221 int 222 sm_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 263 int 264 sm_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 299 int 300 sm_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 331 int 332 sm_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 */ 400 int 401 sm_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 467 SM_FILE_T * 468 #if SM_VA_STD 469 sm_io_fopen(char *pathname, int flags, ...) 470 #else /* SM_VA_STD */ 471 sm_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