18449595gshapiro/*
2b649239gshapiro * Copyright (c) 2000-2002, 2004 Proofpoint, Inc. and its suppliers.
38449595gshapiro *      All rights reserved.
48449595gshapiro *
58449595gshapiro * By using this file, you agree to the terms and conditions set
68449595gshapiro * forth in the LICENSE file which can be found at the top level of
78449595gshapiro * the sendmail distribution.
88449595gshapiro */
98449595gshapiro
108449595gshapiro#include <sm/gen.h>
1148cecd8gshapiroSM_IDSTR(id, "@(#)$Id: smstdio.c,v 1.35 2013-11-22 20:51:43 ca Exp $")
128449595gshapiro#include <unistd.h>
138449595gshapiro#include <stdio.h>
148449595gshapiro#include <fcntl.h>
158449595gshapiro#include <errno.h>
169e3bd35gshapiro#include <sys/stat.h>
178449595gshapiro#include <sm/assert.h>
188449595gshapiro#include <sm/io.h>
198449595gshapiro#include <sm/string.h>
208449595gshapiro#include "local.h"
218449595gshapiro
229883351gshapirostatic void	setup __P((SM_FILE_T *));
239883351gshapiro
248449595gshapiro/*
258449595gshapiro** Overall:
268449595gshapiro**	This is a file type which implements a layer on top of the system
278449595gshapiro**	stdio. fp->f_cookie is the FILE* of stdio. The cookie may be
288449595gshapiro**	"bound late" because of the manner which Linux implements stdio.
298449595gshapiro**	When binding late  (when fp->f_cookie==NULL) then the value of
308449595gshapiro**	fp->f_ival is used (0, 1 or 2) to map to stdio's stdin, stdout or
318449595gshapiro**	stderr.
328449595gshapiro*/
338449595gshapiro
348449595gshapiro/*
358449595gshapiro**  SM_STDIOOPEN -- open a file to system stdio implementation
368449595gshapiro**
378449595gshapiro**	Parameters:
388449595gshapiro**		fp -- file pointer assign for this open
398449595gshapiro**		info -- info about file to open
408449595gshapiro**		flags -- indicating method of opening
418449595gshapiro**		rpool -- ignored
428449595gshapiro**
438449595gshapiro**	Returns:
448449595gshapiro**		Failure: -1
458449595gshapiro**		Success: 0 (zero)
468449595gshapiro*/
478449595gshapiro
488449595gshapiro/* ARGSUSED3 */
498449595gshapiroint
508449595gshapirosm_stdioopen(fp, info, flags, rpool)
518449595gshapiro	SM_FILE_T *fp;
528449595gshapiro	const void *info;
538449595gshapiro	int flags;
548449595gshapiro	const void *rpool;
558449595gshapiro{
568449595gshapiro	register FILE *s;
578449595gshapiro	char *stdiomode;
588449595gshapiro
598449595gshapiro	switch (flags)
608449595gshapiro	{
618449595gshapiro	  case SM_IO_RDONLY:
628449595gshapiro		stdiomode = "r";
638449595gshapiro		break;
648449595gshapiro	  case SM_IO_WRONLY:
658449595gshapiro		stdiomode = "w";
668449595gshapiro		break;
678449595gshapiro	  case SM_IO_APPEND:
688449595gshapiro		stdiomode = "a";
698449595gshapiro		break;
708449595gshapiro	  case SM_IO_APPENDRW:
718449595gshapiro		stdiomode = "a+";
728449595gshapiro		break;
7396b960fgshapiro#if SM_IO_BINARY != 0
7496b960fgshapiro	  case SM_IO_RDONLY_B:
7596b960fgshapiro		stdiomode = "rb";
7696b960fgshapiro		break;
7796b960fgshapiro	  case SM_IO_WRONLY_B:
7896b960fgshapiro		stdiomode = "wb";
7996b960fgshapiro		break;
8096b960fgshapiro	  case SM_IO_APPEND_B:
8196b960fgshapiro		stdiomode = "ab";
8296b960fgshapiro		break;
8396b960fgshapiro	  case SM_IO_APPENDRW_B:
8496b960fgshapiro		stdiomode = "a+b";
8596b960fgshapiro		break;
8696b960fgshapiro	  case SM_IO_RDWR_B:
8796b960fgshapiro		stdiomode = "r+b";
8896b960fgshapiro		break;
8996b960fgshapiro#endif /* SM_IO_BINARY != 0 */
908449595gshapiro	  case SM_IO_RDWR:
918449595gshapiro	  default:
928449595gshapiro		stdiomode = "r+";
938449595gshapiro		break;
948449595gshapiro	}
958449595gshapiro
968449595gshapiro	if ((s = fopen((char *)info, stdiomode)) == NULL)
978449595gshapiro		return -1;
988449595gshapiro	fp->f_cookie = s;
998449595gshapiro	return 0;
1008449595gshapiro}
1018449595gshapiro
1028449595gshapiro/*
1038449595gshapiro**  SETUP -- assign file type cookie when not already assigned
1048449595gshapiro**
1058449595gshapiro**	Parameters:
1068449595gshapiro**		fp - the file pointer to get the cookie assigned
1078449595gshapiro**
1088449595gshapiro**	Return:
1098449595gshapiro**		none.
1108449595gshapiro*/
1118449595gshapiro
1128449595gshapirostatic void
1138449595gshapirosetup(fp)
1148449595gshapiro	SM_FILE_T *fp;
1158449595gshapiro{
1168449595gshapiro	if (fp->f_cookie == NULL)
1178449595gshapiro	{
1188449595gshapiro		switch (fp->f_ival)
1198449595gshapiro		{
1208449595gshapiro		  case 0:
1218449595gshapiro			fp->f_cookie = stdin;
1228449595gshapiro			break;
1238449595gshapiro		  case 1:
1248449595gshapiro			fp->f_cookie = stdout;
1258449595gshapiro			break;
1268449595gshapiro		  case 2:
1278449595gshapiro			fp->f_cookie = stderr;
1288449595gshapiro			break;
1298449595gshapiro		  default:
1308449595gshapiro			sm_abort("fp->f_ival=%d: out of range (0...2)", fp->f_ival);
1318449595gshapiro			break;
1328449595gshapiro		}
1338449595gshapiro	}
1348449595gshapiro}
1358449595gshapiro
1368449595gshapiro/*
1378449595gshapiro**  SM_STDIOREAD -- read from the file
1388449595gshapiro**
1398449595gshapiro**	Parameters:
1408449595gshapiro**		fp -- the file pointer
1418449595gshapiro**		buf -- location to place the read data
1428449595gshapiro**		n - number of bytes to read
1438449595gshapiro**
1448449595gshapiro**	Returns:
1458449595gshapiro**		result from fread().
1468449595gshapiro*/
1478449595gshapiro
1488449595gshapirossize_t
1498449595gshapirosm_stdioread(fp, buf, n)
1508449595gshapiro	SM_FILE_T *fp;
1518449595gshapiro	char *buf;
1528449595gshapiro	size_t n;
1538449595gshapiro{
1548449595gshapiro	register FILE *s;
1558449595gshapiro
1568449595gshapiro	if (fp->f_cookie == NULL)
1578449595gshapiro		setup(fp);
1588449595gshapiro	s = fp->f_cookie;
1598449595gshapiro	return fread(buf, 1, n, s);
1608449595gshapiro}
1618449595gshapiro
1628449595gshapiro/*
1638449595gshapiro**  SM_STDIOWRITE -- write to the file
1648449595gshapiro**
1658449595gshapiro**	Parameters:
1668449595gshapiro**		fp -- the file pointer
1678449595gshapiro**		buf -- location of data to write
1688449595gshapiro**		n - number of bytes to write
1698449595gshapiro**
1708449595gshapiro**	Returns:
1718449595gshapiro**		result from fwrite().
1728449595gshapiro*/
1738449595gshapiro
1748449595gshapirossize_t
1758449595gshapirosm_stdiowrite(fp, buf, n)
1768449595gshapiro	SM_FILE_T *fp;
1778449595gshapiro	char const *buf;
1788449595gshapiro	size_t n;
1798449595gshapiro{
1808449595gshapiro	register FILE *s;
1818449595gshapiro
1828449595gshapiro	if (fp->f_cookie == NULL)
1838449595gshapiro		setup(fp);
1848449595gshapiro	s = fp->f_cookie;
1858449595gshapiro	return fwrite(buf, 1, n, s);
1868449595gshapiro}
1878449595gshapiro
1888449595gshapiro/*
1898449595gshapiro**  SM_STDIOSEEK -- set position within file
1908449595gshapiro**
1918449595gshapiro**	Parameters:
1928449595gshapiro**		fp -- the file pointer
1938449595gshapiro**		offset -- new location based on 'whence'
1948449595gshapiro**		whence -- indicates "base" for 'offset'
1958449595gshapiro**
1968449595gshapiro**	Returns:
1978449595gshapiro**		result from fseek().
1988449595gshapiro*/
1998449595gshapiro
2008449595gshapirooff_t
2018449595gshapirosm_stdioseek(fp, offset, whence)
2028449595gshapiro	SM_FILE_T *fp;
2038449595gshapiro	off_t offset;
2048449595gshapiro	int whence;
2058449595gshapiro{
2068449595gshapiro	register FILE *s;
2078449595gshapiro
2088449595gshapiro	if (fp->f_cookie == NULL)
2098449595gshapiro		setup(fp);
2108449595gshapiro	s = fp->f_cookie;
2118449595gshapiro	return fseek(s, offset, whence);
2128449595gshapiro}
2138449595gshapiro
2148449595gshapiro/*
2158449595gshapiro**  SM_STDIOCLOSE -- close the file
2168449595gshapiro**
2178449595gshapiro**	Parameters:
2188449595gshapiro**		fp -- close file pointer
2198449595gshapiro**
2208449595gshapiro**	Return:
2218449595gshapiro**		status from fclose()
2228449595gshapiro*/
2238449595gshapiro
2248449595gshapiroint
2258449595gshapirosm_stdioclose(fp)
2268449595gshapiro	SM_FILE_T *fp;
2278449595gshapiro{
2288449595gshapiro	register FILE *s;
2298449595gshapiro
2308449595gshapiro	if (fp->f_cookie == NULL)
2318449595gshapiro		setup(fp);
2328449595gshapiro	s = fp->f_cookie;
2338449595gshapiro	return fclose(s);
2348449595gshapiro}
2358449595gshapiro
2368449595gshapiro/*
2378449595gshapiro**  SM_STDIOSETINFO -- set info for this open file
2388449595gshapiro**
2398449595gshapiro**	Parameters:
2408449595gshapiro**		fp -- the file pointer
2418449595gshapiro**		what -- type of information setting
2428449595gshapiro**		valp -- memory location of info to set
2438449595gshapiro**
2448449595gshapiro**	Return:
2458449595gshapiro**		Failure: -1 and sets errno
2468449595gshapiro**		Success: none (currently).
2478449595gshapiro*/
2488449595gshapiro
2498449595gshapiro/* ARGSUSED2 */
2508449595gshapiroint
2518449595gshapirosm_stdiosetinfo(fp, what, valp)
2528449595gshapiro	SM_FILE_T *fp;
2538449595gshapiro	int what;
2548449595gshapiro	void *valp;
2558449595gshapiro{
2568449595gshapiro	switch (what)
2578449595gshapiro	{
2588449595gshapiro	  case SM_IO_WHAT_MODE:
2598449595gshapiro	  default:
2608449595gshapiro		errno = EINVAL;
2618449595gshapiro		return -1;
2628449595gshapiro	}
2638449595gshapiro}
2648449595gshapiro
2658449595gshapiro/*
2668449595gshapiro**  SM_STDIOGETINFO -- get info for this open file
2678449595gshapiro**
2688449595gshapiro**	Parameters:
2698449595gshapiro**		fp -- the file pointer
2708449595gshapiro**		what -- type of information request
2718449595gshapiro**		valp -- memory location to place info
2728449595gshapiro**
2738449595gshapiro**	Return:
2748449595gshapiro**		Failure: -1 and sets errno
2758449595gshapiro**		Success: none (currently).
2768449595gshapiro*/
2778449595gshapiro
2788449595gshapiro/* ARGSUSED2 */
2798449595gshapiroint
2808449595gshapirosm_stdiogetinfo(fp, what, valp)
2818449595gshapiro	SM_FILE_T *fp;
2828449595gshapiro	int what;
2838449595gshapiro	void *valp;
2848449595gshapiro{
2858449595gshapiro	switch (what)
2868449595gshapiro	{
2879e3bd35gshapiro	  case SM_IO_WHAT_SIZE:
2889e3bd35gshapiro	  {
2899e3bd35gshapiro		  int fd;
2909e3bd35gshapiro		  struct stat st;
2919e3bd35gshapiro
2929e3bd35gshapiro		  if (fp->f_cookie == NULL)
2939e3bd35gshapiro			  setup(fp);
2949e3bd35gshapiro		  fd = fileno((FILE *) fp->f_cookie);
2959e3bd35gshapiro		  if (fd < 0)
2969e3bd35gshapiro			  return -1;
2979e3bd35gshapiro		  if (fstat(fd, &st) == 0)
2989e3bd35gshapiro			  return st.st_size;
2999e3bd35gshapiro		  else
3009e3bd35gshapiro			  return -1;
3019e3bd35gshapiro	  }
3029e3bd35gshapiro
3038449595gshapiro	  case SM_IO_WHAT_MODE:
3048449595gshapiro	  default:
3058449595gshapiro		errno = EINVAL;
3068449595gshapiro		return -1;
3078449595gshapiro	}
3088449595gshapiro}
3098449595gshapiro
3108449595gshapiro/*
3118449595gshapiro**  SM_IO_STDIOOPEN -- create an SM_FILE which interfaces to a stdio FILE
3128449595gshapiro**
3138449595gshapiro**	Parameters:
3148449595gshapiro**		stream -- an open stdio stream, as returned by fopen()
3158449595gshapiro**		mode -- the mode argument to fopen() which describes stream
3168449595gshapiro**
3178449595gshapiro**	Return:
3188449595gshapiro**		On success, return a pointer to an SM_FILE object which
3198449595gshapiro**		can be used for reading and writing 'stream'.
3208449595gshapiro**		Abort if mode is gibberish or stream is bad.
3218449595gshapiro**		Raise an exception if we can't allocate memory.
3228449595gshapiro*/
3238449595gshapiro
3248449595gshapiroSM_FILE_T *
3258449595gshapirosm_io_stdioopen(stream, mode)
3268449595gshapiro	FILE *stream;
3278449595gshapiro	char *mode;
3288449595gshapiro{
3298449595gshapiro	int fd;
3308449595gshapiro	bool r, w;
3318449595gshapiro	int ioflags;
3328449595gshapiro	SM_FILE_T *fp;
3338449595gshapiro
3348449595gshapiro	fd = fileno(stream);
3358449595gshapiro	SM_REQUIRE(fd >= 0);
3368449595gshapiro
3378449595gshapiro	r = w = false;
3388449595gshapiro	switch (mode[0])
3398449595gshapiro	{
3408449595gshapiro	  case 'r':
3418449595gshapiro		r = true;
3428449595gshapiro		break;
3438449595gshapiro	  case 'w':
3448449595gshapiro	  case 'a':
3458449595gshapiro		w = true;
3468449595gshapiro		break;
3478449595gshapiro	  default:
3488449595gshapiro		sm_abort("sm_io_stdioopen: mode '%s' is bad", mode);
3498449595gshapiro	}
3508449595gshapiro	if (strchr(&mode[1], '+') != NULL)
3518449595gshapiro		r = w = true;
3528449595gshapiro	if (r && w)
3538449595gshapiro		ioflags = SMRW;
3548449595gshapiro	else if (r)
3558449595gshapiro		ioflags = SMRD;
3568449595gshapiro	else
3578449595gshapiro		ioflags = SMWR;
3588449595gshapiro
3598449595gshapiro	fp = sm_fp(SmFtRealStdio, ioflags, NULL);
3608449595gshapiro	fp->f_file = fd;
3618449595gshapiro	fp->f_cookie = stream;
3628449595gshapiro	return fp;
3638449595gshapiro}
364