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