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