xref: /freebsd/contrib/sendmail/libsm/findfp.c (revision 5b587aff2db911bb380d5f7d0d507423c3441152)
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.62 2002/01/11 16:33:03 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) + ALIGNBYTES +
123 					    n * sizeof(SM_FILE_T));
124 	p = (SM_FILE_T *) 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 	fp->f_self = fp;		/* self reference for future use */
198 
199 	fp->f_ub.smb_base = NULL;	/* no ungetc buffer */
200 	fp->f_ub.smb_size = 0;		/* no size for no ungetc buffer */
201 
202 	fp->f_lb.smb_base = NULL;	/* no line buffer */
203 	fp->f_lb.smb_size = 0;		/* no size for no line buffer */
204 	if (fp->f_timeout == SM_TIME_DEFAULT)
205 		fp->f_timeout = SM_TIME_FOREVER;
206 	else
207 		fp->f_timeout = t->f_timeout; /* traditional behavior */
208 	fp->f_timeoutstate = SM_TIME_BLOCK; /* by default */
209 
210 	return fp;
211 }
212 
213 /*
214 **  SM_CLEANUP -- cleanup function when exit called.
215 **
216 **	This function is registered via atexit().
217 **
218 **	Parameters:
219 **		none
220 **
221 **	Returns:
222 **		nothing.
223 **
224 **	Side Effects:
225 **		flushes open files before they are forced closed
226 */
227 
228 void
229 sm_cleanup()
230 {
231 	int timeout = SM_TIME_DEFAULT;
232 
233 	(void) sm_fwalk(sm_flush, &timeout); /* `cheating' */
234 }
235 
236 /*
237 **  SM_INIT -- called whenever sm_io's internal variables must be set up.
238 **
239 **	Parameters:
240 **		none
241 **
242 **	Returns:
243 **		none
244 **
245 **	Side Effects:
246 **		Registers sm_cleanup() using atexit().
247 */
248 
249 void
250 sm_init()
251 {
252 	if (Sm_IO_DidInit)	/* paranoia */
253 		return;
254 
255 	/* more paranoia: initialize pointers in a static variable */
256 	empty.f_type = NULL;
257 	empty.sm_magic = NULL;
258 
259 	/* make sure we clean up on exit */
260 	atexit(sm_cleanup);		/* conservative */
261 	Sm_IO_DidInit = true;
262 }
263 
264 /*
265 **  SM_IO_SETINFO -- change info for an open file type (fp)
266 **
267 **	The generic SM_IO_WHAT_VECTORS is auto supplied for all file types.
268 **	If the request is to set info other than SM_IO_WHAT_VECTORS then
269 **	the request is passed on to the file type's specific setinfo vector.
270 **	WARNING: this is working on an active/open file type.
271 **
272 **	Parameters:
273 **		fp -- file to make the setting on
274 **		what -- type of information to set
275 **		valp -- structure to obtain info from
276 **
277 **	Returns:
278 **		0 on success
279 **		-1 on error and sets errno:
280 **			- when what != SM_IO_WHAT_VECTORS and setinfo vector
281 **				not set
282 **			- when vectored setinfo returns -1
283 */
284 
285 int
286 sm_io_setinfo(fp, what, valp)
287 	SM_FILE_T *fp;
288 	int what;
289 	void *valp;
290 {
291 	SM_FILE_T *v = (SM_FILE_T *) valp;
292 
293 	SM_REQUIRE_ISA(fp, SmFileMagic);
294 	switch (what)
295 	{
296 	  case SM_IO_WHAT_VECTORS:
297 
298 		/*
299 		**  This is the "generic" available for all.
300 		**  This allows the function vectors to be replaced
301 		**  while the file type is active.
302 		*/
303 
304 		fp->f_close = v->f_close;
305 		fp->f_read = v->f_read;
306 		fp->f_seek = v->f_seek;
307 		fp->f_write = v->f_write;
308 		fp->f_open = v->f_open;
309 		fp->f_setinfo = v->f_setinfo;
310 		fp->f_getinfo = v->f_getinfo;
311 		sm_free(fp->f_type);
312 		fp->f_type = sm_strdup_x(v->f_type);
313 		return 0;
314 	  case SM_IO_WHAT_TIMEOUT:
315 		fp->f_timeout = *((int *)valp);
316 		return 0;
317 	}
318 
319 	/* Otherwise the vector will check it out */
320 	if (fp->f_setinfo == NULL)
321 	{
322 		errno = EINVAL;
323 		return -1;
324 	}
325 	else
326 		return (*fp->f_setinfo)(fp, what, valp);
327 }
328 
329 /*
330 **  SM_IO_GETINFO -- get information for an active file type (fp)
331 **
332 **  This function supplies for all file types the answers for the
333 **		three requests SM_IO_WHAT_VECTORS, SM_IO_WHAT_TYPE and
334 **		SM_IO_WHAT_ISTYPE. Other requests are handled by the getinfo
335 **		vector if available for the open file type.
336 **	SM_IO_WHAT_VECTORS returns information for the file pointer vectors.
337 **	SM_IO_WHAT_TYPE returns the type identifier for the file pointer
338 **	SM_IO_WHAT_ISTYPE returns >0 if the passed in type matches the
339 **		file pointer's type.
340 **	SM_IO_IS_READABLE returns 1 if there is data available for reading,
341 **		0 otherwise.
342 **
343 **	Parameters:
344 **		fp -- file pointer for active file type
345 **		what -- type of information request
346 **		valp -- structure to place obtained info into
347 **
348 **	Returns:
349 **		-1 on error and sets errno:
350 **			- when valp==NULL and request expects otherwise
351 **			- when request is not SM_IO_WHAT_VECTORS and not
352 **				SM_IO_WHAT_TYPE and not SM_IO_WHAT_ISTYPE
353 **				and getinfo vector is NULL
354 **			- when getinfo type vector returns -1
355 **		>=0 on success
356 */
357 
358 int
359 sm_io_getinfo(fp, what, valp)
360 	SM_FILE_T *fp;
361 	int what;
362 	void *valp;
363 {
364 	SM_FILE_T *v = (SM_FILE_T *) valp;
365 
366 	SM_REQUIRE_ISA(fp, SmFileMagic);
367 
368 	switch (what)
369 	{
370 	  case SM_IO_WHAT_VECTORS:
371 
372 		/* This is the "generic" available for all */
373 		v->f_close = fp->f_close;
374 		v->f_read = fp->f_read;
375 		v->f_seek = fp->f_seek;
376 		v->f_write = fp->f_write;
377 		v->f_open = fp->f_open;
378 		v->f_setinfo = fp->f_setinfo;
379 		v->f_getinfo = fp->f_getinfo;
380 		v->f_type = fp->f_type;
381 		return 0;
382 
383 	  case SM_IO_WHAT_TYPE:
384 		if (valp == NULL)
385 		{
386 			errno = EINVAL;
387 			return -1;
388 		}
389 		valp = sm_strdup_x(fp->f_type);
390 		return 0;
391 
392 	  case SM_IO_WHAT_ISTYPE:
393 		if (valp == NULL)
394 		{
395 			errno = EINVAL;
396 			return -1;
397 		}
398 		return strcmp(fp->f_type, valp) == 0;
399 
400 	  case SM_IO_IS_READABLE:
401 
402 		/* if there is data in the buffer, it must be readable */
403 		if (fp->f_r > 0)
404 			return 1;
405 
406 		/* otherwise query the underlying file */
407 		break;
408 
409 	   case SM_IO_WHAT_TIMEOUT:
410 		*((int *) valp) = fp->f_timeout;
411 		return 0;
412 
413 	  case SM_IO_WHAT_FD:
414 		if (fp->f_file > -1)
415 			return fp->f_file;
416 
417 		/* try the file type specific getinfo to see if it knows */
418 		break;
419 	}
420 
421 	/* Otherwise the vector will check it out */
422 	if (fp->f_getinfo == NULL)
423 	{
424 		errno = EINVAL;
425 		return -1;
426 	}
427 	return (*fp->f_getinfo)(fp, what, valp);
428 }
429