smstdio.c revision 261194
1/*
2 * Copyright (c) 2000-2002, 2004 Proofpoint, Inc. and its suppliers.
3 *      All rights reserved.
4 *
5 * By using this file, you agree to the terms and conditions set
6 * forth in the LICENSE file which can be found at the top level of
7 * the sendmail distribution.
8 */
9
10#include <sm/gen.h>
11SM_IDSTR(id, "@(#)$Id: smstdio.c,v 1.35 2013/11/22 20:51:43 ca Exp $")
12#include <unistd.h>
13#include <stdio.h>
14#include <fcntl.h>
15#include <errno.h>
16#include <sys/stat.h>
17#include <sm/assert.h>
18#include <sm/io.h>
19#include <sm/string.h>
20#include "local.h"
21
22static void	setup __P((SM_FILE_T *));
23
24/*
25** Overall:
26**	This is a file type which implements a layer on top of the system
27**	stdio. fp->f_cookie is the FILE* of stdio. The cookie may be
28**	"bound late" because of the manner which Linux implements stdio.
29**	When binding late  (when fp->f_cookie==NULL) then the value of
30**	fp->f_ival is used (0, 1 or 2) to map to stdio's stdin, stdout or
31**	stderr.
32*/
33
34/*
35**  SM_STDIOOPEN -- open a file to system stdio implementation
36**
37**	Parameters:
38**		fp -- file pointer assign for this open
39**		info -- info about file to open
40**		flags -- indicating method of opening
41**		rpool -- ignored
42**
43**	Returns:
44**		Failure: -1
45**		Success: 0 (zero)
46*/
47
48/* ARGSUSED3 */
49int
50sm_stdioopen(fp, info, flags, rpool)
51	SM_FILE_T *fp;
52	const void *info;
53	int flags;
54	const void *rpool;
55{
56	register FILE *s;
57	char *stdiomode;
58
59	switch (flags)
60	{
61	  case SM_IO_RDONLY:
62		stdiomode = "r";
63		break;
64	  case SM_IO_WRONLY:
65		stdiomode = "w";
66		break;
67	  case SM_IO_APPEND:
68		stdiomode = "a";
69		break;
70	  case SM_IO_APPENDRW:
71		stdiomode = "a+";
72		break;
73#if SM_IO_BINARY != 0
74	  case SM_IO_RDONLY_B:
75		stdiomode = "rb";
76		break;
77	  case SM_IO_WRONLY_B:
78		stdiomode = "wb";
79		break;
80	  case SM_IO_APPEND_B:
81		stdiomode = "ab";
82		break;
83	  case SM_IO_APPENDRW_B:
84		stdiomode = "a+b";
85		break;
86	  case SM_IO_RDWR_B:
87		stdiomode = "r+b";
88		break;
89#endif /* SM_IO_BINARY != 0 */
90	  case SM_IO_RDWR:
91	  default:
92		stdiomode = "r+";
93		break;
94	}
95
96	if ((s = fopen((char *)info, stdiomode)) == NULL)
97		return -1;
98	fp->f_cookie = s;
99	return 0;
100}
101
102/*
103**  SETUP -- assign file type cookie when not already assigned
104**
105**	Parameters:
106**		fp - the file pointer to get the cookie assigned
107**
108**	Return:
109**		none.
110*/
111
112static void
113setup(fp)
114	SM_FILE_T *fp;
115{
116	if (fp->f_cookie == NULL)
117	{
118		switch (fp->f_ival)
119		{
120		  case 0:
121			fp->f_cookie = stdin;
122			break;
123		  case 1:
124			fp->f_cookie = stdout;
125			break;
126		  case 2:
127			fp->f_cookie = stderr;
128			break;
129		  default:
130			sm_abort("fp->f_ival=%d: out of range (0...2)", fp->f_ival);
131			break;
132		}
133	}
134}
135
136/*
137**  SM_STDIOREAD -- read from the file
138**
139**	Parameters:
140**		fp -- the file pointer
141**		buf -- location to place the read data
142**		n - number of bytes to read
143**
144**	Returns:
145**		result from fread().
146*/
147
148ssize_t
149sm_stdioread(fp, buf, n)
150	SM_FILE_T *fp;
151	char *buf;
152	size_t n;
153{
154	register FILE *s;
155
156	if (fp->f_cookie == NULL)
157		setup(fp);
158	s = fp->f_cookie;
159	return fread(buf, 1, n, s);
160}
161
162/*
163**  SM_STDIOWRITE -- write to the file
164**
165**	Parameters:
166**		fp -- the file pointer
167**		buf -- location of data to write
168**		n - number of bytes to write
169**
170**	Returns:
171**		result from fwrite().
172*/
173
174ssize_t
175sm_stdiowrite(fp, buf, n)
176	SM_FILE_T *fp;
177	char const *buf;
178	size_t n;
179{
180	register FILE *s;
181
182	if (fp->f_cookie == NULL)
183		setup(fp);
184	s = fp->f_cookie;
185	return fwrite(buf, 1, n, s);
186}
187
188/*
189**  SM_STDIOSEEK -- set position within file
190**
191**	Parameters:
192**		fp -- the file pointer
193**		offset -- new location based on 'whence'
194**		whence -- indicates "base" for 'offset'
195**
196**	Returns:
197**		result from fseek().
198*/
199
200off_t
201sm_stdioseek(fp, offset, whence)
202	SM_FILE_T *fp;
203	off_t offset;
204	int whence;
205{
206	register FILE *s;
207
208	if (fp->f_cookie == NULL)
209		setup(fp);
210	s = fp->f_cookie;
211	return fseek(s, offset, whence);
212}
213
214/*
215**  SM_STDIOCLOSE -- close the file
216**
217**	Parameters:
218**		fp -- close file pointer
219**
220**	Return:
221**		status from fclose()
222*/
223
224int
225sm_stdioclose(fp)
226	SM_FILE_T *fp;
227{
228	register FILE *s;
229
230	if (fp->f_cookie == NULL)
231		setup(fp);
232	s = fp->f_cookie;
233	return fclose(s);
234}
235
236/*
237**  SM_STDIOSETINFO -- set info for this open file
238**
239**	Parameters:
240**		fp -- the file pointer
241**		what -- type of information setting
242**		valp -- memory location of info to set
243**
244**	Return:
245**		Failure: -1 and sets errno
246**		Success: none (currently).
247*/
248
249/* ARGSUSED2 */
250int
251sm_stdiosetinfo(fp, what, valp)
252	SM_FILE_T *fp;
253	int what;
254	void *valp;
255{
256	switch (what)
257	{
258	  case SM_IO_WHAT_MODE:
259	  default:
260		errno = EINVAL;
261		return -1;
262	}
263}
264
265/*
266**  SM_STDIOGETINFO -- get info for this open file
267**
268**	Parameters:
269**		fp -- the file pointer
270**		what -- type of information request
271**		valp -- memory location to place info
272**
273**	Return:
274**		Failure: -1 and sets errno
275**		Success: none (currently).
276*/
277
278/* ARGSUSED2 */
279int
280sm_stdiogetinfo(fp, what, valp)
281	SM_FILE_T *fp;
282	int what;
283	void *valp;
284{
285	switch (what)
286	{
287	  case SM_IO_WHAT_SIZE:
288	  {
289		  int fd;
290		  struct stat st;
291
292		  if (fp->f_cookie == NULL)
293			  setup(fp);
294		  fd = fileno((FILE *) fp->f_cookie);
295		  if (fd < 0)
296			  return -1;
297		  if (fstat(fd, &st) == 0)
298			  return st.st_size;
299		  else
300			  return -1;
301	  }
302
303	  case SM_IO_WHAT_MODE:
304	  default:
305		errno = EINVAL;
306		return -1;
307	}
308}
309
310/*
311**  SM_IO_STDIOOPEN -- create an SM_FILE which interfaces to a stdio FILE
312**
313**	Parameters:
314**		stream -- an open stdio stream, as returned by fopen()
315**		mode -- the mode argument to fopen() which describes stream
316**
317**	Return:
318**		On success, return a pointer to an SM_FILE object which
319**		can be used for reading and writing 'stream'.
320**		Abort if mode is gibberish or stream is bad.
321**		Raise an exception if we can't allocate memory.
322*/
323
324SM_FILE_T *
325sm_io_stdioopen(stream, mode)
326	FILE *stream;
327	char *mode;
328{
329	int fd;
330	bool r, w;
331	int ioflags;
332	SM_FILE_T *fp;
333
334	fd = fileno(stream);
335	SM_REQUIRE(fd >= 0);
336
337	r = w = false;
338	switch (mode[0])
339	{
340	  case 'r':
341		r = true;
342		break;
343	  case 'w':
344	  case 'a':
345		w = true;
346		break;
347	  default:
348		sm_abort("sm_io_stdioopen: mode '%s' is bad", mode);
349	}
350	if (strchr(&mode[1], '+') != NULL)
351		r = w = true;
352	if (r && w)
353		ioflags = SMRW;
354	else if (r)
355		ioflags = SMRD;
356	else
357		ioflags = SMWR;
358
359	fp = sm_fp(SmFtRealStdio, ioflags, NULL);
360	fp->f_file = fd;
361	fp->f_cookie = stream;
362	return fp;
363}
364