static void start_filelist_progress(char *kind) { rprintf(FINFO, "%s ... ", kind); if (verbose > 1 || do_progress) rprintf(FINFO, "\n"); rflush(FINFO); }
/* {{{ 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 } }
/* 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; }
/* 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; }
/* 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; }
/** * @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); } }
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); }
static SCM api_rflush(SCM s_) { servlet *s = scm_to_pointer(s_); rflush(s); return SCM_UNSPECIFIED; }
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); }
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; }
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); }
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(); } }
/* * 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; }