mirror of
git://git.code.sf.net/p/cdesktopenv/code
synced 2025-03-09 15:50:02 +00:00
This commit applies various accumulated bugfixes: - Applied some fixes for compiler warnings based off of the following pull requests (with whitespace changes excluded to avoid inflating the size of the diff): https://github.com/att/ast/pull/281 https://github.com/att/ast/pull/283 https://github.com/att/ast/pull/303 https://github.com/att/ast/pull/304 - clone_type(): Two separate variables in this function share the same name. A bugfix from ksh93v- 2013-05-24 was backported to avoid conflict issues. - Backported a minor error message improvement from ksh2020 for when the user attempts to run too many coprocesses. - Backported a ksh2020 bugfix for a file descriptor leak:58bc8b56- Backported ksh2020 bugfixes for unused variable and pointless assignment lint warnings:47650fe0df209c0d5e417b00- Applied a few minor improvements to libast from graphviz:e7c03541969a7cde- dtmemory(): Mark unused parameters with NOT_USED(). Based on:6ac3ad99- Applied a few documentation/comment tweaks for the NEWS file, printf -v and spawnveg. - Added a missing regression test for using the rm builtin's -f option without additional arguments (this was fixed in ksh93u+ 2012-02-14).
563 lines
13 KiB
C
563 lines
13 KiB
C
/***********************************************************************
|
|
* *
|
|
* This software is part of the ast package *
|
|
* Copyright (c) 1985-2012 AT&T Intellectual Property *
|
|
* Copyright (c) 2020-2022 Contributors to ksh 93u+m *
|
|
* and is licensed under the *
|
|
* Eclipse Public License, Version 1.0 *
|
|
* by AT&T Intellectual Property *
|
|
* *
|
|
* A copy of the License is available at *
|
|
* http://www.eclipse.org/org/documents/epl-v10.html *
|
|
* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
|
|
* *
|
|
* Information and Software Systems Research *
|
|
* AT&T Research *
|
|
* Florham Park NJ *
|
|
* *
|
|
* Glenn Fowler <gsf@research.att.com> *
|
|
* David Korn <dgk@research.att.com> *
|
|
* Phong Vo <kpv@research.att.com> *
|
|
* *
|
|
***********************************************************************/
|
|
#include "sfhdr.h"
|
|
static char* Version = "\n@(#)$Id: sfio (AT&T Labs - Research) 2009-09-15 $\0\n";
|
|
|
|
/* Functions to set a given stream to some desired mode
|
|
**
|
|
** Written by Kiem-Phong Vo.
|
|
**
|
|
** Modifications:
|
|
** 06/27/1990 (first version)
|
|
** 01/06/1991
|
|
** 07/08/1991
|
|
** 06/18/1992
|
|
** 02/02/1993
|
|
** 05/25/1993
|
|
** 02/07/1994
|
|
** 05/21/1996
|
|
** 08/01/1997
|
|
** 08/01/1998 (extended formatting)
|
|
** 09/09/1999 (thread-safe)
|
|
** 02/01/2001 (adaptive buffering)
|
|
** 05/31/2002 (multi-byte handling in sfvprintf/vscanf)
|
|
** 09/06/2002 (SF_IOINTR flag)
|
|
** 11/15/2002 (%#c for sfvprintf)
|
|
** 05/31/2003 (sfsetbuf(f,f,align_size) to set alignment for data)
|
|
** (%I1d is fixed to handle "signed char" correctly)
|
|
** 01/01/2004 Porting issues to various platforms resolved.
|
|
** 06/01/2008 Allowing notify() at entering/exiting thread-safe routines.
|
|
** 09/15/2008 Add sfwalk().
|
|
*/
|
|
|
|
/* the below is for protecting the application from SIGPIPE */
|
|
#if _PACKAGE_ast
|
|
#include <sig.h>
|
|
#include <wait.h>
|
|
#define Sfsignal_f Sig_handler_t
|
|
#else
|
|
#include <signal.h>
|
|
typedef void(* Sfsignal_f)(int);
|
|
#endif
|
|
#ifdef SIGPIPE
|
|
static int _Sfsigp = 0; /* # of streams needing SIGPIPE protection */
|
|
#endif
|
|
|
|
/* done at exiting time */
|
|
static void _sfcleanup(void)
|
|
{
|
|
reg Sfpool_t* p;
|
|
reg Sfio_t* f;
|
|
reg int n;
|
|
reg int pool;
|
|
|
|
f = (Sfio_t*)Version; /* shut compiler warning */
|
|
|
|
/* set this so that no more buffering is allowed for write streams */
|
|
_Sfexiting = 1001;
|
|
|
|
sfsync(NIL(Sfio_t*));
|
|
|
|
for(p = &_Sfpool; p; p = p->next)
|
|
{ for(n = 0; n < p->n_sf; ++n)
|
|
{ if(!(f = p->sf[n]) || SFFROZEN(f) )
|
|
continue;
|
|
|
|
SFLOCK(f,0);
|
|
SFMTXLOCK(f);
|
|
|
|
/* let application know that we are leaving */
|
|
(void)SFRAISE(f, SF_ATEXIT, NIL(void*));
|
|
|
|
if(f->flags&SF_STRING)
|
|
continue;
|
|
|
|
/* from now on, write streams are unbuffered */
|
|
pool = f->mode&SF_POOL;
|
|
f->mode &= ~SF_POOL;
|
|
if((f->flags&SF_WRITE) && !(f->mode&SF_WRITE))
|
|
(void)_sfmode(f,SF_WRITE,1);
|
|
if(f->data &&
|
|
((f->bits&SF_MMAP) ||
|
|
((f->mode&SF_WRITE) && f->next == f->data) ) )
|
|
(void)SFSETBUF(f,NIL(void*),0);
|
|
f->mode |= pool;
|
|
|
|
SFMTXUNLOCK(f);
|
|
SFOPEN(f,0);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* put into discrete pool */
|
|
int _sfsetpool(Sfio_t* f)
|
|
{
|
|
reg Sfpool_t* p;
|
|
reg Sfio_t** array;
|
|
reg int n, rv;
|
|
|
|
if(!_Sfcleanup)
|
|
{ _Sfcleanup = _sfcleanup;
|
|
(void)atexit(_sfcleanup);
|
|
}
|
|
|
|
if(!(p = f->pool) )
|
|
p = f->pool = &_Sfpool;
|
|
|
|
POOLMTXENTER(p);
|
|
|
|
rv = -1;
|
|
|
|
if(p->n_sf >= p->s_sf)
|
|
{ if(p->s_sf == 0) /* initialize pool array */
|
|
{ p->s_sf = sizeof(p->array)/sizeof(p->array[0]);
|
|
p->sf = p->array;
|
|
}
|
|
else /* allocate a larger array */
|
|
{ n = (p->sf != p->array ? p->s_sf : (p->s_sf/4 + 1)*4) + 4;
|
|
if(!(array = (Sfio_t**)malloc(n*sizeof(Sfio_t*))) )
|
|
goto done;
|
|
|
|
/* move old array to new one */
|
|
memcpy((void*)array,(void*)p->sf,p->n_sf*sizeof(Sfio_t*));
|
|
if(p->sf != p->array)
|
|
free((void*)p->sf);
|
|
|
|
p->sf = array;
|
|
p->s_sf = n;
|
|
}
|
|
}
|
|
|
|
/* always add at end of array because if this was done during some sort
|
|
of walk through all streams, we'll want the new stream to be seen.
|
|
*/
|
|
p->sf[p->n_sf++] = f;
|
|
rv = 0;
|
|
|
|
done:
|
|
POOLMTXRETURN(p, rv);
|
|
}
|
|
|
|
/* create an auxiliary buffer for sfgetr/sfreserve/sfputr */
|
|
Sfrsrv_t* _sfrsrv(reg Sfio_t* f, reg ssize_t size)
|
|
{
|
|
Sfrsrv_t *rsrv, *rs;
|
|
|
|
/* make buffer if nothing yet */
|
|
size = ((size + SF_GRAIN-1)/SF_GRAIN)*SF_GRAIN;
|
|
if(!(rsrv = f->rsrv) || size > rsrv->size)
|
|
{ if(!(rs = (Sfrsrv_t*)malloc(size+sizeof(Sfrsrv_t))))
|
|
size = -1;
|
|
else
|
|
{ if(rsrv)
|
|
{ if(rsrv->slen > 0)
|
|
memcpy(rs,rsrv,sizeof(Sfrsrv_t)+rsrv->slen);
|
|
free(rsrv);
|
|
}
|
|
f->rsrv = rsrv = rs;
|
|
rsrv->size = size;
|
|
rsrv->slen = 0;
|
|
}
|
|
}
|
|
|
|
if(rsrv && size > 0)
|
|
rsrv->slen = 0;
|
|
|
|
return size >= 0 ? rsrv : NIL(Sfrsrv_t*);
|
|
}
|
|
|
|
#ifdef SIGPIPE
|
|
static void ignoresig(int sig)
|
|
{
|
|
signal(sig, ignoresig);
|
|
}
|
|
#endif
|
|
|
|
int _sfpopen(reg Sfio_t* f, int fd, int pid, int stdio) /* stdio popen() does not reset SIGPIPE handler */
|
|
{
|
|
reg Sfproc_t* p;
|
|
|
|
if(f->proc)
|
|
return 0;
|
|
|
|
if(!(p = f->proc = (Sfproc_t*)malloc(sizeof(Sfproc_t))) )
|
|
return -1;
|
|
|
|
p->pid = pid;
|
|
p->size = p->ndata = 0;
|
|
p->rdata = NIL(uchar*);
|
|
p->file = fd;
|
|
p->sigp = (!stdio && pid >= 0 && (f->flags&SF_WRITE)) ? 1 : 0;
|
|
|
|
#ifdef SIGPIPE /* protect from broken pipe signal */
|
|
if(p->sigp)
|
|
{ Sfsignal_f handler;
|
|
|
|
(void)vtmtxlock(_Sfmutex);
|
|
if((handler = signal(SIGPIPE, ignoresig)) != SIG_DFL &&
|
|
handler != ignoresig)
|
|
signal(SIGPIPE, handler); /* honor user handler */
|
|
_Sfsigp += 1;
|
|
(void)vtmtxunlock(_Sfmutex);
|
|
}
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
int _sfpclose(reg Sfio_t* f)
|
|
{
|
|
Sfproc_t* p;
|
|
int status;
|
|
|
|
if(!(p = f->proc))
|
|
return -1;
|
|
f->proc = NIL(Sfproc_t*);
|
|
|
|
if(p->rdata)
|
|
free(p->rdata);
|
|
|
|
if(p->pid < 0)
|
|
status = 0;
|
|
else
|
|
{ /* close the associated stream */
|
|
if(p->file >= 0)
|
|
CLOSE(p->file);
|
|
|
|
/* wait for process termination */
|
|
#if _PACKAGE_ast
|
|
sigcritical(SIG_REG_EXEC|SIG_REG_PROC);
|
|
#endif
|
|
status = -1;
|
|
while (waitpid(p->pid,&status,0) == -1 && errno == EINTR)
|
|
;
|
|
#if _PACKAGE_ast
|
|
status = status == -1 ?
|
|
EXIT_QUIT :
|
|
WIFSIGNALED(status) ?
|
|
EXIT_TERM(WTERMSIG(status)) :
|
|
EXIT_CODE(WEXITSTATUS(status));
|
|
sigcritical(0);
|
|
#endif
|
|
|
|
#ifdef SIGPIPE
|
|
(void)vtmtxlock(_Sfmutex);
|
|
if(p->sigp && (_Sfsigp -= 1) <= 0)
|
|
{ Sfsignal_f handler;
|
|
if((handler = signal(SIGPIPE,SIG_DFL)) != SIG_DFL &&
|
|
handler != ignoresig)
|
|
signal(SIGPIPE,handler); /* honor user handler */
|
|
_Sfsigp = 0;
|
|
}
|
|
(void)vtmtxunlock(_Sfmutex);
|
|
#endif
|
|
}
|
|
|
|
free(p);
|
|
return status;
|
|
}
|
|
|
|
static int _sfpmode(Sfio_t* f, int type)
|
|
{
|
|
Sfproc_t* p;
|
|
|
|
if(!(p = f->proc) )
|
|
return -1;
|
|
|
|
if(type == SF_WRITE)
|
|
{ /* save unread data */
|
|
p->ndata = f->endb-f->next;
|
|
if(p->ndata > p->size)
|
|
{ if(p->rdata)
|
|
free((char*)p->rdata);
|
|
if((p->rdata = (uchar*)malloc(p->ndata)) )
|
|
p->size = p->ndata;
|
|
else
|
|
{ p->size = 0;
|
|
return -1;
|
|
}
|
|
}
|
|
if(p->ndata > 0)
|
|
memcpy((void*)p->rdata,(void*)f->next,p->ndata);
|
|
f->endb = f->data;
|
|
}
|
|
else
|
|
{ /* restore read data */
|
|
if(p->ndata > f->size) /* may lose data!!! */
|
|
p->ndata = f->size;
|
|
if(p->ndata > 0)
|
|
{ memcpy((void*)f->data,(void*)p->rdata,p->ndata);
|
|
f->endb = f->data+p->ndata;
|
|
p->ndata = 0;
|
|
}
|
|
}
|
|
|
|
/* switch file descriptor */
|
|
if(p->pid >= 0)
|
|
{ type = f->file;
|
|
f->file = p->file;
|
|
p->file = type;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int _sfmode(reg Sfio_t* f, /* change r/w mode and sync file pointer for this stream */
|
|
reg int wanted, /* desired mode */
|
|
reg int local) /* a local call */
|
|
{
|
|
reg int n;
|
|
Sfoff_t addr;
|
|
reg int rv = 0;
|
|
|
|
SFONCE(); /* initialize mutexes */
|
|
|
|
if(wanted&SF_SYNCED) /* for (SF_SYNCED|SF_READ) stream, just junk data */
|
|
{ wanted &= ~SF_SYNCED;
|
|
if((f->mode&(SF_SYNCED|SF_READ)) == (SF_SYNCED|SF_READ) )
|
|
{ f->next = f->endb = f->endr = f->data;
|
|
f->mode &= ~SF_SYNCED;
|
|
}
|
|
}
|
|
|
|
if((!local && SFFROZEN(f)) || (!(f->flags&SF_STRING) && f->file < 0))
|
|
{ if(local || !f->disc || !f->disc->exceptf)
|
|
{ local = 1;
|
|
goto err_notify;
|
|
}
|
|
|
|
for(;;)
|
|
{ if((rv = (*f->disc->exceptf)(f,SF_LOCKED,0,f->disc)) < 0)
|
|
return rv;
|
|
if((!local && SFFROZEN(f)) ||
|
|
(!(f->flags&SF_STRING) && f->file < 0) )
|
|
{ if(rv == 0)
|
|
{ local = 1;
|
|
goto err_notify;
|
|
}
|
|
else continue;
|
|
}
|
|
else break;
|
|
}
|
|
}
|
|
|
|
if(f->mode&SF_GETR)
|
|
{ f->mode &= ~SF_GETR;
|
|
#ifdef MAP_TYPE
|
|
if(f->bits&SF_MMAP)
|
|
{
|
|
if (!++f->ngetr)
|
|
f->tiny[0]++;
|
|
if(((f->tiny[0]<<8)|f->ngetr) >= (4*SF_NMAP) )
|
|
{ /* turn off mmap to avoid page faulting */
|
|
sfsetbuf(f,(void*)f->tiny,(size_t)SF_UNBOUND);
|
|
f->ngetr = f->tiny[0] = 0;
|
|
}
|
|
}
|
|
#endif
|
|
if(f->getr)
|
|
{ f->next[-1] = f->getr;
|
|
f->getr = 0;
|
|
}
|
|
}
|
|
|
|
if(f->mode&SF_STDIO) /* synchronizing with stdio pointers */
|
|
(*_Sfstdsync)(f);
|
|
|
|
if(f->disc == _Sfudisc && wanted == SF_WRITE &&
|
|
sfclose((*_Sfstack)(f,NIL(Sfio_t*))) < 0 )
|
|
{ local = 1;
|
|
goto err_notify;
|
|
}
|
|
|
|
if(f->mode&SF_POOL)
|
|
{ /* move to head of pool */
|
|
if(f == f->pool->sf[0] || (*_Sfpmove)(f,0) < 0 )
|
|
{ local = 1;
|
|
goto err_notify;
|
|
}
|
|
f->mode &= ~SF_POOL;
|
|
}
|
|
|
|
SFLOCK(f,local);
|
|
|
|
/* buffer initialization */
|
|
wanted &= SF_RDWR;
|
|
if(f->mode&SF_INIT)
|
|
{
|
|
if(!f->pool && _sfsetpool(f) < 0)
|
|
{ rv = -1;
|
|
goto done;
|
|
}
|
|
|
|
if(wanted == 0)
|
|
goto done;
|
|
|
|
if(wanted != (int)(f->mode&SF_RDWR) && !(f->flags&wanted) )
|
|
goto err_notify;
|
|
|
|
if((f->flags&SF_STRING) && f->size >= 0 && f->data)
|
|
{ f->mode &= ~SF_INIT;
|
|
f->extent = ((f->flags&SF_READ) || (f->bits&SF_BOTH)) ?
|
|
f->size : 0;
|
|
f->here = 0;
|
|
f->endb = f->data + f->size;
|
|
f->next = f->endr = f->endw = f->data;
|
|
if(f->mode&SF_READ)
|
|
f->endr = f->endb;
|
|
else f->endw = f->endb;
|
|
}
|
|
else
|
|
{ n = f->flags;
|
|
(void)SFSETBUF(f,f->data,f->size);
|
|
f->flags |= (n&SF_MALLOC);
|
|
}
|
|
}
|
|
|
|
if(wanted == (int)SFMODE(f,1))
|
|
goto done;
|
|
|
|
switch(SFMODE(f,1))
|
|
{
|
|
case SF_WRITE: /* switching to SF_READ */
|
|
if(wanted == 0 || wanted == SF_WRITE)
|
|
break;
|
|
if(!(f->flags&SF_READ) )
|
|
goto err_notify;
|
|
else if(f->flags&SF_STRING)
|
|
{ SFSTRSIZE(f);
|
|
f->endb = f->data+f->extent;
|
|
f->mode = SF_READ;
|
|
break;
|
|
}
|
|
|
|
/* reset buffer */
|
|
if(f->next > f->data && SFFLSBUF(f,-1) < 0)
|
|
goto err_notify;
|
|
|
|
if(f->size == 0)
|
|
{ /* unbuffered */
|
|
f->data = f->tiny;
|
|
f->size = sizeof(f->tiny);
|
|
}
|
|
f->next = f->endr = f->endw = f->endb = f->data;
|
|
f->mode = SF_READ|SF_LOCK;
|
|
|
|
/* restore saved read data for coprocess */
|
|
if(f->proc && _sfpmode(f,wanted) < 0)
|
|
goto err_notify;
|
|
|
|
break;
|
|
|
|
case (SF_READ|SF_SYNCED): /* a previously sync-ed read stream */
|
|
if(wanted != SF_WRITE)
|
|
{ /* just reset the pointers */
|
|
f->mode = SF_READ|SF_LOCK;
|
|
|
|
/* see if must go with new physical location */
|
|
if((f->flags&(SF_SHARE|SF_PUBLIC)) == (SF_SHARE|SF_PUBLIC) &&
|
|
(addr = SFSK(f,0,SEEK_CUR,f->disc)) != f->here)
|
|
{
|
|
#ifdef MAP_TYPE
|
|
if((f->bits&SF_MMAP) && f->data)
|
|
{ SFMUNMAP(f,f->data,f->endb-f->data);
|
|
f->data = NIL(uchar*);
|
|
}
|
|
#endif
|
|
f->endb = f->endr = f->endw = f->next = f->data;
|
|
f->here = addr;
|
|
}
|
|
else
|
|
{ addr = f->here + (f->endb - f->next);
|
|
if(SFSK(f,addr,SEEK_SET,f->disc) < 0)
|
|
goto err_notify;
|
|
f->here = addr;
|
|
}
|
|
|
|
break;
|
|
}
|
|
/* FALLTHROUGH */
|
|
|
|
case SF_READ: /* switching to SF_WRITE */
|
|
if(wanted != SF_WRITE)
|
|
break;
|
|
else if(!(f->flags&SF_WRITE))
|
|
goto err_notify;
|
|
else if(f->flags&SF_STRING)
|
|
{ f->endb = f->data+f->size;
|
|
f->mode = SF_WRITE|SF_LOCK;
|
|
break;
|
|
}
|
|
|
|
/* save unread data before switching mode */
|
|
if(f->proc && _sfpmode(f,wanted) < 0)
|
|
goto err_notify;
|
|
|
|
/* reset buffer and seek pointer */
|
|
if(!(f->mode&SF_SYNCED) )
|
|
{ n = f->endb - f->next;
|
|
if(f->extent >= 0 && (n > 0 || (f->data && (f->bits&SF_MMAP))) )
|
|
{ /* reset file pointer */
|
|
addr = f->here - n;
|
|
if(SFSK(f,addr,SEEK_SET,f->disc) < 0)
|
|
goto err_notify;
|
|
f->here = addr;
|
|
}
|
|
}
|
|
|
|
f->mode = SF_WRITE|SF_LOCK;
|
|
#ifdef MAP_TYPE
|
|
if(f->bits&SF_MMAP)
|
|
{ if(f->data)
|
|
SFMUNMAP(f,f->data,f->endb-f->data);
|
|
(void)SFSETBUF(f,(void*)f->tiny,(size_t)SF_UNBOUND);
|
|
}
|
|
#endif
|
|
if(f->data == f->tiny)
|
|
{ f->endb = f->data = f->next = NIL(uchar*);
|
|
f->size = 0;
|
|
}
|
|
else f->endb = (f->next = f->data) + f->size;
|
|
|
|
break;
|
|
|
|
default: /* unknown case */
|
|
err_notify:
|
|
if((wanted &= SF_RDWR) == 0 && (wanted = f->flags&SF_RDWR) == SF_RDWR)
|
|
wanted = SF_READ;
|
|
|
|
/* set errno for operations that access wrong stream type */
|
|
if(wanted != (f->mode&SF_RDWR) && f->file >= 0)
|
|
errno = EBADF;
|
|
|
|
if(_Sfnotify) /* notify application of the error */
|
|
(*_Sfnotify)(f, wanted, (void*)((long)f->file));
|
|
|
|
rv = -1;
|
|
break;
|
|
}
|
|
|
|
done:
|
|
SFOPEN(f,local);
|
|
return rv;
|
|
}
|