190792Sgshapiro/* 2261363Sgshapiro * Copyright (c) 2000-2002, 2006 Proofpoint, Inc. and its suppliers. 390792Sgshapiro * All rights reserved. 490792Sgshapiro * Copyright (c) 1990, 1993 590792Sgshapiro * The Regents of the University of California. All rights reserved. 690792Sgshapiro * 790792Sgshapiro * This code is derived from software contributed to Berkeley by 890792Sgshapiro * Chris Torek. 990792Sgshapiro * 1090792Sgshapiro * By using this file, you agree to the terms and conditions set 1190792Sgshapiro * forth in the LICENSE file which can be found at the top level of 1290792Sgshapiro * the sendmail distribution. 1390792Sgshapiro */ 1490792Sgshapiro 1590792Sgshapiro#include <sm/gen.h> 16266692SgshapiroSM_RCSID("@(#)$Id: findfp.c,v 1.68 2013-11-22 20:51:42 ca Exp $") 1790792Sgshapiro#include <stdlib.h> 1890792Sgshapiro#include <unistd.h> 1990792Sgshapiro#include <sys/param.h> 2090792Sgshapiro#include <errno.h> 2190792Sgshapiro#include <string.h> 2290792Sgshapiro#include <syslog.h> 2390792Sgshapiro#include <sm/io.h> 2490792Sgshapiro#include <sm/assert.h> 2590792Sgshapiro#include <sm/heap.h> 2690792Sgshapiro#include <sm/string.h> 2790792Sgshapiro#include <sm/conf.h> 2890792Sgshapiro#include "local.h" 2990792Sgshapiro#include "glue.h" 3090792Sgshapiro 3190792Sgshapirobool Sm_IO_DidInit; /* IO system has been initialized? */ 3290792Sgshapiro 3390792Sgshapiroconst char SmFileMagic[] = "sm_file"; 3490792Sgshapiro 3590792Sgshapiro/* An open type to map to fopen()-like behavior */ 3690792SgshapiroSM_FILE_T SmFtStdio_def = 3790792Sgshapiro {SmFileMagic, 0, 0, 0, (SMRW|SMFBF), -1, {0, 0}, 0, 0, 0, 3890792Sgshapiro sm_stdclose, sm_stdread, sm_stdseek, sm_stdwrite, 3990792Sgshapiro sm_stdopen, sm_stdsetinfo, sm_stdgetinfo, SM_TIME_FOREVER, 4090792Sgshapiro SM_TIME_BLOCK, "stdio" }; 4190792Sgshapiro 4290792Sgshapiro/* An open type to map to fdopen()-like behavior */ 4390792SgshapiroSM_FILE_T SmFtStdiofd_def = 4490792Sgshapiro {SmFileMagic, 0, 0, 0, (SMRW|SMFBF), -1, {0, 0}, 0, 0, 0, 4590792Sgshapiro sm_stdclose, sm_stdread, sm_stdseek, sm_stdwrite, 4690792Sgshapiro sm_stdfdopen, sm_stdsetinfo, sm_stdgetinfo, SM_TIME_FOREVER, 4790792Sgshapiro SM_TIME_BLOCK, "stdiofd" }; 4890792Sgshapiro 4990792Sgshapiro/* A string file type */ 5094334SgshapiroSM_FILE_T SmFtString_def = 5190792Sgshapiro {SmFileMagic, 0, 0, 0, (SMRW|SMNBF), -1, {0, 0}, 0, 0, 0, 5290792Sgshapiro sm_strclose, sm_strread, sm_strseek, sm_strwrite, 5390792Sgshapiro sm_stropen, sm_strsetinfo, sm_strgetinfo, SM_TIME_FOREVER, 5490792Sgshapiro SM_TIME_BLOCK, "string" }; 5590792Sgshapiro 5690792Sgshapiro#if 0 5790792Sgshapiro/* A file type for syslog communications */ 5890792SgshapiroSM_FILE_T SmFtSyslog_def = 5990792Sgshapiro {SmFileMagic, 0, 0, 0, (SMRW|SMNBF), -1, {0, 0}, 0, 0, 0, 6090792Sgshapiro sm_syslogclose, sm_syslogread, sm_syslogseek, sm_syslogwrite, 6190792Sgshapiro sm_syslogopen, sm_syslogsetinfo, sm_sysloggetinfo, SM_TIME_FOREVER, 6290792Sgshapiro SM_TIME_BLOCK, "syslog" }; 6390792Sgshapiro#endif /* 0 */ 6490792Sgshapiro 6590792Sgshapiro#define NDYNAMIC 10 /* add ten more whenever necessary */ 6690792Sgshapiro 6790792Sgshapiro#define smio(flags, file, name) \ 6890792Sgshapiro {SmFileMagic, 0, 0, 0, flags, file, {0}, 0, SmIoF+file, 0, \ 6990792Sgshapiro sm_stdclose, sm_stdread, sm_stdseek, sm_stdwrite, \ 7090792Sgshapiro sm_stdopen, sm_stdsetinfo, sm_stdgetinfo, SM_TIME_FOREVER, \ 7190792Sgshapiro SM_TIME_BLOCK, name} 7290792Sgshapiro 7390792Sgshapiro/* sm_magic p r w flags file bf lbfsize cookie ival */ 7490792Sgshapiro#define smstd(flags, file, name) \ 7590792Sgshapiro {SmFileMagic, 0, 0, 0, flags, -1, {0}, 0, 0, file, \ 7690792Sgshapiro sm_stdioclose, sm_stdioread, sm_stdioseek, sm_stdiowrite, \ 7790792Sgshapiro sm_stdioopen, sm_stdiosetinfo, sm_stdiogetinfo, SM_TIME_FOREVER,\ 7890792Sgshapiro SM_TIME_BLOCK, name} 7990792Sgshapiro 8090792Sgshapiro/* A file type for interfacing to stdio FILE* streams. */ 8190792SgshapiroSM_FILE_T SmFtRealStdio_def = smstd(SMRW|SMNBF, -1, "realstdio"); 8290792Sgshapiro 8390792Sgshapiro /* the usual - (stdin + stdout + stderr) */ 8490792Sgshapirostatic SM_FILE_T usual[SM_IO_OPEN_MAX - 3]; 8590792Sgshapirostatic struct sm_glue smuglue = { 0, SM_IO_OPEN_MAX - 3, usual }; 8690792Sgshapiro 8790792Sgshapiro/* List of builtin automagically already open file pointers */ 8890792SgshapiroSM_FILE_T SmIoF[6] = 8990792Sgshapiro{ 9090792Sgshapiro smio(SMRD|SMLBF, SMIOIN_FILENO, "smioin"), /* smioin */ 9190792Sgshapiro smio(SMWR|SMLBF, SMIOOUT_FILENO, "smioout"), /* smioout */ 9290792Sgshapiro smio(SMWR|SMNBF, SMIOERR_FILENO, "smioerr"), /* smioerr */ 9390792Sgshapiro smstd(SMRD|SMNBF, SMIOIN_FILENO, "smiostdin"), /* smiostdin */ 9490792Sgshapiro smstd(SMWR|SMNBF, SMIOOUT_FILENO, "smiostdout"),/* smiostdout */ 9590792Sgshapiro smstd(SMWR|SMNBF, SMIOERR_FILENO, "smiostderr") /* smiostderr */ 9690792Sgshapiro}; 9790792Sgshapiro 9890792Sgshapiro/* Structure containing list of currently open file pointers */ 9990792Sgshapirostruct sm_glue smglue = { &smuglue, 3, SmIoF }; 10090792Sgshapiro 10190792Sgshapiro/* 10290792Sgshapiro** SM_MOREGLUE -- adds more space for open file pointers 10390792Sgshapiro** 10490792Sgshapiro** Parameters: 10590792Sgshapiro** n -- number of new spaces for file pointers 10690792Sgshapiro** 10790792Sgshapiro** Returns: 10890792Sgshapiro** Raises an exception if no more memory. 10990792Sgshapiro** Otherwise, returns a pointer to new spaces. 11090792Sgshapiro*/ 11190792Sgshapiro 11290792Sgshapirostatic struct sm_glue *sm_moreglue_x __P((int)); 11390792Sgshapirostatic SM_FILE_T empty; 11490792Sgshapiro 11590792Sgshapirostatic struct sm_glue * 11690792Sgshapirosm_moreglue_x(n) 11790792Sgshapiro register int n; 11890792Sgshapiro{ 11990792Sgshapiro register struct sm_glue *g; 12090792Sgshapiro register SM_FILE_T *p; 12190792Sgshapiro 12294334Sgshapiro g = (struct sm_glue *) sm_pmalloc_x(sizeof(*g) + SM_ALIGN_BITS + 12390792Sgshapiro n * sizeof(SM_FILE_T)); 12494334Sgshapiro p = (SM_FILE_T *) SM_ALIGN(g + 1); 12590792Sgshapiro g->gl_next = NULL; 12690792Sgshapiro g->gl_niobs = n; 12790792Sgshapiro g->gl_iobs = p; 12890792Sgshapiro while (--n >= 0) 12990792Sgshapiro *p++ = empty; 13090792Sgshapiro return g; 13190792Sgshapiro} 13290792Sgshapiro 13390792Sgshapiro/* 13490792Sgshapiro** SM_FP -- allocate and initialize an SM_FILE structure 13590792Sgshapiro** 13690792Sgshapiro** Parameters: 13790792Sgshapiro** t -- file type requested to be opened. 13890792Sgshapiro** flags -- control flags for file type behavior 13990792Sgshapiro** oldfp -- file pointer to reuse if available (optional) 14090792Sgshapiro** 14190792Sgshapiro** Returns: 14290792Sgshapiro** Raises exception on memory exhaustion. 14390792Sgshapiro** Aborts if type is invalid. 14490792Sgshapiro** Otherwise, returns file pointer for requested file type. 14590792Sgshapiro*/ 14690792Sgshapiro 14790792SgshapiroSM_FILE_T * 14890792Sgshapirosm_fp(t, flags, oldfp) 14990792Sgshapiro const SM_FILE_T *t; 15090792Sgshapiro const int flags; 15190792Sgshapiro SM_FILE_T *oldfp; 15290792Sgshapiro{ 15390792Sgshapiro register SM_FILE_T *fp; 15490792Sgshapiro register int n; 15590792Sgshapiro register struct sm_glue *g; 15690792Sgshapiro 15790792Sgshapiro SM_REQUIRE(t->f_open && t->f_close && (t->f_read || t->f_write)); 15890792Sgshapiro 15990792Sgshapiro if (!Sm_IO_DidInit) 16090792Sgshapiro sm_init(); 16190792Sgshapiro 16290792Sgshapiro if (oldfp != NULL) 16390792Sgshapiro { 16490792Sgshapiro fp = oldfp; 16590792Sgshapiro goto found; /* for opening reusing an 'fp' */ 16690792Sgshapiro } 16790792Sgshapiro 16890792Sgshapiro for (g = &smglue;; g = g->gl_next) 16990792Sgshapiro { 17090792Sgshapiro for (fp = g->gl_iobs, n = g->gl_niobs; --n >= 0; fp++) 17190792Sgshapiro if (fp->sm_magic == NULL) 17290792Sgshapiro goto found; 17390792Sgshapiro if (g->gl_next == NULL) 17490792Sgshapiro g->gl_next = sm_moreglue_x(NDYNAMIC); 17590792Sgshapiro } 17690792Sgshapirofound: 17790792Sgshapiro fp->sm_magic = SmFileMagic; /* 'fp' now valid and in-use */ 17890792Sgshapiro fp->f_p = NULL; /* no current pointer */ 17990792Sgshapiro fp->f_w = 0; /* nothing to write */ 18090792Sgshapiro fp->f_r = 0; /* nothing to read */ 18190792Sgshapiro fp->f_flags = flags; 18290792Sgshapiro fp->f_file = -1; /* no file */ 18390792Sgshapiro fp->f_bf.smb_base = NULL; /* no buffer */ 18490792Sgshapiro fp->f_bf.smb_size = 0; /* no buffer size with no buffer */ 18590792Sgshapiro fp->f_lbfsize = 0; /* not line buffered */ 18690792Sgshapiro fp->f_flushfp = NULL; /* no associated flush file */ 18790792Sgshapiro 18890792Sgshapiro fp->f_cookie = fp; /* default: *open* overrides cookie setting */ 18990792Sgshapiro fp->f_close = t->f_close; /* assign close function */ 19090792Sgshapiro fp->f_read = t->f_read; /* assign read function */ 19190792Sgshapiro fp->f_seek = t->f_seek; /* assign seek function */ 19290792Sgshapiro fp->f_write = t->f_write; /* assign write function */ 19390792Sgshapiro fp->f_open = t->f_open; /* assign open function */ 19490792Sgshapiro fp->f_setinfo = t->f_setinfo; /* assign setinfo function */ 19590792Sgshapiro fp->f_getinfo = t->f_getinfo; /* assign getinfo function */ 19690792Sgshapiro fp->f_type = t->f_type; /* file type */ 19790792Sgshapiro 19890792Sgshapiro fp->f_ub.smb_base = NULL; /* no ungetc buffer */ 19990792Sgshapiro fp->f_ub.smb_size = 0; /* no size for no ungetc buffer */ 20090792Sgshapiro 20190792Sgshapiro if (fp->f_timeout == SM_TIME_DEFAULT) 20290792Sgshapiro fp->f_timeout = SM_TIME_FOREVER; 20390792Sgshapiro else 20490792Sgshapiro fp->f_timeout = t->f_timeout; /* traditional behavior */ 20590792Sgshapiro fp->f_timeoutstate = SM_TIME_BLOCK; /* by default */ 20690792Sgshapiro 20790792Sgshapiro return fp; 20890792Sgshapiro} 20990792Sgshapiro 21090792Sgshapiro/* 21190792Sgshapiro** SM_CLEANUP -- cleanup function when exit called. 21290792Sgshapiro** 21390792Sgshapiro** This function is registered via atexit(). 21490792Sgshapiro** 21590792Sgshapiro** Parameters: 21690792Sgshapiro** none 21790792Sgshapiro** 21890792Sgshapiro** Returns: 21990792Sgshapiro** nothing. 22090792Sgshapiro** 22190792Sgshapiro** Side Effects: 22290792Sgshapiro** flushes open files before they are forced closed 22390792Sgshapiro*/ 22490792Sgshapiro 22590792Sgshapirovoid 22690792Sgshapirosm_cleanup() 22790792Sgshapiro{ 22890792Sgshapiro int timeout = SM_TIME_DEFAULT; 22990792Sgshapiro 23090792Sgshapiro (void) sm_fwalk(sm_flush, &timeout); /* `cheating' */ 23190792Sgshapiro} 23290792Sgshapiro 23390792Sgshapiro/* 23490792Sgshapiro** SM_INIT -- called whenever sm_io's internal variables must be set up. 23590792Sgshapiro** 23690792Sgshapiro** Parameters: 23790792Sgshapiro** none 23890792Sgshapiro** 23990792Sgshapiro** Returns: 24090792Sgshapiro** none 24190792Sgshapiro** 24290792Sgshapiro** Side Effects: 24390792Sgshapiro** Registers sm_cleanup() using atexit(). 24490792Sgshapiro*/ 24590792Sgshapiro 24690792Sgshapirovoid 24790792Sgshapirosm_init() 24890792Sgshapiro{ 24990792Sgshapiro if (Sm_IO_DidInit) /* paranoia */ 25090792Sgshapiro return; 25190792Sgshapiro 25290792Sgshapiro /* more paranoia: initialize pointers in a static variable */ 25390792Sgshapiro empty.f_type = NULL; 25490792Sgshapiro empty.sm_magic = NULL; 25590792Sgshapiro 25690792Sgshapiro /* make sure we clean up on exit */ 25790792Sgshapiro atexit(sm_cleanup); /* conservative */ 25890792Sgshapiro Sm_IO_DidInit = true; 25990792Sgshapiro} 26090792Sgshapiro 26190792Sgshapiro/* 26290792Sgshapiro** SM_IO_SETINFO -- change info for an open file type (fp) 26390792Sgshapiro** 26490792Sgshapiro** The generic SM_IO_WHAT_VECTORS is auto supplied for all file types. 26590792Sgshapiro** If the request is to set info other than SM_IO_WHAT_VECTORS then 26690792Sgshapiro** the request is passed on to the file type's specific setinfo vector. 26790792Sgshapiro** WARNING: this is working on an active/open file type. 26890792Sgshapiro** 26990792Sgshapiro** Parameters: 27090792Sgshapiro** fp -- file to make the setting on 27190792Sgshapiro** what -- type of information to set 27290792Sgshapiro** valp -- structure to obtain info from 27390792Sgshapiro** 27490792Sgshapiro** Returns: 27590792Sgshapiro** 0 on success 27690792Sgshapiro** -1 on error and sets errno: 27790792Sgshapiro** - when what != SM_IO_WHAT_VECTORS and setinfo vector 27890792Sgshapiro** not set 27990792Sgshapiro** - when vectored setinfo returns -1 28090792Sgshapiro*/ 28190792Sgshapiro 28290792Sgshapiroint 28390792Sgshapirosm_io_setinfo(fp, what, valp) 28490792Sgshapiro SM_FILE_T *fp; 28590792Sgshapiro int what; 28690792Sgshapiro void *valp; 28790792Sgshapiro{ 28890792Sgshapiro SM_FILE_T *v = (SM_FILE_T *) valp; 28990792Sgshapiro 29090792Sgshapiro SM_REQUIRE_ISA(fp, SmFileMagic); 29190792Sgshapiro switch (what) 29290792Sgshapiro { 29390792Sgshapiro case SM_IO_WHAT_VECTORS: 29490792Sgshapiro 29590792Sgshapiro /* 29690792Sgshapiro ** This is the "generic" available for all. 29790792Sgshapiro ** This allows the function vectors to be replaced 29890792Sgshapiro ** while the file type is active. 29990792Sgshapiro */ 30090792Sgshapiro 30190792Sgshapiro fp->f_close = v->f_close; 30290792Sgshapiro fp->f_read = v->f_read; 30390792Sgshapiro fp->f_seek = v->f_seek; 30490792Sgshapiro fp->f_write = v->f_write; 30590792Sgshapiro fp->f_open = v->f_open; 30690792Sgshapiro fp->f_setinfo = v->f_setinfo; 30790792Sgshapiro fp->f_getinfo = v->f_getinfo; 30890792Sgshapiro sm_free(fp->f_type); 30990792Sgshapiro fp->f_type = sm_strdup_x(v->f_type); 31090792Sgshapiro return 0; 31190792Sgshapiro case SM_IO_WHAT_TIMEOUT: 31290792Sgshapiro fp->f_timeout = *((int *)valp); 31390792Sgshapiro return 0; 31490792Sgshapiro } 31590792Sgshapiro 31690792Sgshapiro /* Otherwise the vector will check it out */ 31790792Sgshapiro if (fp->f_setinfo == NULL) 31890792Sgshapiro { 31990792Sgshapiro errno = EINVAL; 32090792Sgshapiro return -1; 32190792Sgshapiro } 32290792Sgshapiro else 32390792Sgshapiro return (*fp->f_setinfo)(fp, what, valp); 32490792Sgshapiro} 32590792Sgshapiro 32690792Sgshapiro/* 32790792Sgshapiro** SM_IO_GETINFO -- get information for an active file type (fp) 32890792Sgshapiro** 32990792Sgshapiro** This function supplies for all file types the answers for the 33090792Sgshapiro** three requests SM_IO_WHAT_VECTORS, SM_IO_WHAT_TYPE and 33190792Sgshapiro** SM_IO_WHAT_ISTYPE. Other requests are handled by the getinfo 33290792Sgshapiro** vector if available for the open file type. 33390792Sgshapiro** SM_IO_WHAT_VECTORS returns information for the file pointer vectors. 33490792Sgshapiro** SM_IO_WHAT_TYPE returns the type identifier for the file pointer 33590792Sgshapiro** SM_IO_WHAT_ISTYPE returns >0 if the passed in type matches the 33690792Sgshapiro** file pointer's type. 33790792Sgshapiro** SM_IO_IS_READABLE returns 1 if there is data available for reading, 33890792Sgshapiro** 0 otherwise. 33990792Sgshapiro** 34090792Sgshapiro** Parameters: 34190792Sgshapiro** fp -- file pointer for active file type 34290792Sgshapiro** what -- type of information request 34390792Sgshapiro** valp -- structure to place obtained info into 34490792Sgshapiro** 34590792Sgshapiro** Returns: 34690792Sgshapiro** -1 on error and sets errno: 34790792Sgshapiro** - when valp==NULL and request expects otherwise 34890792Sgshapiro** - when request is not SM_IO_WHAT_VECTORS and not 34990792Sgshapiro** SM_IO_WHAT_TYPE and not SM_IO_WHAT_ISTYPE 35090792Sgshapiro** and getinfo vector is NULL 35190792Sgshapiro** - when getinfo type vector returns -1 35290792Sgshapiro** >=0 on success 35390792Sgshapiro*/ 35490792Sgshapiro 35590792Sgshapiroint 35690792Sgshapirosm_io_getinfo(fp, what, valp) 35790792Sgshapiro SM_FILE_T *fp; 35890792Sgshapiro int what; 35990792Sgshapiro void *valp; 36090792Sgshapiro{ 36190792Sgshapiro SM_FILE_T *v = (SM_FILE_T *) valp; 36290792Sgshapiro 36390792Sgshapiro SM_REQUIRE_ISA(fp, SmFileMagic); 36490792Sgshapiro 36590792Sgshapiro switch (what) 36690792Sgshapiro { 36790792Sgshapiro case SM_IO_WHAT_VECTORS: 368168515Sgshapiro if (valp == NULL) 369168515Sgshapiro { 370168515Sgshapiro errno = EINVAL; 371168515Sgshapiro return -1; 372168515Sgshapiro } 37390792Sgshapiro 37490792Sgshapiro /* This is the "generic" available for all */ 37590792Sgshapiro v->f_close = fp->f_close; 37690792Sgshapiro v->f_read = fp->f_read; 37790792Sgshapiro v->f_seek = fp->f_seek; 37890792Sgshapiro v->f_write = fp->f_write; 37990792Sgshapiro v->f_open = fp->f_open; 38090792Sgshapiro v->f_setinfo = fp->f_setinfo; 38190792Sgshapiro v->f_getinfo = fp->f_getinfo; 38290792Sgshapiro v->f_type = fp->f_type; 38390792Sgshapiro return 0; 38490792Sgshapiro 38590792Sgshapiro case SM_IO_WHAT_TYPE: 38690792Sgshapiro if (valp == NULL) 38790792Sgshapiro { 38890792Sgshapiro errno = EINVAL; 38990792Sgshapiro return -1; 39090792Sgshapiro } 39190792Sgshapiro valp = sm_strdup_x(fp->f_type); 39290792Sgshapiro return 0; 39390792Sgshapiro 39490792Sgshapiro case SM_IO_WHAT_ISTYPE: 39590792Sgshapiro if (valp == NULL) 39690792Sgshapiro { 39790792Sgshapiro errno = EINVAL; 39890792Sgshapiro return -1; 39990792Sgshapiro } 40090792Sgshapiro return strcmp(fp->f_type, valp) == 0; 40190792Sgshapiro 40290792Sgshapiro case SM_IO_IS_READABLE: 40390792Sgshapiro 40490792Sgshapiro /* if there is data in the buffer, it must be readable */ 40590792Sgshapiro if (fp->f_r > 0) 40690792Sgshapiro return 1; 40790792Sgshapiro 40890792Sgshapiro /* otherwise query the underlying file */ 40990792Sgshapiro break; 41090792Sgshapiro 41190792Sgshapiro case SM_IO_WHAT_TIMEOUT: 41290792Sgshapiro *((int *) valp) = fp->f_timeout; 41390792Sgshapiro return 0; 41490792Sgshapiro 41590792Sgshapiro case SM_IO_WHAT_FD: 41690792Sgshapiro if (fp->f_file > -1) 41790792Sgshapiro return fp->f_file; 41890792Sgshapiro 41990792Sgshapiro /* try the file type specific getinfo to see if it knows */ 42090792Sgshapiro break; 42190792Sgshapiro } 42290792Sgshapiro 42390792Sgshapiro /* Otherwise the vector will check it out */ 42490792Sgshapiro if (fp->f_getinfo == NULL) 42590792Sgshapiro { 42690792Sgshapiro errno = EINVAL; 42790792Sgshapiro return -1; 42890792Sgshapiro } 42990792Sgshapiro return (*fp->f_getinfo)(fp, what, valp); 43090792Sgshapiro} 431