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