/* * Copyright (c) 2002-2005 Sendmail, Inc. and its suppliers. * All rights reserved. * * By using this file, you agree to the terms and conditions set * forth in the LICENSE file which can be found at the top level of * the sendmail distribution. */ #include "sm/generic.h" SM_RCSID("@(#)$Id: stthreadsio.c,v 1.25 2006/07/16 02:07:40 ca Exp $") #include "sm/error.h" #include "fcntl.h" #include "sm/memops.h" #include "sm/stat.h" #include "sm/time.h" #include "sm/heap.h" #include "sm/assert.h" #include "sm/varargs.h" #include "sm/io.h" #include "sm/fdset.h" #include "sm/stthreads.h" #include "io-int.h" #include "statethreads/st.h" static read_F sm_thrread; static write_F sm_thrwrite; #if 0 static sm_ret_T sm_thrssm_ret_T(sm_file_T *fp, off_t offset, int whence); #endif static close_F sm_thrclose; static sm_ret_T sm_thrgetmode(sm_file_T *fp, int *mode); static getinfo_F sm_thrgetinfo; static setinfo_F sm_thrsetinfo; static open_F sm_thrfdopen; static seek_F sm_thrseek; static open_F sm_thrnetopen; #if 0 close_F sm_thrnetclose; #endif sm_stream_T SmStThrIO = SM_STREAM_STRUCT(sm_thrfdopen, sm_thrclose, sm_thrread, sm_thrwrite, \ NULL, NULL, sm_thrseek, sm_thrgetinfo, sm_thrsetinfo); sm_stream_T SmStThrNetIO = SM_STREAM_STRUCT(sm_thrnetopen, sm_thrclose, sm_thrread, sm_thrwrite, \ NULL, NULL, sm_thrseek, sm_thrgetinfo, sm_thrsetinfo); #define f_netfd(fp) ((st_netfd_t) f_cookie(fp)) #define assign_f_netfd(fp, netfd) f_cookie(fp) = (void *) (netfd) /* ** SM_THRREAD -- read from the file ** ** Parameters: ** fp -- file pointer to read from ** buf -- location to place read data ** n -- number of bytes to read ** bytesread -- number of bytes read (output) ** ** Returns: ** usual sm_error code */ static sm_ret_T sm_thrread(sm_file_T *fp, uchar *buf, size_t n, ssize_t *bytesread) { ssize_t ret; do { errno = 0; ret = st_read(f_netfd(*fp), buf, n, SEC2USEC(fp->f_timeout)); } while (ret == -1 && errno == EINTR); if (ret == -1) { int e; e = errno; *bytesread = 0; if (E_IS_TEMP(e)) return sm_error_temp(SM_EM_STTHRIO, e); return sm_error_perm(SM_EM_STTHRIO, e); } *bytesread = ret; return SM_SUCCESS; } /* ** SM_THRWRITE -- write to the file ** ** Parameters: ** fp -- file pointer ro write to ** buf -- location of data to be written ** n -- number of bytes to write ** byteswritten -- number of bytes written (output) ** ** Returns: ** usual sm_error code */ static sm_ret_T sm_thrwrite(sm_file_T *fp, const uchar *buf, size_t n, ssize_t *byteswritten) { ssize_t ret; do { errno = 0; ret = st_write(f_netfd(*fp), buf, n, SEC2USEC(fp->f_timeout)); } while (ret == -1 && errno == EINTR); if (ret == -1) { int e; e = errno; *byteswritten = 0; if (E_IS_TEMP(e)) return sm_error_temp(SM_EM_STTHRIO, e); return sm_error_perm(SM_EM_STTHRIO, e); } *byteswritten = ret; return SM_SUCCESS; } /* ** SM_THRSEEK -- set the file offset position ** ** Parmeters: ** fp -- file pointer to position ** offset -- how far to position from "base" (set by 'whence') ** whence -- indicates where the "base" of the 'offset' to start ** ** Results: ** sm_error_perm(SM_EM_STTHRIO, ESPIPE) */ /* ARGSUSED0 */ static sm_ret_T sm_thrseek(sm_file_T *fp, off_t offset, int whence) { return sm_error_perm(SM_EM_STTHRIO, ESPIPE); } /* ** SM_THRCLOSE -- close the file ** ** Parameters: ** fp -- the file pointer to close ** flags -- ignored ** ** Returns: ** usual sm_error code */ static sm_ret_T sm_thrclose(sm_file_T *fp, int flags) { int r; r = st_netfd_close(f_netfd(*fp)); if (r == -1) return sm_error_perm(SM_EM_STTHRIO, errno); return SM_SUCCESS; } /* ** SM_THRSETMODE -- set the access mode for the file ** Called by sm_stdsetinfo(). ** XXX do we really want to allow changing the mode? ** ** Parameters: ** fp -- file pointer ** mode -- new mode to set the file access to ** ** Results: ** Success: 0 (zero); ** Failure: -1 and sets errno */ static sm_ret_T sm_thrsetmode(sm_file_T *fp, const int *mode) { int flags = 0; switch (*mode) { case SM_IO_RDWR: flags |= SMRW; break; case SM_IO_RDONLY: flags |= SMRD; break; case SM_IO_WRONLY: flags |= SMWR; break; case SM_IO_APPEND: default: return sm_error_perm(SM_EM_STTHRIO, EINVAL); } f_flags(*fp) = f_flags(*fp) & ~SMMODEMASK; f_flags(*fp) |= flags; return SM_SUCCESS; } /* ** SM_THRGETMODE -- for getinfo determine open mode ** ** Called by sm_thrgetinfo(). ** ** Parameters: ** fp -- the file mode being determined ** mode -- internal mode to map to external value ** ** Results: ** Failure: -1 and sets errno ** Success: external mode value */ static sm_ret_T sm_thrgetmode(sm_file_T *fp, int *mode) { switch (f_flags(*fp) & SMMODEMASK) { case SMRW: *mode = SM_IO_RDWR; break; case SMRD: *mode = SM_IO_RDONLY; break; case SMWR: *mode = SM_IO_WRONLY; break; default: return sm_error_perm(SM_EM_STTHRIO, EINVAL); } return SM_SUCCESS; } /* ** SM_THRSETINFO -- set/modify information for a file ** ** Parameters: ** fp -- file to set info for ** what -- type of info to set ** valp -- location of data used for setting ** ** Returns: ** usual sm_error code. */ static sm_ret_T sm_thrsetinfo(sm_file_T *fp, int what, void *valp) { switch (what) { case SM_IO_WHAT_MODE: return sm_thrsetmode(fp, (const int *)valp); default: return sm_error_perm(SM_EM_STTHRIO, EINVAL); } } /* ** SM_GETINFO -- get information about the open file ** ** Parameters: ** fp -- file to get info for ** what -- type of info to get ** valp -- location to place found info ** ** Returns: ** Success: may or may not place info in 'valp' depending ** on 'what' value, and returns values >=0. Return ** value may be the obtained info ** Failure: usual sm_error code. */ static sm_ret_T sm_thrgetinfo(sm_file_T *fp, int what, void *valp) { switch (what) { case SM_IO_WHAT_MODE: return sm_thrgetmode(fp, (int *)valp); case SM_IO_WHAT_FD: return f_fd(*fp); #if 0 case SM_IO_WHAT_NETFD: valp = f_netfd(*fp); return SM_SUCCESS; #endif /* 0 */ /* XXX check state-threads code! */ case SM_IO_IS_READABLE: if (st_netfd_poll(f_netfd(*fp), POLLIN, (st_utime_t) 0) == 0) return 1; return 0; default: return sm_error_perm(SM_EM_STTHRIO, EINVAL); } } /* ** SM_THRFDOPEN -- open file by primitive 'fd' rather than pathname ** ** I/O function to handle fdopen() stdio equivalence. The rest of ** the functions are the same as the sm_stdopen() above. ** ** Parameters: ** fp -- the file pointer to be associated with the open ** name -- the primitive file descriptor for association ** flags -- indicates type of access methods ** ** Results: ** usual sm_error code. */ /* ARGSUSED3 */ static sm_ret_T sm_thrfdopen(sm_file_T *fp, const void *info, int flags, va_list ap) { int fd; st_netfd_t netfd; fd = *((const int *) info); #if 0 switch (flags) { case SM_IO_RDWR: oflags = O_RDWR | O_CREAT; break; case SM_IO_RDONLY: oflags = O_RDONLY; break; case SM_IO_WRONLY: oflags = O_WRONLY | O_CREAT | O_TRUNC; break; default: return sm_error_perm(SM_EM_STTHRIO, EINVAL); } #endif /* 0 */ netfd = st_netfd_open(fd); if (netfd == NULL) return sm_error_perm(SM_EM_STTHRIO, errno); /* ??? temp? */ f_fd(*fp) = fd; assign_f_netfd(*fp, netfd); return SM_SUCCESS; } /* ** SM_THRNETOPEN -- open file by netfd 'fd' rather than pathname ** ** Parameters: ** fp -- the file pointer to be associated with the open ** name -- the primitive file descriptor for association ** flags -- indicates type of access methods ** ** Results: ** usual sm_error code. */ /* ARGSUSED3 */ static sm_ret_T sm_thrnetopen(sm_file_T *fp, const void *info, int flags, va_list ap) { st_netfd_t netfd; netfd = *((st_netfd_t *) info); f_fd(*fp) = st_netfd_fileno(netfd); assign_f_netfd(*fp, netfd); return SM_SUCCESS; } #if 0 /* ** SM_THRCLOSE -- close the file ** ** Parameters: ** fp -- the file pointer to close ** flags -- ignored ** ** Returns: ** usual sm_error code */ static sm_ret_T sm_thrnetclose(sm_file_T *fp, int flags) { return SM_SUCCESS; } #endif /* 0 */