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