Ejemplo n.º 1
0
Archivo: flist.c Proyecto: OPSF/uClinux
static void start_filelist_progress(char *kind)
{
	rprintf(FINFO, "%s ... ", kind);
	if (verbose > 1 || do_progress)
		rprintf(FINFO, "\n");
	rflush(FINFO);
}
Ejemplo n.º 2
0
/* {{{ sapi_apache_flush
 */
static void sapi_apache_flush(void *server_context)
{
	if (server_context) {
#if MODULE_MAGIC_NUMBER > 19970110
		rflush((request_rec *) server_context);
#else
		bflush((request_rec *) server_context->connection->client);
#endif
	}
}
Ejemplo n.º 3
0
/*
  We'll make it return the number of bytes sent
  so that we know if we need to send a body by default
*/
long send_fp_black(per_request *reqInfo, FILE *f, void (*onexit)(void))
{
    char *buf;
    long total_bytes_sent;
    register int n,o,w;
    int isHTML = FALSE;

    buf = newString(IOBUFSIZE,STR_TMP);
    exit_callback = onexit;
    signal(SIGALRM,send_fd_timed_out);
    signal(SIGPIPE,send_fd_timed_out);

    total_bytes_sent = 0;
    if (!strcmp(reqInfo->outh_content_type,"text/html")) {
      isHTML = TRUE;
      total_bytes_sent = rprintf(reqInfo,bodyTag);
    }
    rflush(reqInfo);
    while (1) {
        alarm(timeout);
        if((n=fread(buf,sizeof(char),IOBUFSIZE,f)) < 1) {
	   if (errno != EINTR) break;
        }

        o=0;
        if(reqInfo->bytes_sent != -1)
            reqInfo->bytes_sent += n;
        if (isHTML) {
	    sendBody(reqInfo,buf,n);
	    total_bytes_sent += n;
	    n = 0;
          }
        while(n) {
/*   Seems some systems have broken fwrite's (like AIX 3.2.5 on PowerPC)
 *   this should be a drop in replacement, maybe even be faster.
 *   For now, we'll just replace, but may have to #define one or the other
 *   depending on the system.
 */
	    if ((w=write(fileno(reqInfo->out),&buf[o],n)) < 0) {
	      if (errno != EINTR) break;
	    }
            n-=w;
            o+=w;
	    total_bytes_sent += w;
        }

    }
    if (isHTML) 
    rprintf(reqInfo,"<HR><a href=\"http://www.vtw.org/speech/\">My World Wide Web Pages are black for 48 hours to protest second-class treatment from the US Government for free speech.  Read about it at this WWW page.</a>");
    alarm(0);
    signal(SIGALRM,SIG_IGN);
    signal(SIGPIPE,SIG_IGN);
    freeString(buf);
    return total_bytes_sent;
}
Ejemplo n.º 4
0
/* send_fp(): sends a file pointer to the socket.  Uses fread to read,
 * but uses non-buffered I/O for writes (write())
 *
 * We'll make it return the number of bytes sent
 * so that we know if we need to send a body by default
 */
long send_fp(per_request *reqInfo, FILE *f, void (*onexit)(void))
{
    char *buf;
    long total_bytes_sent;
    register int n,o,w;
    /* ADC hack ZZZZ */
    /* blong Unused? */
    /* int i; */

    buf = newString(IOBUFSIZE,STR_TMP);
    exit_callback = onexit;
    signal(SIGALRM,send_fd_timed_out);
    signal(SIGPIPE,send_fd_timed_out);

    total_bytes_sent = 0;
    rflush(reqInfo);
    while (1) {
        alarm(timeout);
        if((n=fread(buf,sizeof(char),IOBUFSIZE,f)) < 1) {
	   if (errno != EINTR) break;
	    else errno = 0;
        }

        o=0;
        if(reqInfo->bytes_sent != -1)
            reqInfo->bytes_sent += n;
        while(n) {
/*   Seems some systems have broken fwrite's (like AIX 3.2.5 on PowerPC)
 *   this should be a drop in replacement, maybe even be faster.
 *   For now, we'll just replace, but may have to #define one or the other
 *   depending on the system.
 */
              w = write(fileno(reqInfo->out),&buf[o],n);
	    if (w < 0) {
	      if (errno != EINTR) break;
		else errno = 0;
	    }
				/* there goes ADC again...  ZZZZ */
/*
for (i = 0; i<w; i++) 
   fputc(buf[o+i],stderr);
fflush(stderr);
*/

            n-=w;
            o+=w;
	    total_bytes_sent += w;
        }
    }
    alarm(0);
    signal(SIGALRM,SIG_IGN);
    signal(SIGPIPE,SIG_IGN);
    freeString(buf);
    return total_bytes_sent;
}
Ejemplo n.º 5
0
/* 01Dec2004, Maiko, New function replaces 'Fail:' GOTO and labels */
static int do_Fail (int fd, struct asy *ap)
{
#ifndef HEADLESS
    rflush();		/* make sure the message gets out */
#endif
    if (fd != -1)
		close(fd);
    /* Unlock port */
    if (ap->uulock[0])
		unlink(ap->uulock);
    ap->uulock[0] = '\0';
    ap->iface = NULLIF;
    return -1;
}
Ejemplo n.º 6
0
/**
 * @param ofs Current position in file
 * @param size Total size of file
 * @param is_last True if this is the last time progress will be
 * printed for this file, so we should output a newline.  (Not
 * necessarily the same as all bytes being received.)
 **/
static void rprint_progress(OFF_T ofs, OFF_T size, struct timeval *now,
			    int is_last)
{
	char rembuf[64], eol[128];
	const char *units;
	unsigned long diff;
	double rate, remain;
	int pct;

	if (is_last) {
		int len = snprintf(eol, sizeof eol,
			" (xfr#%d, %s-chk=%d/%d)\n",
			stats.xferred_files, flist_eof ? "to" : "ir",
			stats.num_files - current_file_index - 1,
			stats.num_files);
		if (INFO_GTE(PROGRESS, 2)) {
			static int last_len = 0;
			/* Drop \n and pad with spaces if line got shorter. */
			if (last_len < --len)
				last_len = len;
			eol[last_len] = '\0';
			while (last_len > len)
				eol[--last_len] = ' ';
			is_last = 0;
		}
		/* Compute stats based on the starting info. */
		if (!ph_start.time.tv_sec
		    || !(diff = msdiff(&ph_start.time, now)))
			diff = 1;
		rate = (double) (ofs - ph_start.ofs) * 1000.0 / diff / 1024.0;
		/* Switch to total time taken for our last update. */
		remain = (double) diff / 1000.0;
	} else {
		strlcpy(eol, "  ", sizeof eol);
		/* Compute stats based on recent progress. */
		if (!(diff = msdiff(&ph_list[oldest_hpos].time, now)))
			diff = 1;
		rate = (double) (ofs - ph_list[oldest_hpos].ofs) * 1000.0
		     / diff / 1024.0;
		remain = rate ? (double) (size - ofs) / rate / 1000.0 : 0.0;
	}

	if (rate > 1024*1024) {
		rate /= 1024.0 * 1024.0;
		units = "GB/s";
	} else if (rate > 1024) {
		rate /= 1024.0;
		units = "MB/s";
	} else {
		units = "kB/s";
	}

	if (remain < 0)
		strlcpy(rembuf, "  ??:??:??", sizeof rembuf);
	else {
		snprintf(rembuf, sizeof rembuf, "%4d:%02d:%02d",
			 (int) (remain / 3600.0),
			 (int) (remain / 60.0) % 60,
			 (int) remain % 60);
	}

	output_needs_newline = 0;
	pct = ofs == size ? 100 : (int) (100.0 * ofs / size);
	rprintf(FCLIENT, "\r%15s %3d%% %7.2f%s %s%s",
		human_num(ofs), pct, rate, units, rembuf, eol);
	if (!is_last && !quiet) {
		output_needs_newline = 1;
		rflush(FCLIENT);
	}
}
Ejemplo n.º 7
0
Archivo: srv.c Proyecto: 99years/plan9
void
respond(Req *r, char *error)
{
	int i, m, n;
	char errbuf[ERRMAX];
	Srv *srv;

	srv = r->srv;
	assert(srv != nil);

	if(r->responded){
		assert(r->pool);
		goto free;
	}
		
	assert(r->responded == 0);
	r->error = error;

	switch(r->ifcall.type){
	default:
		assert(0);
	/*
	 * Flush is special.  If the handler says so, we return
	 * without further processing.  Respond will be called
	 * again once it is safe.
	 */
	case Tflush:
		if(rflush(r, error)<0)
			return;
		break;
	case Tversion:	rversion(r, error);	break;
	case Tauth:	rauth(r, error);	break;
	case Tattach:	rattach(r, error);	break;
	case Twalk:	rwalk(r, error);	break;
	case Topen:	ropen(r, error);	break;
	case Tcreate:	rcreate(r, error);	break;
	case Tread:	rread(r, error);	break;
	case Twrite:	rwrite(r, error);	break;
	case Tclunk:	rclunk(r, error);	break;
	case Tremove:	rremove(r, error, errbuf);	break;
	case Tstat:	rstat(r, error);	break;
	case Twstat:	rwstat(r, error);	break;
	}

	r->ofcall.tag = r->ifcall.tag;
	r->ofcall.type = r->ifcall.type+1;
	if(r->error)
		setfcallerror(&r->ofcall, r->error);

if(chatty9p)
	fprint(2, "-%d-> %F\n", srv->outfd, &r->ofcall);

	qlock(&srv->wlock);
	n = convS2M(&r->ofcall, srv->wbuf, srv->msize);
	if(n <= 0){
		fprint(2, "n = %d %F\n", n, &r->ofcall);
		abort();
	}
	assert(n > 2);
	/*
	 * There is a race here - we must remove the entry before
	 * the write, so that if the client is very fast and reuses the
	 * tag, the read loop won't think it is still in use.
	 * 
	 * By removing the entry before the write, we open up a 
	 * race with incoming Tflush messages.  Specifically, an
	 * incoming Tflush might not see r even though it has not
	 * yet been responded to.  It would then send an Rflush
	 * immediately, potentially before we do the write.  This can't
	 * happen because we already old srv->wlock, so nothing
	 * is going out on the wire before this write.
	 */
	if(r->pool)	/* not a fake */
		closereq(removereq(r->pool, r->ifcall.tag));

	qlock(&r->lk);
	r->responded = 1;
	if(r->pool)
	if(r->ref.ref == 1+r->nflush)
	if(r->fid){
		/*
		 * There are no references other than in our r->flush array,
		 * so no one else should be accessing r concurrently.
		 * Close the fid now, before responding to the message.
		 * 
		 * If the client is behaving (there are no outstanding T-messages
		 * that reference r->fid) and the message is a Tclunk or Tremove,
		 * then this closefid will call destroyfid.  
		 * 
		 * This means destroyfid can't piddle around 
		 * indefinitely (we're holding srv->wlock!), but it provides
		 * for tighter semantics as to when destroyfid is called.
		 *
		 * LANL has observed cases where waiting until after the write
		 * can delay a closefid on a Twrite for many 9P transactions,
		 * so that a handful of transactions can happen including a Tclunk
		 * and a Topen, and the original fid will still not be destroyed.
		 */
		closefid(r->fid);
		r->fid = nil;
	}
	qunlock(&r->lk);
	m = write(srv->outfd, srv->wbuf, n);
	if(m != n)
		sysfatal("lib9p srv: write %d returned %d on fd %d: %r", n, m, srv->outfd);
	qunlock(&srv->wlock);

free:
	qlock(&r->lk);	/* no one will add flushes now */

	for(i=0; i<r->nflush; i++){
		r->flush[i]->oldreq = nil;	/* so it doesn't try to lock us! */
		respond(r->flush[i], nil);
	}
	free(r->flush);
	r->flush = nil;
	r->nflush = 0;
	qunlock(&r->lk);

	if(r->pool)
		closereq(r);
	else
		free(r);
}
Ejemplo n.º 8
0
static SCM api_rflush(SCM s_)
{
  servlet *s = scm_to_pointer(s_);
  rflush(s);
  return SCM_UNSPECIFIED;
}
Ejemplo n.º 9
0
Archivo: srv.c Proyecto: npe9/harvey
void
respond(Req *r, char *error)
{
	int i, m, n;
	char errbuf[ERRMAX];
	Srv *srv;

	srv = r->srv;
	assert(srv != nil);

	assert(r->responded == 0);
	r->error = error;

	switch(r->ifcall.type){
	default:
		assert(0);
	/*
	 * Flush is special.  If the handler says so, we return
	 * without further processing.  Respond will be called
	 * again once it is safe.
	 */
	case Tflush:
		if(rflush(r, error)<0)
			return;
		break;
	case Tversion:	rversion(r, error);	break;
	case Tauth:	rauth(r, error);	break;
	case Tattach:	rattach(r, error);	break;
	case Twalk:	rwalk(r, error);	break;
	case Topen:	ropen(r, error);	break;
	case Tcreate:	rcreate(r, error);	break;
	case Tread:	rread(r, error);	break;
	case Twrite:	rwrite(r, error);	break;
	case Tclunk:	rclunk(r, error);	break;
	case Tremove:	rremove(r, error, errbuf);	break;
	case Tstat:	rstat(r, error);	break;
	case Twstat:	rwstat(r, error);	break;
	}

	r->ofcall.tag = r->ifcall.tag;
	r->ofcall.type = r->ifcall.type+1;
	if(r->error)
		setfcallerror(&r->ofcall, r->error);

if(chatty9p)
	fprint(2, "-%d-> %F\n", srv->outfd, &r->ofcall);

	qlock(&srv->wlock);
	n = convS2M(&r->ofcall, srv->wbuf, srv->msize);
	if(n <= 0){
		fprint(2, "n = %d %F\n", n, &r->ofcall);
		abort();
	}
	assert(n > 2);
	if(r->pool)	/* not a fake */
		closereq(removereq(r->pool, r->ifcall.tag));
	m = write(srv->outfd, srv->wbuf, n);
	if(m != n)
		sysfatal("lib9p srv: write %d returned %d on fd %d: %r", n, m, srv->outfd);
	qunlock(&srv->wlock);

	qlock(&r->lk);	/* no one will add flushes now */
	r->responded = 1;
	qunlock(&r->lk);

	for(i=0; i<r->nflush; i++)
		respond(r->flush[i], nil);
	free(r->flush);
	r->flush = nil;
	r->nflush = 0;

	if(r->pool)
		closereq(r);
	else
		free(r);
}
Ejemplo n.º 10
0
Archivo: cs.c Proyecto: brho/akaros
static void *job_thread(void *arg)
{
	struct mfile *mf;
	struct job *job = arg;

	spinlock_lock(&dblock);
	mf = newfid(job->request.fid);

	if (debug)
		fprintf(stderr, "CS:%F", &job->request);
	switch (job->request.type) {
	default:
		fprintf(stderr, "CS:unknown request type %d", job->request.type);
		break;
	case Tversion:
		rversion(job);
		break;
	case Tauth:
		rauth(job);
		break;
	case Tflush:
		rflush(job);
		break;
	case Tattach:
		rattach(job, mf);
		break;
	case Twalk:
		rwalk(job, mf);
		break;
	case Topen:
		ropen(job, mf);
		break;
	case Tcreate:
		rcreate(job, mf);
		break;
	case Tread:
		rread(job, mf);
		break;
	case Twrite:
		rwrite(job, mf);
		break;
	case Tclunk:
		rclunk(job, mf);
		break;
	case Tremove:
		rremove(job, mf);
		break;
	case Tstat:
		rstat(job, mf);
		break;
	case Twstat:
		rwstat(job, mf);
		break;
	}
	spinlock_unlock(&dblock);

	freejob(job);

	if (debug)
		fprintf(stderr, "CS:Job done\n");
	return 0;
}
Ejemplo n.º 11
0
void
io(void)
{
	volatile long n;
	volatile uchar mdata[IOHDRSZ + Maxfdata];
	Job *volatile job;
	Mfile *volatile mf;
	volatile Request req;

	memset(&req, 0, sizeof req);
	/*
	 *  a slave process is sometimes forked to wait for replies from other
	 *  servers.  The master process returns immediately via a longjmp
	 *  through 'mret'.
	 */
	if(setjmp(req.mret))
		putactivity(0);
	req.isslave = 0;
	stop = 0;
	while(!stop){
		procsetname("%d %s/dns Twrites of %d 9p rpcs read; %d alarms",
			stats.qrecvd9p, mntpt, stats.qrecvd9prpc, stats.alarms);
		n = read9pmsg(mfd[0], mdata, sizeof mdata);
		if(n<=0){
			dnslog("error reading 9P from %s: %r", mntpt);
			sleep(2000);	/* don't thrash after read error */
			return;
		}

		stats.qrecvd9prpc++;
		job = newjob();
		if(convM2S(mdata, n, &job->request) != n){
			freejob(job);
			continue;
		}
		mf = newfid(job->request.fid, 0);
		if(debug)
			dnslog("%F", &job->request);

		getactivity(&req, 0);
		req.aborttime = timems() + Maxreqtm;
		req.from = "9p";

		switch(job->request.type){
		default:
			warning("unknown request type %d", job->request.type);
			break;
		case Tversion:
			rversion(job);
			break;
		case Tauth:
			rauth(job);
			break;
		case Tflush:
			rflush(job);
			break;
		case Tattach:
			rattach(job, mf);
			break;
		case Twalk:
			rwalk(job, mf);
			break;
		case Topen:
			ropen(job, mf);
			break;
		case Tcreate:
			rcreate(job, mf);
			break;
		case Tread:
			rread(job, mf);
			break;
		case Twrite:
			/* &req is handed to dnresolve() */
			rwrite(job, mf, &req);
			break;
		case Tclunk:
			rclunk(job, mf);
			break;
		case Tremove:
			rremove(job, mf);
			break;
		case Tstat:
			rstat(job, mf);
			break;
		case Twstat:
			rwstat(job, mf);
			break;
		}

		freejob(job);

		/*
		 *  slave processes die after replying
		 */
		if(req.isslave){
			putactivity(0);
			_exits(0);
		}

		putactivity(0);
	}
	/* kill any udp server, notifier, etc. processes */
	postnote(PNGROUP, getpid(), "die");
	sleep(1000);
}
Ejemplo n.º 12
0
void
ioproc0(void *v)
{
	long n;
	Mfile *mf;
	uchar mdata[IOHDRSZ + Maxfdata];
	Request req;
	Job *job;

	USED(v);

	for(;;){
		n = read9pmsg(mfd[0], mdata, sizeof mdata);
		if(n <= 0){
			syslog(0, logfile, "error reading mntpt: %r");
			break;
		}
		job = newjob();
		if(convM2S(mdata, n, &job->request) != n){
			freejob(job);
			continue;
		}
		if(debug)
			syslog(0, logfile, "%F", &job->request);

		getactivity(&req);
		req.aborttime = now + 60;	/* don't spend more than 60 seconds */

		mf = nil;
		switch(job->request.type){
		case Tversion:
		case Tauth:
		case Tflush:
			break;
		case Tattach:
			mf = newfid(job->request.fid, 1);
			if(mf == nil){
				sendmsg(job, "fid in use");
				goto skip;
			}
			break;
		default:
			mf = newfid(job->request.fid, 0);
			if(mf == nil){
				sendmsg(job, "unknown fid");
				goto skip;
			}
			break;
		}

		switch(job->request.type){
		default:
			syslog(1, logfile, "unknown request type %d", job->request.type);
			break;
		case Tversion:
			rversion(job);
			break;
		case Tauth:
			rauth(job);
			break;
		case Tflush:
			rflush(job);
			break;
		case Tattach:
			rattach(job, mf);
			break;
		case Twalk:
			rwalk(job, mf);
			break;
		case Topen:
			ropen(job, mf);
			break;
		case Tcreate:
			rcreate(job, mf);
			break;
		case Tread:
			rread(job, mf);
			break;
		case Twrite:
			rwrite(job, mf, &req);
			break;
		case Tclunk:
			rclunk(job, mf);
			break;
		case Tremove:
			rremove(job, mf);
			break;
		case Tstat:
			rstat(job, mf);
			break;
		case Twstat:
			rwstat(job, mf);
			break;
		}
skip:
		freejob(job);
		putactivity();
	}
}
Ejemplo n.º 13
0
/*
 * If type==0, only last line of output is returned (exec)
 * If type==1, all lines will be printed and last lined returned (system)
 * If type==2, all lines will be saved to given array (exec with &$array)
 * If type==3, output will be printed binary, no lines will be saved or returned (passthru)
 *
 */
static int _Exec(int type, char *cmd, pval *array, pval *return_value)
{
	FILE *fp;
	char *buf, *tmp=NULL;
    int buflen=0;
	int t, l, ret, output=1;
	int overflow_limit, lcmd, ldir;
	char *b, *c, *d=NULL;
	TLS_VARS;

    buf = (char*) emalloc(EXEC_INPUT_BUF);
    if (!buf) {
		php3_error(E_WARNING, "Unable to emalloc %d bytes", EXEC_INPUT_BUF);
		return -1;
    }
    buflen = EXEC_INPUT_BUF;

#ifdef WIN32
	(void)AllocConsole(); /* We don't care if this fails. */
#endif

	if (php3_ini.safe_mode) {
		lcmd = strlen(cmd);
		ldir = strlen(php3_ini.safe_mode_exec_dir);
		l = lcmd + ldir + 2;
		overflow_limit = l;
		c = strchr(cmd, ' ');
		if (c) *c = '\0';
		if (strstr(cmd, "..")) {
			php3_error(E_WARNING, "No '..' components allowed in path");
            efree(buf);
			return -1;
		}
		d = emalloc(l);
		strcpy(d, php3_ini.safe_mode_exec_dir);
		overflow_limit -= ldir;
		b = strrchr(cmd, '/');
		if (b) {
			strcat(d, b);
			overflow_limit -= strlen(b);
		} else {
			strcat(d, "/");
			strcat(d, cmd);
			overflow_limit-=(strlen(cmd)+1);
		}
		if (c) {
			*c = ' ';
			strncat(d, c, overflow_limit);
		}
		tmp = _php3_escapeshellcmd(d);
		efree(d);
		d = tmp;
#if WIN32|WINNT
		fp = popen(d, "rb");
#else
		fp = popen(d, "r");
#endif
		if (!fp) {
			php3_error(E_WARNING, "Unable to fork [%s]", d);
			efree(d);
            efree(buf);
			return -1;
		}
	} else { /* not safe_mode */
#if WIN32|WINNT
		fp = popen(cmd, "rb");
#else
		fp = popen(cmd, "r");
#endif
		if (!fp) {
			php3_error(E_WARNING, "Unable to fork [%s]", cmd);
            efree(buf);
			return -1;
		}
	}
	buf[0] = '\0';
	if (type == 1 || type == 3) {
		output=php3_header();
	}
	if (type==2) {
		if (array->type != IS_ARRAY) {
			pval_destructor(array _INLINE_TLS);
			array_init(array);
		}
	}
	if (type != 3) {
		l = 0;
		while ( !feof(fp) || l != 0 ) {
			l = 0;
			/* Read a line or fill the buffer, whichever comes first */
			do {
				if ( buflen <= (l+1) ) {
					buf = erealloc(buf, buflen + EXEC_INPUT_BUF);
					if ( buf == NULL ) {
						php3_error(E_WARNING, "Unable to erealloc %d bytes", 
								buflen + EXEC_INPUT_BUF);
						return -1;
					}
					buflen += EXEC_INPUT_BUF;
				}

				if ( fgets(&(buf[l]), buflen - l, fp) == NULL ) {
					/* eof */
					break;
				}
				l += strlen(&(buf[l]));
			} while ( (l > 0) && (buf[l-1] != '\n') );

			if ( feof(fp) && (l == 0) ) {
				break;
			}

			if (type == 1) {
				if (output) PUTS(buf);
#if APACHE
#  if MODULE_MAGIC_NUMBER > 19970110
				if (output) rflush(GLOBAL(php3_rqst));
#  else
				if (output) bflush(GLOBAL(php3_rqst)->connection->client);
#  endif
#endif
#if CGI_BINARY
				fflush(stdout);
#endif
#if FHTTPD
                               /* fhttpd doesn't flush */
#endif
#if USE_SAPI
				GLOBAL(sapi_rqst)->flush(GLOBAL(sapi_rqst)->scid);
#endif
			}
			else if (type == 2) {
				pval tmp;
			
				/* strip trailing whitespaces */	
				l = strlen(buf);
				t = l;
				while (l-- && isspace((int)buf[l]));
				if (l < t) buf[l + 1] = '\0';
				tmp.value.str.len = strlen(buf);
				tmp.value.str.val = estrndup(buf,tmp.value.str.len);
				tmp.type = IS_STRING;
				_php3_hash_next_index_insert(array->value.ht,(void *) &tmp, sizeof(pval), NULL);
			}
		}

		/* strip trailing spaces */
		l = strlen(buf);
		t = l;
		while (l && isspace((int)buf[--l]));
		if (l < t) buf[l + 1] = '\0';

		/* Return last line from the shell command */
		if(php3_ini.magic_quotes_runtime) {
			int len;
		
			tmp = _php3_addslashes(buf, 0, &len, 0);
			RETVAL_STRINGL(tmp,len,0);
		} else {
			RETVAL_STRINGL(buf,l+1,1);
		}
	} else {
		int b, i;

		while ((b = fread(buf, 1, buflen, fp)) > 0) {
			for (i = 0; i < b; i++)
				if (output) PUTC(buf[i]);
		}
	}

	ret = pclose(fp);
#ifdef HAVE_SYS_WAIT_H
	if (WIFEXITED(ret)) {
		ret = WEXITSTATUS(ret);
	}
#endif

	if (d) efree(d);
    efree(buf);
	return ret;
}