findfp.c revision 261194
1132451Sroberto/*
2132451Sroberto * Copyright (c) 2000-2002, 2006 Proofpoint, Inc. and its suppliers.
3285612Sdelphij *      All rights reserved.
4285612Sdelphij * Copyright (c) 1990, 1993
5285612Sdelphij *	The Regents of the University of California.  All rights reserved.
6285612Sdelphij *
7285612Sdelphij * This code is derived from software contributed to Berkeley by
8285612Sdelphij * Chris Torek.
9285612Sdelphij *
10285612Sdelphij * By using this file, you agree to the terms and conditions set
11285612Sdelphij * forth in the LICENSE file which can be found at the top level of
12285612Sdelphij * the sendmail distribution.
13285612Sdelphij */
14285612Sdelphij
15285612Sdelphij#include <sm/gen.h>
16285612SdelphijSM_RCSID("@(#)$Id: findfp.c,v 1.68 2013/11/22 20:51:42 ca Exp $")
17285612Sdelphij#include <stdlib.h>
18285612Sdelphij#include <unistd.h>
19285612Sdelphij#include <sys/param.h>
20285612Sdelphij#include <errno.h>
21285612Sdelphij#include <string.h>
22285612Sdelphij#include <syslog.h>
23285612Sdelphij#include <sm/io.h>
24285612Sdelphij#include <sm/assert.h>
25285612Sdelphij#include <sm/heap.h>
26285612Sdelphij#include <sm/string.h>
27285612Sdelphij#include <sm/conf.h>
28285612Sdelphij#include "local.h"
29285612Sdelphij#include "glue.h"
30285612Sdelphij
31285612Sdelphijbool	Sm_IO_DidInit;	/* IO system has been initialized? */
32285612Sdelphij
33285612Sdelphijconst char SmFileMagic[] = "sm_file";
34285612Sdelphij
35285612Sdelphij/* An open type to map to fopen()-like behavior */
36285612SdelphijSM_FILE_T SmFtStdio_def =
37285612Sdelphij    {SmFileMagic, 0, 0, 0, (SMRW|SMFBF), -1, {0, 0}, 0, 0, 0,
38285612Sdelphij	sm_stdclose, sm_stdread, sm_stdseek, sm_stdwrite,
39285612Sdelphij	sm_stdopen, sm_stdsetinfo, sm_stdgetinfo, SM_TIME_FOREVER,
40285612Sdelphij	SM_TIME_BLOCK, "stdio" };
41285612Sdelphij
42285612Sdelphij/* An open type to map to fdopen()-like behavior */
43285612SdelphijSM_FILE_T SmFtStdiofd_def =
44285612Sdelphij    {SmFileMagic, 0, 0, 0, (SMRW|SMFBF), -1, {0, 0}, 0, 0, 0,
45285612Sdelphij	sm_stdclose, sm_stdread, sm_stdseek, sm_stdwrite,
46285612Sdelphij	sm_stdfdopen, sm_stdsetinfo, sm_stdgetinfo, SM_TIME_FOREVER,
47285612Sdelphij	SM_TIME_BLOCK, "stdiofd" };
48285612Sdelphij
49285612Sdelphij/* A string file type */
50285612SdelphijSM_FILE_T SmFtString_def =
51285612Sdelphij    {SmFileMagic, 0, 0, 0, (SMRW|SMNBF), -1, {0, 0}, 0, 0, 0,
52285612Sdelphij	sm_strclose, sm_strread, sm_strseek, sm_strwrite,
53285612Sdelphij	sm_stropen, sm_strsetinfo, sm_strgetinfo, SM_TIME_FOREVER,
54285612Sdelphij	SM_TIME_BLOCK, "string" };
55285612Sdelphij
56285612Sdelphij#if 0
57285612Sdelphij/* A file type for syslog communications */
58285612SdelphijSM_FILE_T SmFtSyslog_def =
59285612Sdelphij    {SmFileMagic, 0, 0, 0, (SMRW|SMNBF), -1, {0, 0}, 0, 0, 0,
60285612Sdelphij	sm_syslogclose, sm_syslogread, sm_syslogseek, sm_syslogwrite,
61285612Sdelphij	sm_syslogopen, sm_syslogsetinfo, sm_sysloggetinfo, SM_TIME_FOREVER,
62285612Sdelphij	SM_TIME_BLOCK, "syslog" };
63285612Sdelphij#endif /* 0 */
64285612Sdelphij
65285612Sdelphij#define NDYNAMIC 10		/* add ten more whenever necessary */
66132451Sroberto
67132451Sroberto#define smio(flags, file, name)						\
68132451Sroberto    {SmFileMagic, 0, 0, 0, flags, file, {0}, 0, SmIoF+file, 0,		\
69132451Sroberto	sm_stdclose, sm_stdread, sm_stdseek, sm_stdwrite,		\
70132451Sroberto	sm_stdopen, sm_stdsetinfo, sm_stdgetinfo, SM_TIME_FOREVER,	\
71132451Sroberto	SM_TIME_BLOCK, name}
72132451Sroberto
73132451Sroberto/* sm_magic p r w flags file bf lbfsize cookie ival */
74285612Sdelphij#define smstd(flags, file, name)					\
75285612Sdelphij    {SmFileMagic, 0, 0, 0, flags, -1, {0}, 0, 0, file,			\
76132451Sroberto	sm_stdioclose, sm_stdioread, sm_stdioseek, sm_stdiowrite,	\
77132451Sroberto	sm_stdioopen, sm_stdiosetinfo, sm_stdiogetinfo, SM_TIME_FOREVER,\
78132451Sroberto	SM_TIME_BLOCK, name}
79285612Sdelphij
80285612Sdelphij/* A file type for interfacing to stdio FILE* streams. */
81132451SrobertoSM_FILE_T SmFtRealStdio_def = smstd(SMRW|SMNBF, -1, "realstdio");
82132451Sroberto
83285612Sdelphij				/* the usual - (stdin + stdout + stderr) */
84285612Sdelphijstatic SM_FILE_T usual[SM_IO_OPEN_MAX - 3];
85285612Sdelphijstatic struct sm_glue smuglue = { 0, SM_IO_OPEN_MAX - 3, usual };
86285612Sdelphij
87285612Sdelphij/* List of builtin automagically already open file pointers */
88285612SdelphijSM_FILE_T SmIoF[6] =
89285612Sdelphij{
90285612Sdelphij	smio(SMRD|SMLBF, SMIOIN_FILENO, "smioin"),	/* smioin */
91285612Sdelphij	smio(SMWR|SMLBF, SMIOOUT_FILENO, "smioout"),	/* smioout */
92285612Sdelphij	smio(SMWR|SMNBF, SMIOERR_FILENO, "smioerr"),	/* smioerr */
93285612Sdelphij	smstd(SMRD|SMNBF, SMIOIN_FILENO, "smiostdin"),	/* smiostdin */
94285612Sdelphij	smstd(SMWR|SMNBF, SMIOOUT_FILENO, "smiostdout"),/* smiostdout */
95285612Sdelphij	smstd(SMWR|SMNBF, SMIOERR_FILENO, "smiostderr") /* smiostderr */
96285612Sdelphij};
97285612Sdelphij
98285612Sdelphij/* Structure containing list of currently open file pointers */
99285612Sdelphijstruct sm_glue smglue = { &smuglue, 3, SmIoF };
100285612Sdelphij
101285612Sdelphij/*
102285612Sdelphij**  SM_MOREGLUE -- adds more space for open file pointers
103285612Sdelphij**
104285612Sdelphij**	Parameters:
105285612Sdelphij**		n -- number of new spaces for file pointers
106285612Sdelphij**
107285612Sdelphij**	Returns:
108285612Sdelphij**		Raises an exception if no more memory.
109285612Sdelphij**		Otherwise, returns a pointer to new spaces.
110285612Sdelphij*/
111285612Sdelphij
112285612Sdelphijstatic struct sm_glue *sm_moreglue_x __P((int));
113285612Sdelphijstatic SM_FILE_T empty;
114285612Sdelphij
115285612Sdelphijstatic struct sm_glue *
116285612Sdelphijsm_moreglue_x(n)
117285612Sdelphij	register int n;
118285612Sdelphij{
119285612Sdelphij	register struct sm_glue *g;
120285612Sdelphij	register SM_FILE_T *p;
121285612Sdelphij
122285612Sdelphij	g = (struct sm_glue *) sm_pmalloc_x(sizeof(*g) + SM_ALIGN_BITS +
123285612Sdelphij					    n * sizeof(SM_FILE_T));
124285612Sdelphij	p = (SM_FILE_T *) SM_ALIGN(g + 1);
125285612Sdelphij	g->gl_next = NULL;
126285612Sdelphij	g->gl_niobs = n;
127285612Sdelphij	g->gl_iobs = p;
128285612Sdelphij	while (--n >= 0)
129285612Sdelphij		*p++ = empty;
130285612Sdelphij	return g;
131285612Sdelphij}
132285612Sdelphij
133285612Sdelphij/*
134285612Sdelphij**  SM_FP -- allocate and initialize an SM_FILE structure
135285612Sdelphij**
136285612Sdelphij**	Parameters:
137285612Sdelphij**		t -- file type requested to be opened.
138285612Sdelphij**		flags -- control flags for file type behavior
139285612Sdelphij**		oldfp -- file pointer to reuse if available (optional)
140285612Sdelphij**
141285612Sdelphij**	Returns:
142285612Sdelphij**		Raises exception on memory exhaustion.
143285612Sdelphij**		Aborts if type is invalid.
144285612Sdelphij**		Otherwise, returns file pointer for requested file type.
145*/
146
147SM_FILE_T *
148sm_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	}
176found:
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
225void
226sm_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
246void
247sm_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
282int
283sm_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
355int
356sm_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		if (valp == NULL)
369		{
370			errno = EINVAL;
371			return -1;
372		}
373
374		/* This is the "generic" available for all */
375		v->f_close = fp->f_close;
376		v->f_read = fp->f_read;
377		v->f_seek = fp->f_seek;
378		v->f_write = fp->f_write;
379		v->f_open = fp->f_open;
380		v->f_setinfo = fp->f_setinfo;
381		v->f_getinfo = fp->f_getinfo;
382		v->f_type = fp->f_type;
383		return 0;
384
385	  case SM_IO_WHAT_TYPE:
386		if (valp == NULL)
387		{
388			errno = EINVAL;
389			return -1;
390		}
391		valp = sm_strdup_x(fp->f_type);
392		return 0;
393
394	  case SM_IO_WHAT_ISTYPE:
395		if (valp == NULL)
396		{
397			errno = EINVAL;
398			return -1;
399		}
400		return strcmp(fp->f_type, valp) == 0;
401
402	  case SM_IO_IS_READABLE:
403
404		/* if there is data in the buffer, it must be readable */
405		if (fp->f_r > 0)
406			return 1;
407
408		/* otherwise query the underlying file */
409		break;
410
411	   case SM_IO_WHAT_TIMEOUT:
412		*((int *) valp) = fp->f_timeout;
413		return 0;
414
415	  case SM_IO_WHAT_FD:
416		if (fp->f_file > -1)
417			return fp->f_file;
418
419		/* try the file type specific getinfo to see if it knows */
420		break;
421	}
422
423	/* Otherwise the vector will check it out */
424	if (fp->f_getinfo == NULL)
425	{
426		errno = EINVAL;
427		return -1;
428	}
429	return (*fp->f_getinfo)(fp, what, valp);
430}
431