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> 16 SM_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 31 bool Sm_IO_DidInit; /* IO system has been initialized? */ 32 33 const char SmFileMagic[] = "sm_file"; 34 35 /* An open type to map to fopen()-like behavior */ 36 SM_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 */ 43 SM_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 */ 50 SM_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 */ 58 SM_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. */ 81 SM_FILE_T SmFtRealStdio_def = smstd(SMRW|SMNBF, -1, "realstdio"); 82 83 /* the usual - (stdin + stdout + stderr) */ 84 static SM_FILE_T usual[SM_IO_OPEN_MAX - 3]; 85 static struct sm_glue smuglue = { 0, SM_IO_OPEN_MAX - 3, usual }; 86 87 /* List of builtin automagically already open file pointers */ 88 SM_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 */ 99 struct 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 112 static struct sm_glue *sm_moreglue_x __P((int)); 113 static SM_FILE_T empty; 114 115 static struct sm_glue * 116 sm_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 147 SM_FILE_T * 148 sm_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 } 176 found: 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 225 void 226 sm_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 246 void 247 sm_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 282 int 283 sm_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, and SM_IO_WHAT_ISTYPE. 331 ** 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_ISTYPE returns >0 if the passed in type matches the 335 ** file pointer's type. 336 ** SM_IO_IS_READABLE returns 1 if there is data available for reading, 337 ** 0 otherwise. 338 ** 339 ** Parameters: 340 ** fp -- file pointer for active file type 341 ** what -- type of information request 342 ** valp -- structure to place obtained info into 343 ** 344 ** Returns: 345 ** -1 on error and sets errno: 346 ** - when valp==NULL and request expects otherwise 347 ** - when request is not SM_IO_WHAT_VECTORS 348 ** and not SM_IO_WHAT_ISTYPE 349 ** and getinfo vector is NULL 350 ** - when getinfo type vector returns -1 351 ** >=0 on success 352 */ 353 354 int 355 sm_io_getinfo(fp, what, valp) 356 SM_FILE_T *fp; 357 int what; 358 void *valp; 359 { 360 SM_FILE_T *v = (SM_FILE_T *) valp; 361 362 SM_REQUIRE_ISA(fp, SmFileMagic); 363 364 switch (what) 365 { 366 case SM_IO_WHAT_VECTORS: 367 if (valp == NULL) 368 { 369 errno = EINVAL; 370 return -1; 371 } 372 373 /* This is the "generic" available for all */ 374 v->f_close = fp->f_close; 375 v->f_read = fp->f_read; 376 v->f_seek = fp->f_seek; 377 v->f_write = fp->f_write; 378 v->f_open = fp->f_open; 379 v->f_setinfo = fp->f_setinfo; 380 v->f_getinfo = fp->f_getinfo; 381 v->f_type = fp->f_type; 382 return 0; 383 384 case SM_IO_WHAT_ISTYPE: 385 if (valp == NULL) 386 { 387 errno = EINVAL; 388 return -1; 389 } 390 return strcmp(fp->f_type, valp) == 0; 391 392 case SM_IO_IS_READABLE: 393 394 /* if there is data in the buffer, it must be readable */ 395 if (fp->f_r > 0) 396 return 1; 397 398 /* otherwise query the underlying file */ 399 break; 400 401 case SM_IO_WHAT_TIMEOUT: 402 *((int *) valp) = fp->f_timeout; 403 return 0; 404 405 case SM_IO_WHAT_FD: 406 if (fp->f_file > -1) 407 return fp->f_file; 408 409 /* try the file type specific getinfo to see if it knows */ 410 break; 411 } 412 413 /* Otherwise the vector will check it out */ 414 if (fp->f_getinfo == NULL) 415 { 416 errno = EINVAL; 417 return -1; 418 } 419 return (*fp->f_getinfo)(fp, what, valp); 420 } 421