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