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.10 2003/01/10 23:07:17 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 (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 117 ssize_t 118 sm_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 146 ssize_t 147 sm_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 171 off_t 172 sm_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 196 int 197 sm_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 217 int 218 sm_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 259 int 260 sm_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 295 int 296 sm_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 327 int 328 sm_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 if (SM_FD_SETSIZE > 0 && fp->f_file >= SM_FD_SETSIZE) 357 { 358 errno = EINVAL; 359 return -1; 360 } 361 FD_ZERO(&readfds); 362 SM_FD_SET(fp->f_file, &readfds); 363 timeout.tv_sec = 0; 364 timeout.tv_usec = 0; 365 if (select(fp->f_file + 1, FDSET_CAST &readfds, 366 NULL, NULL, &timeout) > 0 && 367 SM_FD_ISSET(fp->f_file, &readfds)) 368 return 1; 369 return 0; 370 } 371 372 default: 373 errno = EINVAL; 374 return -1; 375 } 376 } 377 378 /* 379 ** SM_STDFDOPEN -- open file by primitive 'fd' rather than pathname 380 ** 381 ** I/O function to handle fdopen() stdio equivalence. The rest of 382 ** the functions are the same as the sm_stdopen() above. 383 ** 384 ** Parameters: 385 ** fp -- the file pointer to be associated with the open 386 ** name -- the primitive file descriptor for association 387 ** flags -- indicates type of access methods 388 ** rpool -- ignored 389 ** 390 ** Results: 391 ** Success: primitive file descriptor value 392 ** Failure: -1 and sets errno 393 */ 394 395 /* ARGSUSED3 */ 396 int 397 sm_stdfdopen(fp, info, flags, rpool) 398 SM_FILE_T *fp; 399 const void *info; 400 int flags; 401 const void *rpool; 402 { 403 int oflags, tmp, fdflags, fd = *((int *) info); 404 405 switch (flags) 406 { 407 case SM_IO_RDWR: 408 oflags = O_RDWR | O_CREAT; 409 break; 410 case SM_IO_RDONLY: 411 oflags = O_RDONLY; 412 break; 413 case SM_IO_WRONLY: 414 oflags = O_WRONLY | O_CREAT | O_TRUNC; 415 break; 416 case SM_IO_APPEND: 417 oflags = O_APPEND | O_WRONLY | O_CREAT; 418 break; 419 case SM_IO_APPENDRW: 420 oflags = O_APPEND | O_RDWR | O_CREAT; 421 break; 422 default: 423 errno = EINVAL; 424 return -1; 425 } 426 427 /* Make sure the mode the user wants is a subset of the actual mode. */ 428 if ((fdflags = fcntl(fd, F_GETFL, 0)) < 0) 429 return -1; 430 tmp = fdflags & O_ACCMODE; 431 if (tmp != O_RDWR && (tmp != (oflags & O_ACCMODE))) 432 { 433 errno = EINVAL; 434 return -1; 435 } 436 fp->f_file = fd; 437 if (oflags & O_APPEND) 438 (void) (*fp->f_seek)(fp, (off_t)0, SEEK_END); 439 return fp->f_file; 440 } 441 442 /* 443 ** SM_IO_FOPEN -- open a file 444 ** 445 ** Same interface and semantics as the open() system call, 446 ** except that it returns SM_FILE_T* instead of a file descriptor. 447 ** 448 ** Parameters: 449 ** pathname -- path of file to open 450 ** flags -- flags controlling the open 451 ** ... -- option "mode" for opening the file 452 ** 453 ** Returns: 454 ** Raises an exception on heap exhaustion. 455 ** Returns NULL and sets errno if open() fails. 456 ** Returns an SM_FILE_T pointer on success. 457 */ 458 459 SM_FILE_T * 460 #if SM_VA_STD 461 sm_io_fopen(char *pathname, int flags, ...) 462 #else /* SM_VA_STD */ 463 sm_io_fopen(pathname, flags, va_alist) 464 char *pathname; 465 int flags; 466 va_dcl 467 #endif /* SM_VA_STD */ 468 { 469 MODE_T mode; 470 SM_FILE_T *fp; 471 int ioflags; 472 473 if (flags & O_CREAT) 474 { 475 SM_VA_LOCAL_DECL 476 477 SM_VA_START(ap, flags); 478 mode = (MODE_T) SM_VA_ARG(ap, int); 479 SM_VA_END(ap); 480 } 481 else 482 mode = 0; 483 484 switch (flags & O_ACCMODE) 485 { 486 case O_RDONLY: 487 ioflags = SMRD; 488 break; 489 case O_WRONLY: 490 ioflags = SMWR; 491 break; 492 case O_RDWR: 493 ioflags = SMRW; 494 break; 495 default: 496 sm_abort("sm_io_fopen: bad flags 0%o", flags); 497 } 498 499 fp = sm_fp(SmFtStdio, ioflags, NULL); 500 fp->f_file = open(pathname, flags, mode); 501 if (fp->f_file == -1) 502 { 503 fp->f_flags = 0; 504 fp->sm_magic = NULL; 505 return NULL; 506 } 507 return fp; 508 } 509