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