* Update Sendmail to version 8.12.10
[dragonfly.git] / contrib / sendmail / libsm / smstdio.c
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 }