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