findfp.c revision 90792
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> 16SM_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 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) + 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 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 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 228void 229sm_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 249void 250sm_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 285int 286sm_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 358int 359sm_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