1N/A/*
1N/A * Copyright (c) 2000-2002, 2004 Sendmail, Inc. and its suppliers.
1N/A * All rights reserved.
1N/A *
1N/A * By using this file, you agree to the terms and conditions set
1N/A * forth in the LICENSE file which can be found at the top level of
1N/A * the sendmail distribution.
1N/A */
1N/A
1N/A#pragma ident "%Z%%M% %I% %E% SMI"
1N/A
1N/A#include <sm/gen.h>
1N/ASM_IDSTR(id, "@(#)$Id: smstdio.c,v 1.34 2004/08/03 20:46:34 ca Exp $")
1N/A#include <unistd.h>
1N/A#include <stdio.h>
1N/A#include <fcntl.h>
1N/A#include <errno.h>
1N/A#include <sys/stat.h>
1N/A#include <sm/assert.h>
1N/A#include <sm/io.h>
1N/A#include <sm/string.h>
1N/A#include "local.h"
1N/A
1N/Astatic void setup __P((SM_FILE_T *));
1N/A
1N/A/*
1N/A** Overall:
1N/A** This is a file type which implements a layer on top of the system
1N/A** stdio. fp->f_cookie is the FILE* of stdio. The cookie may be
1N/A** "bound late" because of the manner which Linux implements stdio.
1N/A** When binding late (when fp->f_cookie==NULL) then the value of
1N/A** fp->f_ival is used (0, 1 or 2) to map to stdio's stdin, stdout or
1N/A** stderr.
1N/A*/
1N/A
1N/A/*
1N/A** SM_STDIOOPEN -- open a file to system stdio implementation
1N/A**
1N/A** Parameters:
1N/A** fp -- file pointer assign for this open
1N/A** info -- info about file to open
1N/A** flags -- indicating method of opening
1N/A** rpool -- ignored
1N/A**
1N/A** Returns:
1N/A** Failure: -1
1N/A** Success: 0 (zero)
1N/A*/
1N/A
1N/A/* ARGSUSED3 */
1N/Aint
1N/Asm_stdioopen(fp, info, flags, rpool)
1N/A SM_FILE_T *fp;
1N/A const void *info;
1N/A int flags;
1N/A const void *rpool;
1N/A{
1N/A register FILE *s;
1N/A char *stdiomode;
1N/A
1N/A switch (flags)
1N/A {
1N/A case SM_IO_RDONLY:
1N/A stdiomode = "r";
1N/A break;
1N/A case SM_IO_WRONLY:
1N/A stdiomode = "w";
1N/A break;
1N/A case SM_IO_APPEND:
1N/A stdiomode = "a";
1N/A break;
1N/A case SM_IO_APPENDRW:
1N/A stdiomode = "a+";
1N/A break;
1N/A#if SM_IO_BINARY != 0
1N/A case SM_IO_RDONLY_B:
1N/A stdiomode = "rb";
1N/A break;
1N/A case SM_IO_WRONLY_B:
1N/A stdiomode = "wb";
1N/A break;
1N/A case SM_IO_APPEND_B:
1N/A stdiomode = "ab";
1N/A break;
1N/A case SM_IO_APPENDRW_B:
1N/A stdiomode = "a+b";
1N/A break;
1N/A case SM_IO_RDWR_B:
1N/A stdiomode = "r+b";
1N/A break;
1N/A#endif /* SM_IO_BINARY != 0 */
1N/A case SM_IO_RDWR:
1N/A default:
1N/A stdiomode = "r+";
1N/A break;
1N/A }
1N/A
1N/A if ((s = fopen((char *)info, stdiomode)) == NULL)
1N/A return -1;
1N/A fp->f_cookie = s;
1N/A return 0;
1N/A}
1N/A
1N/A/*
1N/A** SETUP -- assign file type cookie when not already assigned
1N/A**
1N/A** Parameters:
1N/A** fp - the file pointer to get the cookie assigned
1N/A**
1N/A** Return:
1N/A** none.
1N/A*/
1N/A
1N/Astatic void
1N/Asetup(fp)
1N/A SM_FILE_T *fp;
1N/A{
1N/A if (fp->f_cookie == NULL)
1N/A {
1N/A switch (fp->f_ival)
1N/A {
1N/A case 0:
1N/A fp->f_cookie = stdin;
1N/A break;
1N/A case 1:
1N/A fp->f_cookie = stdout;
1N/A break;
1N/A case 2:
1N/A fp->f_cookie = stderr;
1N/A break;
1N/A default:
1N/A sm_abort("fp->f_ival=%d: out of range (0...2)", fp->f_ival);
1N/A break;
1N/A }
1N/A }
1N/A}
1N/A
1N/A/*
1N/A** SM_STDIOREAD -- read from the file
1N/A**
1N/A** Parameters:
1N/A** fp -- the file pointer
1N/A** buf -- location to place the read data
1N/A** n - number of bytes to read
1N/A**
1N/A** Returns:
1N/A** result from fread().
1N/A*/
1N/A
1N/Assize_t
1N/Asm_stdioread(fp, buf, n)
1N/A SM_FILE_T *fp;
1N/A char *buf;
1N/A size_t n;
1N/A{
1N/A register FILE *s;
1N/A
1N/A if (fp->f_cookie == NULL)
1N/A setup(fp);
1N/A s = fp->f_cookie;
1N/A return fread(buf, 1, n, s);
1N/A}
1N/A
1N/A/*
1N/A** SM_STDIOWRITE -- write to the file
1N/A**
1N/A** Parameters:
1N/A** fp -- the file pointer
1N/A** buf -- location of data to write
1N/A** n - number of bytes to write
1N/A**
1N/A** Returns:
1N/A** result from fwrite().
1N/A*/
1N/A
1N/Assize_t
1N/Asm_stdiowrite(fp, buf, n)
1N/A SM_FILE_T *fp;
1N/A char const *buf;
1N/A size_t n;
1N/A{
1N/A register FILE *s;
1N/A
1N/A if (fp->f_cookie == NULL)
1N/A setup(fp);
1N/A s = fp->f_cookie;
1N/A return fwrite(buf, 1, n, s);
1N/A}
1N/A
1N/A/*
1N/A** SM_STDIOSEEK -- set position within file
1N/A**
1N/A** Parameters:
1N/A** fp -- the file pointer
1N/A** offset -- new location based on 'whence'
1N/A** whence -- indicates "base" for 'offset'
1N/A**
1N/A** Returns:
1N/A** result from fseek().
1N/A*/
1N/A
1N/Aoff_t
1N/Asm_stdioseek(fp, offset, whence)
1N/A SM_FILE_T *fp;
1N/A off_t offset;
1N/A int whence;
1N/A{
1N/A register FILE *s;
1N/A
1N/A if (fp->f_cookie == NULL)
1N/A setup(fp);
1N/A s = fp->f_cookie;
1N/A return fseek(s, offset, whence);
1N/A}
1N/A
1N/A/*
1N/A** SM_STDIOCLOSE -- close the file
1N/A**
1N/A** Parameters:
1N/A** fp -- close file pointer
1N/A**
1N/A** Return:
1N/A** status from fclose()
1N/A*/
1N/A
1N/Aint
1N/Asm_stdioclose(fp)
1N/A SM_FILE_T *fp;
1N/A{
1N/A register FILE *s;
1N/A
1N/A if (fp->f_cookie == NULL)
1N/A setup(fp);
1N/A s = fp->f_cookie;
1N/A return fclose(s);
1N/A}
1N/A
1N/A/*
1N/A** SM_STDIOSETINFO -- set info for this open file
1N/A**
1N/A** Parameters:
1N/A** fp -- the file pointer
1N/A** what -- type of information setting
1N/A** valp -- memory location of info to set
1N/A**
1N/A** Return:
1N/A** Failure: -1 and sets errno
1N/A** Success: none (currently).
1N/A*/
1N/A
1N/A/* ARGSUSED2 */
1N/Aint
1N/Asm_stdiosetinfo(fp, what, valp)
1N/A SM_FILE_T *fp;
1N/A int what;
1N/A void *valp;
1N/A{
1N/A switch (what)
1N/A {
1N/A case SM_IO_WHAT_MODE:
1N/A default:
1N/A errno = EINVAL;
1N/A return -1;
1N/A }
1N/A}
1N/A
1N/A/*
1N/A** SM_STDIOGETINFO -- get info for this open file
1N/A**
1N/A** Parameters:
1N/A** fp -- the file pointer
1N/A** what -- type of information request
1N/A** valp -- memory location to place info
1N/A**
1N/A** Return:
1N/A** Failure: -1 and sets errno
1N/A** Success: none (currently).
1N/A*/
1N/A
1N/A/* ARGSUSED2 */
1N/Aint
1N/Asm_stdiogetinfo(fp, what, valp)
1N/A SM_FILE_T *fp;
1N/A int what;
1N/A void *valp;
1N/A{
1N/A switch (what)
1N/A {
1N/A case SM_IO_WHAT_SIZE:
1N/A {
1N/A int fd;
1N/A struct stat st;
1N/A
1N/A if (fp->f_cookie == NULL)
1N/A setup(fp);
1N/A fd = fileno((FILE *) fp->f_cookie);
1N/A if (fd < 0)
1N/A return -1;
1N/A if (fstat(fd, &st) == 0)
1N/A return st.st_size;
1N/A else
1N/A return -1;
1N/A }
1N/A
1N/A case SM_IO_WHAT_MODE:
1N/A default:
1N/A errno = EINVAL;
1N/A return -1;
1N/A }
1N/A}
1N/A
1N/A/*
1N/A** SM_IO_STDIOOPEN -- create an SM_FILE which interfaces to a stdio FILE
1N/A**
1N/A** Parameters:
1N/A** stream -- an open stdio stream, as returned by fopen()
1N/A** mode -- the mode argument to fopen() which describes stream
1N/A**
1N/A** Return:
1N/A** On success, return a pointer to an SM_FILE object which
1N/A** can be used for reading and writing 'stream'.
1N/A** Abort if mode is gibberish or stream is bad.
1N/A** Raise an exception if we can't allocate memory.
1N/A*/
1N/A
1N/ASM_FILE_T *
1N/Asm_io_stdioopen(stream, mode)
1N/A FILE *stream;
1N/A char *mode;
1N/A{
1N/A int fd;
1N/A bool r, w;
1N/A int ioflags;
1N/A SM_FILE_T *fp;
1N/A
1N/A fd = fileno(stream);
1N/A SM_REQUIRE(fd >= 0);
1N/A
1N/A r = w = false;
1N/A switch (mode[0])
1N/A {
1N/A case 'r':
1N/A r = true;
1N/A break;
1N/A case 'w':
1N/A case 'a':
1N/A w = true;
1N/A break;
1N/A default:
1N/A sm_abort("sm_io_stdioopen: mode '%s' is bad", mode);
1N/A }
1N/A if (strchr(&mode[1], '+') != NULL)
1N/A r = w = true;
1N/A if (r && w)
1N/A ioflags = SMRW;
1N/A else if (r)
1N/A ioflags = SMRD;
1N/A else
1N/A ioflags = SMWR;
1N/A
1N/A fp = sm_fp(SmFtRealStdio, ioflags, NULL);
1N/A fp->f_file = fd;
1N/A fp->f_cookie = stream;
1N/A return fp;
1N/A}