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