Initial import from FreeBSD RELENG_4:
[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 2002/02/23 20:18:36 gshapiro 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           case SM_IO_RDWR:
72           default:
73                 stdiomode = "r+";
74                 break;
75         }
76
77         if ((s = fopen((char *)info, stdiomode)) == NULL)
78                 return -1;
79         fp->f_cookie = s;
80         return 0;
81 }
82
83 /*
84 **  SETUP -- assign file type cookie when not already assigned
85 **
86 **      Parameters:
87 **              fp - the file pointer to get the cookie assigned
88 **
89 **      Return:
90 **              none.
91 */
92
93 static void
94 setup(fp)
95         SM_FILE_T *fp;
96 {
97         if (fp->f_cookie == NULL)
98         {
99                 switch (fp->f_ival)
100                 {
101                   case 0:
102                         fp->f_cookie = stdin;
103                         break;
104                   case 1:
105                         fp->f_cookie = stdout;
106                         break;
107                   case 2:
108                         fp->f_cookie = stderr;
109                         break;
110                   default:
111                         sm_abort("fp->f_ival=%d: out of range (0...2)", fp->f_ival);
112                         break;
113                 }
114         }
115 }
116
117 /*
118 **  SM_STDIOREAD -- read from the file
119 **
120 **      Parameters:
121 **              fp -- the file pointer
122 **              buf -- location to place the read data
123 **              n - number of bytes to read
124 **
125 **      Returns:
126 **              result from fread().
127 */
128
129 ssize_t
130 sm_stdioread(fp, buf, n)
131         SM_FILE_T *fp;
132         char *buf;
133         size_t n;
134 {
135         register FILE *s;
136
137         if (fp->f_cookie == NULL)
138                 setup(fp);
139         s = fp->f_cookie;
140         return fread(buf, 1, n, s);
141 }
142
143 /*
144 **  SM_STDIOWRITE -- write to the file
145 **
146 **      Parameters:
147 **              fp -- the file pointer
148 **              buf -- location of data to write
149 **              n - number of bytes to write
150 **
151 **      Returns:
152 **              result from fwrite().
153 */
154
155 ssize_t
156 sm_stdiowrite(fp, buf, n)
157         SM_FILE_T *fp;
158         char const *buf;
159         size_t n;
160 {
161         register FILE *s;
162
163         if (fp->f_cookie == NULL)
164                 setup(fp);
165         s = fp->f_cookie;
166         return fwrite(buf, 1, n, s);
167 }
168
169 /*
170 **  SM_STDIOSEEK -- set position within file
171 **
172 **      Parameters:
173 **              fp -- the file pointer
174 **              offset -- new location based on 'whence'
175 **              whence -- indicates "base" for 'offset'
176 **
177 **      Returns:
178 **              result from fseek().
179 */
180
181 off_t
182 sm_stdioseek(fp, offset, whence)
183         SM_FILE_T *fp;
184         off_t offset;
185         int whence;
186 {
187         register FILE *s;
188
189         if (fp->f_cookie == NULL)
190                 setup(fp);
191         s = fp->f_cookie;
192         return fseek(s, offset, whence);
193 }
194
195 /*
196 **  SM_STDIOCLOSE -- close the file
197 **
198 **      Parameters:
199 **              fp -- close file pointer
200 **
201 **      Return:
202 **              status from fclose()
203 */
204
205 int
206 sm_stdioclose(fp)
207         SM_FILE_T *fp;
208 {
209         register FILE *s;
210
211         if (fp->f_cookie == NULL)
212                 setup(fp);
213         s = fp->f_cookie;
214         return fclose(s);
215 }
216
217 /*
218 **  SM_STDIOSETINFO -- set info for this open file
219 **
220 **      Parameters:
221 **              fp -- the file pointer
222 **              what -- type of information setting
223 **              valp -- memory location of info to set
224 **
225 **      Return:
226 **              Failure: -1 and sets errno
227 **              Success: none (currently).
228 */
229
230 /* ARGSUSED2 */
231 int
232 sm_stdiosetinfo(fp, what, valp)
233         SM_FILE_T *fp;
234         int what;
235         void *valp;
236 {
237         switch (what)
238         {
239           case SM_IO_WHAT_MODE:
240           default:
241                 errno = EINVAL;
242                 return -1;
243         }
244 }
245
246 /*
247 **  SM_STDIOGETINFO -- get info for this open file
248 **
249 **      Parameters:
250 **              fp -- the file pointer
251 **              what -- type of information request
252 **              valp -- memory location to place info
253 **
254 **      Return:
255 **              Failure: -1 and sets errno
256 **              Success: none (currently).
257 */
258
259 /* ARGSUSED2 */
260 int
261 sm_stdiogetinfo(fp, what, valp)
262         SM_FILE_T *fp;
263         int what;
264         void *valp;
265 {
266         switch (what)
267         {
268           case SM_IO_WHAT_SIZE:
269           {
270                   int fd;
271                   struct stat st;
272
273                   if (fp->f_cookie == NULL)
274                           setup(fp);
275                   fd = fileno((FILE *) fp->f_cookie);
276                   if (fd < 0)
277                           return -1;
278                   if (fstat(fd, &st) == 0)
279                           return st.st_size;
280                   else
281                           return -1;
282           }
283
284           case SM_IO_WHAT_MODE:
285           default:
286                 errno = EINVAL;
287                 return -1;
288         }
289 }
290
291 /*
292 **  SM_IO_STDIOOPEN -- create an SM_FILE which interfaces to a stdio FILE
293 **
294 **      Parameters:
295 **              stream -- an open stdio stream, as returned by fopen()
296 **              mode -- the mode argument to fopen() which describes stream
297 **
298 **      Return:
299 **              On success, return a pointer to an SM_FILE object which
300 **              can be used for reading and writing 'stream'.
301 **              Abort if mode is gibberish or stream is bad.
302 **              Raise an exception if we can't allocate memory.
303 */
304
305 SM_FILE_T *
306 sm_io_stdioopen(stream, mode)
307         FILE *stream;
308         char *mode;
309 {
310         int fd;
311         bool r, w;
312         int ioflags;
313         SM_FILE_T *fp;
314
315         fd = fileno(stream);
316         SM_REQUIRE(fd >= 0);
317
318         r = w = false;
319         switch (mode[0])
320         {
321           case 'r':
322                 r = true;
323                 break;
324           case 'w':
325           case 'a':
326                 w = true;
327                 break;
328           default:
329                 sm_abort("sm_io_stdioopen: mode '%s' is bad", mode);
330         }
331         if (strchr(&mode[1], '+') != NULL)
332                 r = w = true;
333         if (r && w)
334                 ioflags = SMRW;
335         else if (r)
336                 ioflags = SMRD;
337         else
338                 ioflags = SMWR;
339
340         fp = sm_fp(SmFtRealStdio, ioflags, NULL);
341         fp->f_file = fd;
342         fp->f_cookie = stream;
343         return fp;
344 }