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