Merge from vendor branch SENDMAIL:
[dragonfly.git] / contrib / sendmail-8.13.4 / libsm / findfp.c
1 /*
2  * Copyright (c) 2000-2002 Sendmail, Inc. and its suppliers.
3  *      All rights reserved.
4  * Copyright (c) 1990, 1993
5  *      The Regents of the University of California.  All rights reserved.
6  *
7  * This code is derived from software contributed to Berkeley by
8  * Chris Torek.
9  *
10  * By using this file, you agree to the terms and conditions set
11  * forth in the LICENSE file which can be found at the top level of
12  * the sendmail distribution.
13  */
14
15 #include <sm/gen.h>
16 SM_RCSID("@(#)$Id: findfp.c,v 1.66 2002/02/20 02:40:24 ca Exp $")
17 #include <stdlib.h>
18 #include <unistd.h>
19 #include <sys/param.h>
20 #include <errno.h>
21 #include <string.h>
22 #include <syslog.h>
23 #include <sm/io.h>
24 #include <sm/assert.h>
25 #include <sm/heap.h>
26 #include <sm/string.h>
27 #include <sm/conf.h>
28 #include "local.h"
29 #include "glue.h"
30
31 bool    Sm_IO_DidInit;  /* IO system has been initialized? */
32
33 const char SmFileMagic[] = "sm_file";
34
35 /* An open type to map to fopen()-like behavior */
36 SM_FILE_T SmFtStdio_def =
37     {SmFileMagic, 0, 0, 0, (SMRW|SMFBF), -1, {0, 0}, 0, 0, 0,
38         sm_stdclose, sm_stdread, sm_stdseek, sm_stdwrite,
39         sm_stdopen, sm_stdsetinfo, sm_stdgetinfo, SM_TIME_FOREVER,
40         SM_TIME_BLOCK, "stdio" };
41
42 /* An open type to map to fdopen()-like behavior */
43 SM_FILE_T SmFtStdiofd_def =
44     {SmFileMagic, 0, 0, 0, (SMRW|SMFBF), -1, {0, 0}, 0, 0, 0,
45         sm_stdclose, sm_stdread, sm_stdseek, sm_stdwrite,
46         sm_stdfdopen, sm_stdsetinfo, sm_stdgetinfo, SM_TIME_FOREVER,
47         SM_TIME_BLOCK, "stdiofd" };
48
49 /* A string file type */
50 SM_FILE_T SmFtString_def =
51     {SmFileMagic, 0, 0, 0, (SMRW|SMNBF), -1, {0, 0}, 0, 0, 0,
52         sm_strclose, sm_strread, sm_strseek, sm_strwrite,
53         sm_stropen, sm_strsetinfo, sm_strgetinfo, SM_TIME_FOREVER,
54         SM_TIME_BLOCK, "string" };
55
56 #if 0
57 /* A file type for syslog communications */
58 SM_FILE_T SmFtSyslog_def =
59     {SmFileMagic, 0, 0, 0, (SMRW|SMNBF), -1, {0, 0}, 0, 0, 0,
60         sm_syslogclose, sm_syslogread, sm_syslogseek, sm_syslogwrite,
61         sm_syslogopen, sm_syslogsetinfo, sm_sysloggetinfo, SM_TIME_FOREVER,
62         SM_TIME_BLOCK, "syslog" };
63 #endif /* 0 */
64
65 #define NDYNAMIC 10             /* add ten more whenever necessary */
66
67 #define smio(flags, file, name)                                         \
68     {SmFileMagic, 0, 0, 0, flags, file, {0}, 0, SmIoF+file, 0,          \
69         sm_stdclose, sm_stdread, sm_stdseek, sm_stdwrite,               \
70         sm_stdopen, sm_stdsetinfo, sm_stdgetinfo, SM_TIME_FOREVER,      \
71         SM_TIME_BLOCK, name}
72
73 /* sm_magic p r w flags file bf lbfsize cookie ival */
74 #define smstd(flags, file, name)                                        \
75     {SmFileMagic, 0, 0, 0, flags, -1, {0}, 0, 0, file,                  \
76         sm_stdioclose, sm_stdioread, sm_stdioseek, sm_stdiowrite,       \
77         sm_stdioopen, sm_stdiosetinfo, sm_stdiogetinfo, SM_TIME_FOREVER,\
78         SM_TIME_BLOCK, name}
79
80 /* A file type for interfacing to stdio FILE* streams. */
81 SM_FILE_T SmFtRealStdio_def = smstd(SMRW|SMNBF, -1, "realstdio");
82
83                                 /* the usual - (stdin + stdout + stderr) */
84 static SM_FILE_T usual[SM_IO_OPEN_MAX - 3];
85 static struct sm_glue smuglue = { 0, SM_IO_OPEN_MAX - 3, usual };
86
87 /* List of builtin automagically already open file pointers */
88 SM_FILE_T SmIoF[6] =
89 {
90         smio(SMRD|SMLBF, SMIOIN_FILENO, "smioin"),      /* smioin */
91         smio(SMWR|SMLBF, SMIOOUT_FILENO, "smioout"),    /* smioout */
92         smio(SMWR|SMNBF, SMIOERR_FILENO, "smioerr"),    /* smioerr */
93         smstd(SMRD|SMNBF, SMIOIN_FILENO, "smiostdin"),  /* smiostdin */
94         smstd(SMWR|SMNBF, SMIOOUT_FILENO, "smiostdout"),/* smiostdout */
95         smstd(SMWR|SMNBF, SMIOERR_FILENO, "smiostderr") /* smiostderr */
96 };
97
98 /* Structure containing list of currently open file pointers */
99 struct sm_glue smglue = { &smuglue, 3, SmIoF };
100
101 /*
102 **  SM_MOREGLUE -- adds more space for open file pointers
103 **
104 **      Parameters:
105 **              n -- number of new spaces for file pointers
106 **
107 **      Returns:
108 **              Raises an exception if no more memory.
109 **              Otherwise, returns a pointer to new spaces.
110 */
111
112 static struct sm_glue *sm_moreglue_x __P((int));
113 static SM_FILE_T empty;
114
115 static struct sm_glue *
116 sm_moreglue_x(n)
117         register int n;
118 {
119         register struct sm_glue *g;
120         register SM_FILE_T *p;
121
122         g = (struct sm_glue *) sm_pmalloc_x(sizeof(*g) + SM_ALIGN_BITS +
123                                             n * sizeof(SM_FILE_T));
124         p = (SM_FILE_T *) SM_ALIGN(g + 1);
125         g->gl_next = NULL;
126         g->gl_niobs = n;
127         g->gl_iobs = p;
128         while (--n >= 0)
129                 *p++ = empty;
130         return g;
131 }
132
133 /*
134 **  SM_FP -- allocate and initialize an SM_FILE structure
135 **
136 **      Parameters:
137 **              t -- file type requested to be opened.
138 **              flags -- control flags for file type behavior
139 **              oldfp -- file pointer to reuse if available (optional)
140 **
141 **      Returns:
142 **              Raises exception on memory exhaustion.
143 **              Aborts if type is invalid.
144 **              Otherwise, returns file pointer for requested file type.
145 */
146
147 SM_FILE_T *
148 sm_fp(t, flags, oldfp)
149         const SM_FILE_T *t;
150         const int flags;
151         SM_FILE_T *oldfp;
152 {
153         register SM_FILE_T *fp;
154         register int n;
155         register struct sm_glue *g;
156
157         SM_REQUIRE(t->f_open && t->f_close && (t->f_read || t->f_write));
158
159         if (!Sm_IO_DidInit)
160                 sm_init();
161
162         if (oldfp != NULL)
163         {
164                 fp = oldfp;
165                 goto found; /* for opening reusing an 'fp' */
166         }
167
168         for (g = &smglue;; g = g->gl_next)
169         {
170                 for (fp = g->gl_iobs, n = g->gl_niobs; --n >= 0; fp++)
171                         if (fp->sm_magic == NULL)
172                                 goto found;
173                 if (g->gl_next == NULL)
174                         g->gl_next = sm_moreglue_x(NDYNAMIC);
175         }
176 found:
177         fp->sm_magic = SmFileMagic; /* 'fp' now valid and in-use */
178         fp->f_p = NULL;         /* no current pointer */
179         fp->f_w = 0;            /* nothing to write */
180         fp->f_r = 0;            /* nothing to read */
181         fp->f_flags = flags;
182         fp->f_file = -1;                /* no file */
183         fp->f_bf.smb_base = NULL;       /* no buffer */
184         fp->f_bf.smb_size = 0;  /* no buffer size with no buffer */
185         fp->f_lbfsize = 0;      /* not line buffered */
186         fp->f_flushfp = NULL;   /* no associated flush file */
187
188         fp->f_cookie = fp;      /* default: *open* overrides cookie setting */
189         fp->f_close = t->f_close;       /* assign close function */
190         fp->f_read = t->f_read;         /* assign read function */
191         fp->f_seek = t->f_seek;         /* assign seek function */
192         fp->f_write = t->f_write;       /* assign write function */
193         fp->f_open = t->f_open;         /* assign open function */
194         fp->f_setinfo = t->f_setinfo;   /* assign setinfo function */
195         fp->f_getinfo = t->f_getinfo;   /* assign getinfo function */
196         fp->f_type = t->f_type;         /* file type */
197
198         fp->f_ub.smb_base = NULL;       /* no ungetc buffer */
199         fp->f_ub.smb_size = 0;          /* no size for no ungetc buffer */
200
201         if (fp->f_timeout == SM_TIME_DEFAULT)
202                 fp->f_timeout = SM_TIME_FOREVER;
203         else
204                 fp->f_timeout = t->f_timeout; /* traditional behavior */
205         fp->f_timeoutstate = SM_TIME_BLOCK; /* by default */
206
207         return fp;
208 }
209
210 /*
211 **  SM_CLEANUP -- cleanup function when exit called.
212 **
213 **      This function is registered via atexit().
214 **
215 **      Parameters:
216 **              none
217 **
218 **      Returns:
219 **              nothing.
220 **
221 **      Side Effects:
222 **              flushes open files before they are forced closed
223 */
224
225 void
226 sm_cleanup()
227 {
228         int timeout = SM_TIME_DEFAULT;
229
230         (void) sm_fwalk(sm_flush, &timeout); /* `cheating' */
231 }
232
233 /*
234 **  SM_INIT -- called whenever sm_io's internal variables must be set up.
235 **
236 **      Parameters:
237 **              none
238 **
239 **      Returns:
240 **              none
241 **
242 **      Side Effects:
243 **              Registers sm_cleanup() using atexit().
244 */
245
246 void
247 sm_init()
248 {
249         if (Sm_IO_DidInit)      /* paranoia */
250                 return;
251
252         /* more paranoia: initialize pointers in a static variable */
253         empty.f_type = NULL;
254         empty.sm_magic = NULL;
255
256         /* make sure we clean up on exit */
257         atexit(sm_cleanup);             /* conservative */
258         Sm_IO_DidInit = true;
259 }
260
261 /*
262 **  SM_IO_SETINFO -- change info for an open file type (fp)
263 **
264 **      The generic SM_IO_WHAT_VECTORS is auto supplied for all file types.
265 **      If the request is to set info other than SM_IO_WHAT_VECTORS then
266 **      the request is passed on to the file type's specific setinfo vector.
267 **      WARNING: this is working on an active/open file type.
268 **
269 **      Parameters:
270 **              fp -- file to make the setting on
271 **              what -- type of information to set
272 **              valp -- structure to obtain info from
273 **
274 **      Returns:
275 **              0 on success
276 **              -1 on error and sets errno:
277 **                      - when what != SM_IO_WHAT_VECTORS and setinfo vector
278 **                              not set
279 **                      - when vectored setinfo returns -1
280 */
281
282 int
283 sm_io_setinfo(fp, what, valp)
284         SM_FILE_T *fp;
285         int what;
286         void *valp;
287 {
288         SM_FILE_T *v = (SM_FILE_T *) valp;
289
290         SM_REQUIRE_ISA(fp, SmFileMagic);
291         switch (what)
292         {
293           case SM_IO_WHAT_VECTORS:
294
295                 /*
296                 **  This is the "generic" available for all.
297                 **  This allows the function vectors to be replaced
298                 **  while the file type is active.
299                 */
300
301                 fp->f_close = v->f_close;
302                 fp->f_read = v->f_read;
303                 fp->f_seek = v->f_seek;
304                 fp->f_write = v->f_write;
305                 fp->f_open = v->f_open;
306                 fp->f_setinfo = v->f_setinfo;
307                 fp->f_getinfo = v->f_getinfo;
308                 sm_free(fp->f_type);
309                 fp->f_type = sm_strdup_x(v->f_type);
310                 return 0;
311           case SM_IO_WHAT_TIMEOUT:
312                 fp->f_timeout = *((int *)valp);
313                 return 0;
314         }
315
316         /* Otherwise the vector will check it out */
317         if (fp->f_setinfo == NULL)
318         {
319                 errno = EINVAL;
320                 return -1;
321         }
322         else
323                 return (*fp->f_setinfo)(fp, what, valp);
324 }
325
326 /*
327 **  SM_IO_GETINFO -- get information for an active file type (fp)
328 **
329 **  This function supplies for all file types the answers for the
330 **              three requests SM_IO_WHAT_VECTORS, SM_IO_WHAT_TYPE and
331 **              SM_IO_WHAT_ISTYPE. Other requests are handled by the getinfo
332 **              vector if available for the open file type.
333 **      SM_IO_WHAT_VECTORS returns information for the file pointer vectors.
334 **      SM_IO_WHAT_TYPE returns the type identifier for the file pointer
335 **      SM_IO_WHAT_ISTYPE returns >0 if the passed in type matches the
336 **              file pointer's type.
337 **      SM_IO_IS_READABLE returns 1 if there is data available for reading,
338 **              0 otherwise.
339 **
340 **      Parameters:
341 **              fp -- file pointer for active file type
342 **              what -- type of information request
343 **              valp -- structure to place obtained info into
344 **
345 **      Returns:
346 **              -1 on error and sets errno:
347 **                      - when valp==NULL and request expects otherwise
348 **                      - when request is not SM_IO_WHAT_VECTORS and not
349 **                              SM_IO_WHAT_TYPE and not SM_IO_WHAT_ISTYPE
350 **                              and getinfo vector is NULL
351 **                      - when getinfo type vector returns -1
352 **              >=0 on success
353 */
354
355 int
356 sm_io_getinfo(fp, what, valp)
357         SM_FILE_T *fp;
358         int what;
359         void *valp;
360 {
361         SM_FILE_T *v = (SM_FILE_T *) valp;
362
363         SM_REQUIRE_ISA(fp, SmFileMagic);
364
365         switch (what)
366         {
367           case SM_IO_WHAT_VECTORS:
368
369                 /* This is the "generic" available for all */
370                 v->f_close = fp->f_close;
371                 v->f_read = fp->f_read;
372                 v->f_seek = fp->f_seek;
373                 v->f_write = fp->f_write;
374                 v->f_open = fp->f_open;
375                 v->f_setinfo = fp->f_setinfo;
376                 v->f_getinfo = fp->f_getinfo;
377                 v->f_type = fp->f_type;
378                 return 0;
379
380           case SM_IO_WHAT_TYPE:
381                 if (valp == NULL)
382                 {
383                         errno = EINVAL;
384                         return -1;
385                 }
386                 valp = sm_strdup_x(fp->f_type);
387                 return 0;
388
389           case SM_IO_WHAT_ISTYPE:
390                 if (valp == NULL)
391                 {
392                         errno = EINVAL;
393                         return -1;
394                 }
395                 return strcmp(fp->f_type, valp) == 0;
396
397           case SM_IO_IS_READABLE:
398
399                 /* if there is data in the buffer, it must be readable */
400                 if (fp->f_r > 0)
401                         return 1;
402
403                 /* otherwise query the underlying file */
404                 break;
405
406            case SM_IO_WHAT_TIMEOUT:
407                 *((int *) valp) = fp->f_timeout;
408                 return 0;
409
410           case SM_IO_WHAT_FD:
411                 if (fp->f_file > -1)
412                         return fp->f_file;
413
414                 /* try the file type specific getinfo to see if it knows */
415                 break;
416         }
417
418         /* Otherwise the vector will check it out */
419         if (fp->f_getinfo == NULL)
420         {
421                 errno = EINVAL;
422                 return -1;
423         }
424         return (*fp->f_getinfo)(fp, what, valp);
425 }