1 /*********************************************************************** 2 * * 3 * This software is part of the ast package * 4 * Copyright (c) 1985-2007 AT&T Knowledge Ventures * 5 * and is licensed under the * 6 * Common Public License, Version 1.0 * 7 * by AT&T Knowledge Ventures * 8 * * 9 * A copy of the License is available at * 10 * http://www.opensource.org/licenses/cpl1.0.txt * 11 * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * 12 * * 13 * Information and Software Systems Research * 14 * AT&T Research * 15 * Florham Park NJ * 16 * * 17 * Glenn Fowler <gsf@research.att.com> * 18 * David Korn <dgk@research.att.com> * 19 * Phong Vo <kpv@research.att.com> * 20 * * 21 ***********************************************************************/ 22 #include "sfhdr.h" 23 static char* Version = "\n@(#)$Id: sfio (AT&T Research) 2006-02-07 $\0\n"; 24 25 /* Functions to set a given stream to some desired mode 26 ** 27 ** Written by Kiem-Phong Vo. 28 ** 29 ** Modifications: 30 ** 06/27/1990 (first version) 31 ** 01/06/1991 32 ** 07/08/1991 33 ** 06/18/1992 34 ** 02/02/1993 35 ** 05/25/1993 36 ** 02/07/1994 37 ** 05/21/1996 38 ** 08/01/1997 39 ** 08/01/1998 (extended formatting) 40 ** 09/09/1999 (thread-safe) 41 ** 02/01/2001 (adaptive buffering) 42 ** 05/31/2002 (multi-byte handling in sfvprintf/vscanf) 43 ** 09/06/2002 (SF_IOINTR flag) 44 ** 11/15/2002 (%#c for sfvprintf) 45 ** 05/31/2003 (sfsetbuf(f,f,align_size) to set alignment for data) 46 ** (%I1d is fixed to handle "signed char" correctly) 47 ** 01/01/2004 Porting issues to various platforms resolved. 48 */ 49 50 /* the below is for protecting the application from SIGPIPE */ 51 #if _PACKAGE_ast 52 #include <sig.h> 53 #include <wait.h> 54 #define Sfsignal_f Sig_handler_t 55 #else 56 #include <signal.h> 57 typedef void(* Sfsignal_f)_ARG_((int)); 58 #endif 59 static int _Sfsigp = 0; /* # of streams needing SIGPIPE protection */ 60 61 /* done at exiting time */ 62 #if __STD_C 63 static void _sfcleanup(void) 64 #else 65 static void _sfcleanup() 66 #endif 67 { 68 reg Sfpool_t* p; 69 reg Sfio_t* f; 70 reg int n; 71 reg int pool; 72 73 f = (Sfio_t*)Version; /* shut compiler warning */ 74 75 /* set this so that no more buffering is allowed for write streams */ 76 _Sfexiting = 1001; 77 78 sfsync(NIL(Sfio_t*)); 79 80 for(p = &_Sfpool; p; p = p->next) 81 { for(n = 0; n < p->n_sf; ++n) 82 { if(!(f = p->sf[n]) || SFFROZEN(f) ) 83 continue; 84 85 SFLOCK(f,0); 86 SFMTXLOCK(f); 87 88 /* let application know that we are leaving */ 89 (void)SFRAISE(f, SF_ATEXIT, NIL(Void_t*)); 90 91 if(f->flags&SF_STRING) 92 continue; 93 94 /* from now on, write streams are unbuffered */ 95 pool = f->mode&SF_POOL; 96 f->mode &= ~SF_POOL; 97 if((f->flags&SF_WRITE) && !(f->mode&SF_WRITE)) 98 (void)_sfmode(f,SF_WRITE,1); 99 if(((f->bits&SF_MMAP) && f->data) || 100 ((f->mode&SF_WRITE) && f->next == f->data) ) 101 (void)SFSETBUF(f,NIL(Void_t*),0); 102 f->mode |= pool; 103 104 SFMTXUNLOCK(f); 105 SFOPEN(f,0); 106 } 107 } 108 } 109 110 /* put into discrete pool */ 111 #if __STD_C 112 int _sfsetpool(Sfio_t* f) 113 #else 114 int _sfsetpool(f) 115 Sfio_t* f; 116 #endif 117 { 118 reg Sfpool_t* p; 119 reg Sfio_t** array; 120 reg int n, rv; 121 122 if(!_Sfcleanup) 123 { _Sfcleanup = _sfcleanup; 124 (void)atexit(_sfcleanup); 125 } 126 127 if(!(p = f->pool) ) 128 p = f->pool = &_Sfpool; 129 130 POOLMTXSTART(p); 131 132 rv = -1; 133 134 if(p->n_sf >= p->s_sf) 135 { if(p->s_sf == 0) /* initialize pool array */ 136 { p->s_sf = sizeof(p->array)/sizeof(p->array[0]); 137 p->sf = p->array; 138 } 139 else /* allocate a larger array */ 140 { n = (p->sf != p->array ? p->s_sf : (p->s_sf/4 + 1)*4) + 4; 141 if(!(array = (Sfio_t**)malloc(n*sizeof(Sfio_t*))) ) 142 goto done; 143 144 /* move old array to new one */ 145 memcpy((Void_t*)array,(Void_t*)p->sf,p->n_sf*sizeof(Sfio_t*)); 146 if(p->sf != p->array) 147 free((Void_t*)p->sf); 148 149 p->sf = array; 150 p->s_sf = n; 151 } 152 } 153 154 /* always add at end of array because if this was done during some sort 155 of walk thru all streams, we'll want the new stream to be seen. 156 */ 157 p->sf[p->n_sf++] = f; 158 rv = 0; 159 160 done: 161 POOLMTXRETURN(p, rv); 162 } 163 164 /* create an auxiliary buffer for sfgetr/sfreserve/sfputr */ 165 #if __STD_C 166 Sfrsrv_t* _sfrsrv(reg Sfio_t* f, reg ssize_t size) 167 #else 168 Sfrsrv_t* _sfrsrv(f,size) 169 reg Sfio_t* f; 170 reg ssize_t size; 171 #endif 172 { 173 Sfrsrv_t *rsrv, *rs; 174 175 /* make buffer if nothing yet */ 176 size = ((size + SF_GRAIN-1)/SF_GRAIN)*SF_GRAIN; 177 if(!(rsrv = f->rsrv) || size > rsrv->size) 178 { if(!(rs = (Sfrsrv_t*)malloc(size+sizeof(Sfrsrv_t)))) 179 size = -1; 180 else 181 { if(rsrv) 182 { if(rsrv->slen > 0) 183 memcpy(rs,rsrv,sizeof(Sfrsrv_t)+rsrv->slen); 184 free(rsrv); 185 } 186 f->rsrv = rsrv = rs; 187 rsrv->size = size; 188 rsrv->slen = 0; 189 } 190 } 191 192 if(rsrv && size > 0) 193 rsrv->slen = 0; 194 195 return size >= 0 ? rsrv : NIL(Sfrsrv_t*); 196 } 197 198 #ifdef SIGPIPE 199 #if __STD_C 200 static void ignoresig(int sig) 201 #else 202 static void ignoresig(sig) 203 int sig; 204 #endif 205 { 206 signal(sig, ignoresig); 207 } 208 #endif 209 210 #if __STD_C 211 int _sfpopen(reg Sfio_t* f, int fd, int pid, int stdio) 212 #else 213 int _sfpopen(f, fd, pid, stdio) 214 reg Sfio_t* f; 215 int fd; 216 int pid; 217 int stdio; /* stdio popen() does not reset SIGPIPE handler */ 218 #endif 219 { 220 reg Sfproc_t* p; 221 222 if(f->proc) 223 return 0; 224 225 if(!(p = f->proc = (Sfproc_t*)malloc(sizeof(Sfproc_t))) ) 226 return -1; 227 228 p->pid = pid; 229 p->size = p->ndata = 0; 230 p->rdata = NIL(uchar*); 231 p->file = fd; 232 p->sigp = (!stdio && pid >= 0 && (f->flags&SF_WRITE)) ? 1 : 0; 233 234 #ifdef SIGPIPE /* protect from broken pipe signal */ 235 if(p->sigp) 236 { Sfsignal_f handler; 237 238 (void)vtmtxlock(_Sfmutex); 239 if((handler = signal(SIGPIPE, ignoresig)) != SIG_DFL && 240 handler != ignoresig) 241 signal(SIGPIPE, handler); /* honor user handler */ 242 _Sfsigp += 1; 243 (void)vtmtxunlock(_Sfmutex); 244 } 245 #endif 246 247 return 0; 248 } 249 250 #if __STD_C 251 int _sfpclose(reg Sfio_t* f) 252 #else 253 int _sfpclose(f) 254 reg Sfio_t* f; /* stream to close */ 255 #endif 256 { 257 Sfproc_t* p; 258 int pid, status; 259 260 if(!(p = f->proc)) 261 return -1; 262 f->proc = NIL(Sfproc_t*); 263 264 if(p->rdata) 265 free(p->rdata); 266 267 if(p->pid < 0) 268 status = 0; 269 else 270 { /* close the associated stream */ 271 if(p->file >= 0) 272 CLOSE(p->file); 273 274 /* wait for process termination */ 275 #if _PACKAGE_ast 276 sigcritical(SIG_REG_EXEC|SIG_REG_PROC); 277 #endif 278 while ((pid = waitpid(p->pid,&status,0)) == -1 && errno == EINTR) 279 ; 280 if(pid == -1) 281 status = -1; 282 #if _PACKAGE_ast 283 sigcritical(0); 284 #endif 285 286 #ifdef SIGPIPE 287 (void)vtmtxlock(_Sfmutex); 288 if(p->sigp && (_Sfsigp -= 1) <= 0) 289 { Sfsignal_f handler; 290 if((handler = signal(SIGPIPE,SIG_DFL)) != SIG_DFL && 291 handler != ignoresig) 292 signal(SIGPIPE,handler); /* honor user handler */ 293 _Sfsigp = 0; 294 } 295 (void)vtmtxunlock(_Sfmutex); 296 #endif 297 } 298 299 free(p); 300 return status; 301 } 302 303 #if __STD_C 304 static int _sfpmode(Sfio_t* f, int type) 305 #else 306 static int _sfpmode(f,type) 307 Sfio_t* f; 308 int type; 309 #endif 310 { 311 Sfproc_t* p; 312 313 if(!(p = f->proc) ) 314 return -1; 315 316 if(type == SF_WRITE) 317 { /* save unread data */ 318 p->ndata = f->endb-f->next; 319 if(p->ndata > p->size) 320 { if(p->rdata) 321 free((char*)p->rdata); 322 if((p->rdata = (uchar*)malloc(p->ndata)) ) 323 p->size = p->ndata; 324 else 325 { p->size = 0; 326 return -1; 327 } 328 } 329 if(p->ndata > 0) 330 memcpy((Void_t*)p->rdata,(Void_t*)f->next,p->ndata); 331 f->endb = f->data; 332 } 333 else 334 { /* restore read data */ 335 if(p->ndata > f->size) /* may lose data!!! */ 336 p->ndata = f->size; 337 if(p->ndata > 0) 338 { memcpy((Void_t*)f->data,(Void_t*)p->rdata,p->ndata); 339 f->endb = f->data+p->ndata; 340 p->ndata = 0; 341 } 342 } 343 344 /* switch file descriptor */ 345 if(p->pid >= 0) 346 { type = f->file; 347 f->file = p->file; 348 p->file = type; 349 } 350 351 return 0; 352 } 353 354 #if __STD_C 355 int _sfmode(reg Sfio_t* f, reg int wanted, reg int local) 356 #else 357 int _sfmode(f, wanted, local) 358 reg Sfio_t* f; /* change r/w mode and sync file pointer for this stream */ 359 reg int wanted; /* desired mode */ 360 reg int local; /* a local call */ 361 #endif 362 { 363 reg int n; 364 Sfoff_t addr; 365 reg int rv = 0; 366 367 SFONCE(); /* initialize mutexes */ 368 369 if(wanted&SF_SYNCED) /* for (SF_SYNCED|SF_READ) stream, just junk data */ 370 { wanted &= ~SF_SYNCED; 371 if((f->mode&(SF_SYNCED|SF_READ)) == (SF_SYNCED|SF_READ) ) 372 { f->next = f->endb = f->endr = f->data; 373 f->mode &= ~SF_SYNCED; 374 } 375 } 376 377 if((!local && SFFROZEN(f)) || (!(f->flags&SF_STRING) && f->file < 0)) 378 { if(local || !f->disc || !f->disc->exceptf) 379 { local = 1; 380 goto err_notify; 381 } 382 383 for(;;) 384 { if((rv = (*f->disc->exceptf)(f,SF_LOCKED,0,f->disc)) < 0) 385 return rv; 386 if((!local && SFFROZEN(f)) || 387 (!(f->flags&SF_STRING) && f->file < 0) ) 388 { if(rv == 0) 389 { local = 1; 390 goto err_notify; 391 } 392 else continue; 393 } 394 else break; 395 } 396 } 397 398 if(f->mode&SF_GETR) 399 { f->mode &= ~SF_GETR; 400 #ifdef MAP_TYPE 401 if((f->bits&SF_MMAP) && (f->tiny[0] += 1) >= (4*SF_NMAP) ) 402 { /* turn off mmap to avoid page faulting */ 403 sfsetbuf(f,(Void_t*)f->tiny,(size_t)SF_UNBOUND); 404 f->tiny[0] = 0; 405 } 406 else 407 #endif 408 if(f->getr) 409 { f->next[-1] = f->getr; 410 f->getr = 0; 411 } 412 } 413 414 if(f->mode&SF_STDIO) /* synchronizing with stdio pointers */ 415 (*_Sfstdsync)(f); 416 417 if(f->disc == _Sfudisc && wanted == SF_WRITE && 418 sfclose((*_Sfstack)(f,NIL(Sfio_t*))) < 0 ) 419 { local = 1; 420 goto err_notify; 421 } 422 423 if(f->mode&SF_POOL) 424 { /* move to head of pool */ 425 if(f == f->pool->sf[0] || (*_Sfpmove)(f,0) < 0 ) 426 { local = 1; 427 goto err_notify; 428 } 429 f->mode &= ~SF_POOL; 430 } 431 432 SFLOCK(f,local); 433 434 /* buffer initialization */ 435 wanted &= SF_RDWR; 436 if(f->mode&SF_INIT) 437 { 438 if(!f->pool && _sfsetpool(f) < 0) 439 { rv = -1; 440 goto done; 441 } 442 443 if(wanted == 0) 444 goto done; 445 446 if(wanted != (int)(f->mode&SF_RDWR) && !(f->flags&wanted) ) 447 goto err_notify; 448 449 if((f->flags&SF_STRING) && f->size >= 0 && f->data) 450 { f->mode &= ~SF_INIT; 451 f->extent = ((f->flags&SF_READ) || (f->bits&SF_BOTH)) ? 452 f->size : 0; 453 f->here = 0; 454 f->endb = f->data + f->size; 455 f->next = f->endr = f->endw = f->data; 456 if(f->mode&SF_READ) 457 f->endr = f->endb; 458 else f->endw = f->endb; 459 } 460 else 461 { n = f->flags; 462 (void)SFSETBUF(f,f->data,f->size); 463 f->flags |= (n&SF_MALLOC); 464 } 465 } 466 467 if(wanted == (int)SFMODE(f,1)) 468 goto done; 469 470 switch(SFMODE(f,1)) 471 { 472 case SF_WRITE: /* switching to SF_READ */ 473 if(wanted == 0 || wanted == SF_WRITE) 474 break; 475 if(!(f->flags&SF_READ) ) 476 goto err_notify; 477 else if(f->flags&SF_STRING) 478 { SFSTRSIZE(f); 479 f->endb = f->data+f->extent; 480 f->mode = SF_READ; 481 break; 482 } 483 484 /* reset buffer */ 485 if(f->next > f->data && SFFLSBUF(f,-1) < 0) 486 goto err_notify; 487 488 if(f->size == 0) 489 { /* unbuffered */ 490 f->data = f->tiny; 491 f->size = sizeof(f->tiny); 492 } 493 f->next = f->endr = f->endw = f->endb = f->data; 494 f->mode = SF_READ|SF_LOCK; 495 496 /* restore saved read data for coprocess */ 497 if(f->proc && _sfpmode(f,wanted) < 0) 498 goto err_notify; 499 500 break; 501 502 case (SF_READ|SF_SYNCED): /* a previously sync-ed read stream */ 503 if(wanted != SF_WRITE) 504 { /* just reset the pointers */ 505 f->mode = SF_READ|SF_LOCK; 506 507 /* see if must go with new physical location */ 508 if((f->flags&(SF_SHARE|SF_PUBLIC)) == (SF_SHARE|SF_PUBLIC) && 509 (addr = SFSK(f,0,SEEK_CUR,f->disc)) != f->here) 510 { 511 #ifdef MAP_TYPE 512 if((f->bits&SF_MMAP) && f->data) 513 { SFMUNMAP(f,f->data,f->endb-f->data); 514 f->data = NIL(uchar*); 515 } 516 #endif 517 f->endb = f->endr = f->endw = f->next = f->data; 518 f->here = addr; 519 } 520 else 521 { addr = f->here + (f->endb - f->next); 522 if(SFSK(f,addr,SEEK_SET,f->disc) < 0) 523 goto err_notify; 524 f->here = addr; 525 } 526 527 break; 528 } 529 /* fall thru */ 530 531 case SF_READ: /* switching to SF_WRITE */ 532 if(wanted != SF_WRITE) 533 break; 534 else if(!(f->flags&SF_WRITE)) 535 goto err_notify; 536 else if(f->flags&SF_STRING) 537 { f->endb = f->data+f->size; 538 f->mode = SF_WRITE|SF_LOCK; 539 break; 540 } 541 542 /* save unread data before switching mode */ 543 if(f->proc && _sfpmode(f,wanted) < 0) 544 goto err_notify; 545 546 /* reset buffer and seek pointer */ 547 if(!(f->mode&SF_SYNCED) ) 548 { n = f->endb - f->next; 549 if(f->extent >= 0 && (n > 0 || (f->data && (f->bits&SF_MMAP))) ) 550 { /* reset file pointer */ 551 addr = f->here - n; 552 if(SFSK(f,addr,SEEK_SET,f->disc) < 0) 553 goto err_notify; 554 f->here = addr; 555 } 556 } 557 558 f->mode = SF_WRITE|SF_LOCK; 559 #ifdef MAP_TYPE 560 if(f->bits&SF_MMAP) 561 { if(f->data) 562 SFMUNMAP(f,f->data,f->endb-f->data); 563 (void)SFSETBUF(f,(Void_t*)f->tiny,(size_t)SF_UNBOUND); 564 } 565 #endif 566 if(f->data == f->tiny) 567 { f->endb = f->data = f->next = NIL(uchar*); 568 f->size = 0; 569 } 570 else f->endb = (f->next = f->data) + f->size; 571 572 break; 573 574 default: /* unknown case */ 575 err_notify: 576 if((wanted &= SF_RDWR) == 0 && (wanted = f->flags&SF_RDWR) == SF_RDWR) 577 wanted = SF_READ; 578 579 /* set errno for operations that access wrong stream type */ 580 if(wanted != (f->mode&SF_RDWR) && f->file >= 0) 581 errno = EBADF; 582 583 if(_Sfnotify) /* notify application of the error */ 584 (*_Sfnotify)(f,wanted,f->file); 585 586 rv = -1; 587 break; 588 } 589 590 done: 591 SFOPEN(f,local); 592 return rv; 593 } 594