[19203] | 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.1.1.1 2003-04-08 15:08:46 zacheiss 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 | } |
---|