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