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
sm_stdioopen(fp,info,flags,rpool)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
setup(fp)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
sm_stdioread(fp,buf,n)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
sm_stdiowrite(fp,buf,n)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
sm_stdioseek(fp,offset,whence)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
sm_stdioclose(fp)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
sm_stdiosetinfo(fp,what,valp)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
sm_stdiogetinfo(fp,what,valp)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 *
sm_io_stdioopen(stream,mode)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