findfp.c revision 266692
1/* 2 * Copyright (c) 2000-2002, 2006 Proofpoint, 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> 16SM_RCSID("@(#)$Id: findfp.c,v 1.68 2013-11-22 20:51:42 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 31bool Sm_IO_DidInit; /* IO system has been initialized? */ 32 33const char SmFileMagic[] = "sm_file"; 34 35/* An open type to map to fopen()-like behavior */ 36SM_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 */ 43SM_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 */ 50SM_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 */ 58SM_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. */ 81SM_FILE_T SmFtRealStdio_def = smstd(SMRW|SMNBF, -1, "realstdio"); 82 83 /* the usual - (stdin + stdout + stderr) */ 84static SM_FILE_T usual[SM_IO_OPEN_MAX - 3]; 85static struct sm_glue smuglue = { 0, SM_IO_OPEN_MAX - 3, usual }; 86 87/* List of builtin automagically already open file pointers */ 88SM_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 */ 99struct 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 112static struct sm_glue *sm_moreglue_x __P((int)); 113static SM_FILE_T empty; 114 115static struct sm_glue * 116sm_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 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