xref: /freebsd/contrib/sendmail/libsm/smstdio.c (revision ae83180158c4c937f170e31eff311b18c0286a93)
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>
11 SM_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 */
47 int
48 sm_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 
93 static void
94 setup(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 
129 ssize_t
130 sm_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 
155 ssize_t
156 sm_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 
181 off_t
182 sm_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 
205 int
206 sm_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 */
231 int
232 sm_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 */
260 int
261 sm_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 
305 SM_FILE_T *
306 sm_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