smstdio.c revision 98121
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 2002/02/23 20:18:36 gshapiro 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	  case SM_IO_RDWR:
72	  default:
73		stdiomode = "r+";
74		break;
75	}
76
77	if ((s = fopen((char *)info, stdiomode)) == NULL)
78		return -1;
79	fp->f_cookie = s;
80	return 0;
81}
82
83/*
84**  SETUP -- assign file type cookie when not already assigned
85**
86**	Parameters:
87**		fp - the file pointer to get the cookie assigned
88**
89**	Return:
90**		none.
91*/
92
93static void
94setup(fp)
95	SM_FILE_T *fp;
96{
97	if (fp->f_cookie == NULL)
98	{
99		switch (fp->f_ival)
100		{
101		  case 0:
102			fp->f_cookie = stdin;
103			break;
104		  case 1:
105			fp->f_cookie = stdout;
106			break;
107		  case 2:
108			fp->f_cookie = stderr;
109			break;
110		  default:
111			sm_abort("fp->f_ival=%d: out of range (0...2)", fp->f_ival);
112			break;
113		}
114	}
115}
116
117/*
118**  SM_STDIOREAD -- read from the file
119**
120**	Parameters:
121**		fp -- the file pointer
122**		buf -- location to place the read data
123**		n - number of bytes to read
124**
125**	Returns:
126**		result from fread().
127*/
128
129ssize_t
130sm_stdioread(fp, buf, n)
131	SM_FILE_T *fp;
132	char *buf;
133	size_t n;
134{
135	register FILE *s;
136
137	if (fp->f_cookie == NULL)
138		setup(fp);
139	s = fp->f_cookie;
140	return fread(buf, 1, n, s);
141}
142
143/*
144**  SM_STDIOWRITE -- write to the file
145**
146**	Parameters:
147**		fp -- the file pointer
148**		buf -- location of data to write
149**		n - number of bytes to write
150**
151**	Returns:
152**		result from fwrite().
153*/
154
155ssize_t
156sm_stdiowrite(fp, buf, n)
157	SM_FILE_T *fp;
158	char const *buf;
159	size_t n;
160{
161	register FILE *s;
162
163	if (fp->f_cookie == NULL)
164		setup(fp);
165	s = fp->f_cookie;
166	return fwrite(buf, 1, n, s);
167}
168
169/*
170**  SM_STDIOSEEK -- set position within file
171**
172**	Parameters:
173**		fp -- the file pointer
174**		offset -- new location based on 'whence'
175**		whence -- indicates "base" for 'offset'
176**
177**	Returns:
178**		result from fseek().
179*/
180
181off_t
182sm_stdioseek(fp, offset, whence)
183	SM_FILE_T *fp;
184	off_t offset;
185	int whence;
186{
187	register FILE *s;
188
189	if (fp->f_cookie == NULL)
190		setup(fp);
191	s = fp->f_cookie;
192	return fseek(s, offset, whence);
193}
194
195/*
196**  SM_STDIOCLOSE -- close the file
197**
198**	Parameters:
199**		fp -- close file pointer
200**
201**	Return:
202**		status from fclose()
203*/
204
205int
206sm_stdioclose(fp)
207	SM_FILE_T *fp;
208{
209	register FILE *s;
210
211	if (fp->f_cookie == NULL)
212		setup(fp);
213	s = fp->f_cookie;
214	return fclose(s);
215}
216
217/*
218**  SM_STDIOSETINFO -- set info for this open file
219**
220**	Parameters:
221**		fp -- the file pointer
222**		what -- type of information setting
223**		valp -- memory location of info to set
224**
225**	Return:
226**		Failure: -1 and sets errno
227**		Success: none (currently).
228*/
229
230/* ARGSUSED2 */
231int
232sm_stdiosetinfo(fp, what, valp)
233	SM_FILE_T *fp;
234	int what;
235	void *valp;
236{
237	switch (what)
238	{
239	  case SM_IO_WHAT_MODE:
240	  default:
241		errno = EINVAL;
242		return -1;
243	}
244}
245
246/*
247**  SM_STDIOGETINFO -- get info for this open file
248**
249**	Parameters:
250**		fp -- the file pointer
251**		what -- type of information request
252**		valp -- memory location to place info
253**
254**	Return:
255**		Failure: -1 and sets errno
256**		Success: none (currently).
257*/
258
259/* ARGSUSED2 */
260int
261sm_stdiogetinfo(fp, what, valp)
262	SM_FILE_T *fp;
263	int what;
264	void *valp;
265{
266	switch (what)
267	{
268	  case SM_IO_WHAT_SIZE:
269	  {
270		  int fd;
271		  struct stat st;
272
273		  if (fp->f_cookie == NULL)
274			  setup(fp);
275		  fd = fileno((FILE *) fp->f_cookie);
276		  if (fd < 0)
277			  return -1;
278		  if (fstat(fd, &st) == 0)
279			  return st.st_size;
280		  else
281			  return -1;
282	  }
283
284	  case SM_IO_WHAT_MODE:
285	  default:
286		errno = EINVAL;
287		return -1;
288	}
289}
290
291/*
292**  SM_IO_STDIOOPEN -- create an SM_FILE which interfaces to a stdio FILE
293**
294**	Parameters:
295**		stream -- an open stdio stream, as returned by fopen()
296**		mode -- the mode argument to fopen() which describes stream
297**
298**	Return:
299**		On success, return a pointer to an SM_FILE object which
300**		can be used for reading and writing 'stream'.
301**		Abort if mode is gibberish or stream is bad.
302**		Raise an exception if we can't allocate memory.
303*/
304
305SM_FILE_T *
306sm_io_stdioopen(stream, mode)
307	FILE *stream;
308	char *mode;
309{
310	int fd;
311	bool r, w;
312	int ioflags;
313	SM_FILE_T *fp;
314
315	fd = fileno(stream);
316	SM_REQUIRE(fd >= 0);
317
318	r = w = false;
319	switch (mode[0])
320	{
321	  case 'r':
322		r = true;
323		break;
324	  case 'w':
325	  case 'a':
326		w = true;
327		break;
328	  default:
329		sm_abort("sm_io_stdioopen: mode '%s' is bad", mode);
330	}
331	if (strchr(&mode[1], '+') != NULL)
332		r = w = true;
333	if (r && w)
334		ioflags = SMRW;
335	else if (r)
336		ioflags = SMRD;
337	else
338		ioflags = SMWR;
339
340	fp = sm_fp(SmFtRealStdio, ioflags, NULL);
341	fp->f_file = fd;
342	fp->f_cookie = stream;
343	return fp;
344}
345