xref: /freebsd/contrib/sendmail/libsm/smstdio.c (revision c98323078dede7579020518ec84cdcb478e5c142)
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.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 */
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 #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 
110 static void
111 setup(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 
146 ssize_t
147 sm_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 
172 ssize_t
173 sm_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 
198 off_t
199 sm_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 
222 int
223 sm_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 */
248 int
249 sm_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 */
277 int
278 sm_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 
322 SM_FILE_T *
323 sm_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