190792Sgshapiro/*
2132943Sgshapiro * Copyright (c) 2000-2002, 2004 Sendmail, Inc. and its suppliers.
390792Sgshapiro *      All rights reserved.
490792Sgshapiro *
590792Sgshapiro * By using this file, you agree to the terms and conditions set
690792Sgshapiro * forth in the LICENSE file which can be found at the top level of
790792Sgshapiro * the sendmail distribution.
890792Sgshapiro */
990792Sgshapiro
1090792Sgshapiro#include <sm/gen.h>
11141858SgshapiroSM_IDSTR(id, "@(#)$Id: smstdio.c,v 1.34 2004/08/03 20:46:34 ca Exp $")
1290792Sgshapiro#include <unistd.h>
1390792Sgshapiro#include <stdio.h>
1490792Sgshapiro#include <fcntl.h>
1590792Sgshapiro#include <errno.h>
1694334Sgshapiro#include <sys/stat.h>
1790792Sgshapiro#include <sm/assert.h>
1890792Sgshapiro#include <sm/io.h>
1990792Sgshapiro#include <sm/string.h>
2090792Sgshapiro#include "local.h"
2190792Sgshapiro
22141858Sgshapirostatic void	setup __P((SM_FILE_T *));
23141858Sgshapiro
2490792Sgshapiro/*
2590792Sgshapiro** Overall:
2690792Sgshapiro**	This is a file type which implements a layer on top of the system
2790792Sgshapiro**	stdio. fp->f_cookie is the FILE* of stdio. The cookie may be
2890792Sgshapiro**	"bound late" because of the manner which Linux implements stdio.
2990792Sgshapiro**	When binding late  (when fp->f_cookie==NULL) then the value of
3090792Sgshapiro**	fp->f_ival is used (0, 1 or 2) to map to stdio's stdin, stdout or
3190792Sgshapiro**	stderr.
3290792Sgshapiro*/
3390792Sgshapiro
3490792Sgshapiro/*
3590792Sgshapiro**  SM_STDIOOPEN -- open a file to system stdio implementation
3690792Sgshapiro**
3790792Sgshapiro**	Parameters:
3890792Sgshapiro**		fp -- file pointer assign for this open
3990792Sgshapiro**		info -- info about file to open
4090792Sgshapiro**		flags -- indicating method of opening
4190792Sgshapiro**		rpool -- ignored
4290792Sgshapiro**
4390792Sgshapiro**	Returns:
4490792Sgshapiro**		Failure: -1
4590792Sgshapiro**		Success: 0 (zero)
4690792Sgshapiro*/
4790792Sgshapiro
4890792Sgshapiro/* ARGSUSED3 */
4990792Sgshapiroint
5090792Sgshapirosm_stdioopen(fp, info, flags, rpool)
5190792Sgshapiro	SM_FILE_T *fp;
5290792Sgshapiro	const void *info;
5390792Sgshapiro	int flags;
5490792Sgshapiro	const void *rpool;
5590792Sgshapiro{
5690792Sgshapiro	register FILE *s;
5790792Sgshapiro	char *stdiomode;
5890792Sgshapiro
5990792Sgshapiro	switch (flags)
6090792Sgshapiro	{
6190792Sgshapiro	  case SM_IO_RDONLY:
6290792Sgshapiro		stdiomode = "r";
6390792Sgshapiro		break;
6490792Sgshapiro	  case SM_IO_WRONLY:
6590792Sgshapiro		stdiomode = "w";
6690792Sgshapiro		break;
6790792Sgshapiro	  case SM_IO_APPEND:
6890792Sgshapiro		stdiomode = "a";
6990792Sgshapiro		break;
7090792Sgshapiro	  case SM_IO_APPENDRW:
7190792Sgshapiro		stdiomode = "a+";
7290792Sgshapiro		break;
73120256Sgshapiro#if SM_IO_BINARY != 0
74120256Sgshapiro	  case SM_IO_RDONLY_B:
75120256Sgshapiro		stdiomode = "rb";
76120256Sgshapiro		break;
77120256Sgshapiro	  case SM_IO_WRONLY_B:
78120256Sgshapiro		stdiomode = "wb";
79120256Sgshapiro		break;
80120256Sgshapiro	  case SM_IO_APPEND_B:
81120256Sgshapiro		stdiomode = "ab";
82120256Sgshapiro		break;
83120256Sgshapiro	  case SM_IO_APPENDRW_B:
84120256Sgshapiro		stdiomode = "a+b";
85120256Sgshapiro		break;
86120256Sgshapiro	  case SM_IO_RDWR_B:
87120256Sgshapiro		stdiomode = "r+b";
88120256Sgshapiro		break;
89120256Sgshapiro#endif /* SM_IO_BINARY != 0 */
9090792Sgshapiro	  case SM_IO_RDWR:
9190792Sgshapiro	  default:
9290792Sgshapiro		stdiomode = "r+";
9390792Sgshapiro		break;
9490792Sgshapiro	}
9590792Sgshapiro
9690792Sgshapiro	if ((s = fopen((char *)info, stdiomode)) == NULL)
9790792Sgshapiro		return -1;
9890792Sgshapiro	fp->f_cookie = s;
9990792Sgshapiro	return 0;
10090792Sgshapiro}
10190792Sgshapiro
10290792Sgshapiro/*
10390792Sgshapiro**  SETUP -- assign file type cookie when not already assigned
10490792Sgshapiro**
10590792Sgshapiro**	Parameters:
10690792Sgshapiro**		fp - the file pointer to get the cookie assigned
10790792Sgshapiro**
10890792Sgshapiro**	Return:
10990792Sgshapiro**		none.
11090792Sgshapiro*/
11190792Sgshapiro
11290792Sgshapirostatic void
11390792Sgshapirosetup(fp)
11490792Sgshapiro	SM_FILE_T *fp;
11590792Sgshapiro{
11690792Sgshapiro	if (fp->f_cookie == NULL)
11790792Sgshapiro	{
11890792Sgshapiro		switch (fp->f_ival)
11990792Sgshapiro		{
12090792Sgshapiro		  case 0:
12190792Sgshapiro			fp->f_cookie = stdin;
12290792Sgshapiro			break;
12390792Sgshapiro		  case 1:
12490792Sgshapiro			fp->f_cookie = stdout;
12590792Sgshapiro			break;
12690792Sgshapiro		  case 2:
12790792Sgshapiro			fp->f_cookie = stderr;
12890792Sgshapiro			break;
12990792Sgshapiro		  default:
13090792Sgshapiro			sm_abort("fp->f_ival=%d: out of range (0...2)", fp->f_ival);
13190792Sgshapiro			break;
13290792Sgshapiro		}
13390792Sgshapiro	}
13490792Sgshapiro}
13590792Sgshapiro
13690792Sgshapiro/*
13790792Sgshapiro**  SM_STDIOREAD -- read from the file
13890792Sgshapiro**
13990792Sgshapiro**	Parameters:
14090792Sgshapiro**		fp -- the file pointer
14190792Sgshapiro**		buf -- location to place the read data
14290792Sgshapiro**		n - number of bytes to read
14390792Sgshapiro**
14490792Sgshapiro**	Returns:
14590792Sgshapiro**		result from fread().
14690792Sgshapiro*/
14790792Sgshapiro
14890792Sgshapirossize_t
14990792Sgshapirosm_stdioread(fp, buf, n)
15090792Sgshapiro	SM_FILE_T *fp;
15190792Sgshapiro	char *buf;
15290792Sgshapiro	size_t n;
15390792Sgshapiro{
15490792Sgshapiro	register FILE *s;
15590792Sgshapiro
15690792Sgshapiro	if (fp->f_cookie == NULL)
15790792Sgshapiro		setup(fp);
15890792Sgshapiro	s = fp->f_cookie;
15990792Sgshapiro	return fread(buf, 1, n, s);
16090792Sgshapiro}
16190792Sgshapiro
16290792Sgshapiro/*
16390792Sgshapiro**  SM_STDIOWRITE -- write to the file
16490792Sgshapiro**
16590792Sgshapiro**	Parameters:
16690792Sgshapiro**		fp -- the file pointer
16790792Sgshapiro**		buf -- location of data to write
16890792Sgshapiro**		n - number of bytes to write
16990792Sgshapiro**
17090792Sgshapiro**	Returns:
17190792Sgshapiro**		result from fwrite().
17290792Sgshapiro*/
17390792Sgshapiro
17490792Sgshapirossize_t
17590792Sgshapirosm_stdiowrite(fp, buf, n)
17690792Sgshapiro	SM_FILE_T *fp;
17790792Sgshapiro	char const *buf;
17890792Sgshapiro	size_t n;
17990792Sgshapiro{
18090792Sgshapiro	register FILE *s;
18190792Sgshapiro
18290792Sgshapiro	if (fp->f_cookie == NULL)
18390792Sgshapiro		setup(fp);
18490792Sgshapiro	s = fp->f_cookie;
18590792Sgshapiro	return fwrite(buf, 1, n, s);
18690792Sgshapiro}
18790792Sgshapiro
18890792Sgshapiro/*
18990792Sgshapiro**  SM_STDIOSEEK -- set position within file
19090792Sgshapiro**
19190792Sgshapiro**	Parameters:
19290792Sgshapiro**		fp -- the file pointer
19390792Sgshapiro**		offset -- new location based on 'whence'
19490792Sgshapiro**		whence -- indicates "base" for 'offset'
19590792Sgshapiro**
19690792Sgshapiro**	Returns:
19790792Sgshapiro**		result from fseek().
19890792Sgshapiro*/
19990792Sgshapiro
20090792Sgshapirooff_t
20190792Sgshapirosm_stdioseek(fp, offset, whence)
20290792Sgshapiro	SM_FILE_T *fp;
20390792Sgshapiro	off_t offset;
20490792Sgshapiro	int whence;
20590792Sgshapiro{
20690792Sgshapiro	register FILE *s;
20790792Sgshapiro
20890792Sgshapiro	if (fp->f_cookie == NULL)
20990792Sgshapiro		setup(fp);
21090792Sgshapiro	s = fp->f_cookie;
21190792Sgshapiro	return fseek(s, offset, whence);
21290792Sgshapiro}
21390792Sgshapiro
21490792Sgshapiro/*
21590792Sgshapiro**  SM_STDIOCLOSE -- close the file
21690792Sgshapiro**
21790792Sgshapiro**	Parameters:
21890792Sgshapiro**		fp -- close file pointer
21990792Sgshapiro**
22090792Sgshapiro**	Return:
22190792Sgshapiro**		status from fclose()
22290792Sgshapiro*/
22390792Sgshapiro
22490792Sgshapiroint
22590792Sgshapirosm_stdioclose(fp)
22690792Sgshapiro	SM_FILE_T *fp;
22790792Sgshapiro{
22890792Sgshapiro	register FILE *s;
22990792Sgshapiro
23090792Sgshapiro	if (fp->f_cookie == NULL)
23190792Sgshapiro		setup(fp);
23290792Sgshapiro	s = fp->f_cookie;
23390792Sgshapiro	return fclose(s);
23490792Sgshapiro}
23590792Sgshapiro
23690792Sgshapiro/*
23790792Sgshapiro**  SM_STDIOSETINFO -- set info for this open file
23890792Sgshapiro**
23990792Sgshapiro**	Parameters:
24090792Sgshapiro**		fp -- the file pointer
24190792Sgshapiro**		what -- type of information setting
24290792Sgshapiro**		valp -- memory location of info to set
24390792Sgshapiro**
24490792Sgshapiro**	Return:
24590792Sgshapiro**		Failure: -1 and sets errno
24690792Sgshapiro**		Success: none (currently).
24790792Sgshapiro*/
24890792Sgshapiro
24990792Sgshapiro/* ARGSUSED2 */
25090792Sgshapiroint
25190792Sgshapirosm_stdiosetinfo(fp, what, valp)
25290792Sgshapiro	SM_FILE_T *fp;
25390792Sgshapiro	int what;
25490792Sgshapiro	void *valp;
25590792Sgshapiro{
25690792Sgshapiro	switch (what)
25790792Sgshapiro	{
25890792Sgshapiro	  case SM_IO_WHAT_MODE:
25990792Sgshapiro	  default:
26090792Sgshapiro		errno = EINVAL;
26190792Sgshapiro		return -1;
26290792Sgshapiro	}
26390792Sgshapiro}
26490792Sgshapiro
26590792Sgshapiro/*
26690792Sgshapiro**  SM_STDIOGETINFO -- get info for this open file
26790792Sgshapiro**
26890792Sgshapiro**	Parameters:
26990792Sgshapiro**		fp -- the file pointer
27090792Sgshapiro**		what -- type of information request
27190792Sgshapiro**		valp -- memory location to place info
27290792Sgshapiro**
27390792Sgshapiro**	Return:
27490792Sgshapiro**		Failure: -1 and sets errno
27590792Sgshapiro**		Success: none (currently).
27690792Sgshapiro*/
27790792Sgshapiro
27890792Sgshapiro/* ARGSUSED2 */
27990792Sgshapiroint
28090792Sgshapirosm_stdiogetinfo(fp, what, valp)
28190792Sgshapiro	SM_FILE_T *fp;
28290792Sgshapiro	int what;
28390792Sgshapiro	void *valp;
28490792Sgshapiro{
28590792Sgshapiro	switch (what)
28690792Sgshapiro	{
28794334Sgshapiro	  case SM_IO_WHAT_SIZE:
28894334Sgshapiro	  {
28994334Sgshapiro		  int fd;
29094334Sgshapiro		  struct stat st;
29194334Sgshapiro
29294334Sgshapiro		  if (fp->f_cookie == NULL)
29394334Sgshapiro			  setup(fp);
29494334Sgshapiro		  fd = fileno((FILE *) fp->f_cookie);
29594334Sgshapiro		  if (fd < 0)
29694334Sgshapiro			  return -1;
29794334Sgshapiro		  if (fstat(fd, &st) == 0)
29894334Sgshapiro			  return st.st_size;
29994334Sgshapiro		  else
30094334Sgshapiro			  return -1;
30194334Sgshapiro	  }
30294334Sgshapiro
30390792Sgshapiro	  case SM_IO_WHAT_MODE:
30490792Sgshapiro	  default:
30590792Sgshapiro		errno = EINVAL;
30690792Sgshapiro		return -1;
30790792Sgshapiro	}
30890792Sgshapiro}
30990792Sgshapiro
31090792Sgshapiro/*
31190792Sgshapiro**  SM_IO_STDIOOPEN -- create an SM_FILE which interfaces to a stdio FILE
31290792Sgshapiro**
31390792Sgshapiro**	Parameters:
31490792Sgshapiro**		stream -- an open stdio stream, as returned by fopen()
31590792Sgshapiro**		mode -- the mode argument to fopen() which describes stream
31690792Sgshapiro**
31790792Sgshapiro**	Return:
31890792Sgshapiro**		On success, return a pointer to an SM_FILE object which
31990792Sgshapiro**		can be used for reading and writing 'stream'.
32090792Sgshapiro**		Abort if mode is gibberish or stream is bad.
32190792Sgshapiro**		Raise an exception if we can't allocate memory.
32290792Sgshapiro*/
32390792Sgshapiro
32490792SgshapiroSM_FILE_T *
32590792Sgshapirosm_io_stdioopen(stream, mode)
32690792Sgshapiro	FILE *stream;
32790792Sgshapiro	char *mode;
32890792Sgshapiro{
32990792Sgshapiro	int fd;
33090792Sgshapiro	bool r, w;
33190792Sgshapiro	int ioflags;
33290792Sgshapiro	SM_FILE_T *fp;
33390792Sgshapiro
33490792Sgshapiro	fd = fileno(stream);
33590792Sgshapiro	SM_REQUIRE(fd >= 0);
33690792Sgshapiro
33790792Sgshapiro	r = w = false;
33890792Sgshapiro	switch (mode[0])
33990792Sgshapiro	{
34090792Sgshapiro	  case 'r':
34190792Sgshapiro		r = true;
34290792Sgshapiro		break;
34390792Sgshapiro	  case 'w':
34490792Sgshapiro	  case 'a':
34590792Sgshapiro		w = true;
34690792Sgshapiro		break;
34790792Sgshapiro	  default:
34890792Sgshapiro		sm_abort("sm_io_stdioopen: mode '%s' is bad", mode);
34990792Sgshapiro	}
35090792Sgshapiro	if (strchr(&mode[1], '+') != NULL)
35190792Sgshapiro		r = w = true;
35290792Sgshapiro	if (r && w)
35390792Sgshapiro		ioflags = SMRW;
35490792Sgshapiro	else if (r)
35590792Sgshapiro		ioflags = SMRD;
35690792Sgshapiro	else
35790792Sgshapiro		ioflags = SMWR;
35890792Sgshapiro
35990792Sgshapiro	fp = sm_fp(SmFtRealStdio, ioflags, NULL);
36090792Sgshapiro	fp->f_file = fd;
36190792Sgshapiro	fp->f_cookie = stream;
36290792Sgshapiro	return fp;
36390792Sgshapiro}
364