Beispiel #1
0
 // takes an entry that was written _logTransactionOps
 // and applies them to collections
 //
 // TODO: possibly improve performance of this. We create and destroy a
 // context for each operation. Find a way to amortize it out if necessary
 //
 void applyTransactionFromOplog(BSONObj entry) {
     bool transactionAlreadyApplied = entry["a"].Bool();
     if (!transactionAlreadyApplied) {
         Client::Transaction transaction(DB_SERIALIZABLE);
         if (entry.hasElement("ref")) {
             applyRefOp(entry);
         } else if (entry.hasElement("ops")) {
             applyOps(entry["ops"].Array());
         } else {
             verify(0);
         }
         // set the applied bool to true, to let the oplog know that
         // this entry has been applied to collections
         BSONElementManipulator(entry["a"]).setBool(true);
         {
             LOCK_REASON(lockReason, "repl: setting oplog entry's applied bit");
             Lock::DBRead lk1("local", lockReason);
             writeEntryToOplog(entry, false);
         }
         // If this code fails, it is impossible to recover from
         // because we don't know if the transaction successfully committed
         // so we might as well crash
         // There is currently no known way this code can throw an exception
         try {
             // we are operating as a secondary. We don't have to fsync
             transaction.commit(DB_TXN_NOSYNC);
         }
         catch (std::exception &e) {
             log() << "exception during commit of applyTransactionFromOplog, aborting system: " << e.what() << endl;
             printStackTrace();
             logflush();
             ::abort();
         }
     }
 }
Beispiel #2
0
Datei: log.c Projekt: aixoss/wget
void
logputs (enum log_options o, const char *s)
{
  FILE *fp;
  FILE *warcfp;

  check_redirect_output ();
  if (o == LOG_PROGRESS)
    fp = get_progress_fp ();
  else
    fp = get_log_fp ();

  if (fp == NULL)
    return;

  warcfp = get_warc_log_fp ();
  CHECK_VERBOSE (o);

  FPUTS (s, fp);
  if (warcfp != NULL)
    FPUTS (s, warcfp);
  if (save_context_p)
    saved_append (s);
  if (flush_log_p)
    logflush ();
  else
    needs_flushing = true;
}
Beispiel #3
0
/*
 * Log an Event Log entry. Used in SSH packet logging mode; this is
 * also as convenient a place as any to put the output of Event Log
 * entries to stderr when a command-line tool is in verbose mode.
 * (In particular, this is a better place to put it than in the
 * front ends, because it only has to be done once for all
 * platforms. Platforms which don't have a meaningful stderr can
 * just avoid defining FLAG_STDERR.
 */
void log_eventlog(void *handle, const char *event)
{
    struct LogContext *ctx = (struct LogContext *)handle;
    if ((flags & FLAG_STDERR) && (flags & FLAG_VERBOSE)) {
	fzprintf(sftpVerbose, event);
    }
    /* If we don't have a context yet (eg winnet.c init) then skip entirely */
    if (!ctx)
	return;
    if (ctx->cfg.logtype != LGTYP_PACKETS &&
	ctx->cfg.logtype != LGTYP_SSHRAW)
	return;
    logprintf(ctx, "Event Log: %s\r\n", event);
    logflush(ctx);
}
Beispiel #4
0
/*
 * Log an Event Log entry. Used in SSH packet logging mode; this is
 * also as convenient a place as any to put the output of Event Log
 * entries to stderr when a command-line tool is in verbose mode.
 * (In particular, this is a better place to put it than in the
 * front ends, because it only has to be done once for all
 * platforms. Platforms which don't have a meaningful stderr can
 * just avoid defining FLAG_STDERR.
 */
void log_eventlog(void *handle, const char *event)
{
    struct LogContext *ctx = (struct LogContext *)handle;
    if ((flags & FLAG_STDERR) && (flags & FLAG_VERBOSE)) {
	REprintf("%s\n", event);
	/*fflush(stderr);* Not allowed in an R package*/
    }
    /* If we don't have a context yet (eg winnet.c init) then skip entirely */
    if (!ctx)
	return;
    if (ctx->logtype != LGTYP_PACKETS &&
	ctx->logtype != LGTYP_SSHRAW)
	return;
    logprintf(ctx, "Event Log: %s\r\n", event);
    logflush(ctx);
}
Beispiel #5
0
Datei: log.c Projekt: DonCN/haiku
void
logputs (enum log_options o, const char *s)
{
  FILE *fp;

  check_redirect_output ();
  if ((fp = get_log_fp ()) == NULL)
    return;
  CHECK_VERBOSE (o);

  FPUTS (s, fp);
  if (save_context_p)
    saved_append (s);
  if (flush_log_p)
    logflush ();
  else
    needs_flushing = true;
}
Beispiel #6
0
Datei: log.c Projekt: DonCN/haiku
/* Enable or disable log flushing. */
void
log_set_flush (bool flush)
{
  if (flush == flush_log_p)
    return;

  if (flush == false)
    {
      /* Disable flushing by setting flush_log_p to 0. */
      flush_log_p = false;
    }
  else
    {
      /* Reenable flushing.  If anything was printed in no-flush mode,
         flush the log now.  */
      if (needs_flushing)
        logflush ();
      flush_log_p = true;
    }
}
Beispiel #7
0
/*
 * Log an SSH packet.
 * If n_blanks != 0, blank or omit some parts.
 * Set of blanking areas must be in increasing order.
 */
void log_packet(void *handle, int direction, int type,
                char *texttype, const void *data, int len,
                int n_blanks, const struct logblank_t *blanks,
                const unsigned long *seq)
{
    struct LogContext *ctx = (struct LogContext *)handle;
    char dumpdata[80], smalldata[5];
    int p = 0, b = 0, omitted = 0;
    int output_pos = 0; /* NZ if pending output in dumpdata */

    if (!(ctx->cfg.logtype == LGTYP_SSHRAW ||
            (ctx->cfg.logtype == LGTYP_PACKETS && texttype)))
        return;

    /* Packet header. */
    if (texttype) {
        if (seq) {
            logprintf(ctx, "%s packet #0x%lx, type %d / 0x%02x (%s)\r\n",
                      direction == PKT_INCOMING ? "Incoming" : "Outgoing",
                      *seq, type, type, texttype);
        } else {
            logprintf(ctx, "%s packet type %d / 0x%02x (%s)\r\n",
                      direction == PKT_INCOMING ? "Incoming" : "Outgoing",
                      type, type, texttype);
        }
    } else {
        logprintf(ctx, "%s raw data\r\n",
                  direction == PKT_INCOMING ? "Incoming" : "Outgoing");
    }

    /*
     * Output a hex/ASCII dump of the packet body, blanking/omitting
     * parts as specified.
     */
    while (p < len) {
        int blktype;

        /* Move to a current entry in the blanking array. */
        while ((b < n_blanks) &&
                (p >= blanks[b].offset + blanks[b].len))
            b++;
        /* Work out what type of blanking to apply to
         * this byte. */
        blktype = PKTLOG_EMIT; /* default */
        if ((b < n_blanks) &&
                (p >= blanks[b].offset) &&
                (p < blanks[b].offset + blanks[b].len))
            blktype = blanks[b].type;

        /* If we're about to stop omitting, it's time to say how
         * much we omitted. */
        if ((blktype != PKTLOG_OMIT) && omitted) {
            logprintf(ctx, "  (%d byte%s omitted)\r\n",
                      omitted, (omitted==1?"":"s"));
            omitted = 0;
        }

        /* (Re-)initialise dumpdata as necessary
         * (start of row, or if we've just stopped omitting) */
        if (!output_pos && !omitted)
            sprintf(dumpdata, "  %08x%*s\r\n", p-(p%16), 1+3*16+2+16, "");

        /* Deal with the current byte. */
        if (blktype == PKTLOG_OMIT) {
            omitted++;
        } else {
            int c;
            if (blktype == PKTLOG_BLANK) {
                c = 'X';
                sprintf(smalldata, "XX");
            } else {  /* PKTLOG_EMIT */
                c = ((unsigned char *)data)[p];
                sprintf(smalldata, "%02x", c);
            }
            dumpdata[10+2+3*(p%16)] = smalldata[0];
            dumpdata[10+2+3*(p%16)+1] = smalldata[1];
            dumpdata[10+1+3*16+2+(p%16)] = (isprint(c) ? c : '.');
            output_pos = (p%16) + 1;
        }

        p++;

        /* Flush row if necessary */
        if (((p % 16) == 0) || (p == len) || omitted) {
            if (output_pos) {
                strcpy(dumpdata + 10+1+3*16+2+output_pos, "\r\n");
                logwrite(ctx, dumpdata, strlen(dumpdata));
                output_pos = 0;
            }
        }

    }

    /* Tidy up */
    if (omitted)
        logprintf(ctx, "  (%d byte%s omitted)\r\n",
                  omitted, (omitted==1?"":"s"));
    logflush(ctx);
}
Beispiel #8
0
/*ARGSUSED*/
static void
pkg_door_srv(void *cookie, char *argp, size_t asz, door_desc_t *dp,
    uint_t ndesc)
{
	char *p = NULL;
	pkgcmd_t *pcmd = (pkgcmd_t *)argp;
	ucred_t *uc = NULL;
	uid_t caller;
	pid_t pcaller;
	door_desc_t ddp;
	int dnum = 0;
	int one = 1;
	int len = -1;

	if (asz < sizeof (pkgcmd_t)) {
		(void) door_return(NULL, 0, NULL, 0);
		return;
	}

	if (door_ucred(&uc) != 0) {
		(void) door_return(NULL, 0, NULL, 0);
		return;
	}

	caller = ucred_geteuid(uc);
	pcaller = ucred_getpid(uc);
	ucred_free(uc);

	if (caller != myuid) {
		(void) door_return(NULL, 0, NULL, 0);
		return;
	}

	(void) mutex_lock(&mtx);
	ncalls++;

	if (pcaller != client_pid && pcaller != -1 &&
	    (client_pid == 1 || kill(client_pid, 0) != 0)) {
		client_pid = pcaller;
	}

	if (PKG_WRITE_COMMAND(pcmd->cmd))
		while (write_locked > 0)
			(void) cond_wait(&cv, &mtx);

	switch (pcmd->cmd) {
	case PKG_FINDFILE:
		p = file_find((pkgfilter_t *)argp, &len);
		break;
	case PKG_DUMP:
		if (read_only)
			goto err;
		if (logcount > 0)
			pkgdump();
		break;
	case PKG_EXIT:
		if (logcount > 0)
			pkgdump();
		exit(0);
		/*NOTREACHED*/
	case PKG_PKGSYNC:
		if (read_only || logflush() != 0)
			goto err;
		break;
	case PKG_FILTER:
		if (pkgfilter((pkgfilter_t *)argp, &ddp) == 0)
			dnum = 1;
		break;
	case PKG_ADDLINES:
		if (read_only)
			goto err;
		changes++;

		if (pkgaddlines((pkgfilter_t *)argp) != 0)
			goto err;
		/* If we've updated the database, tell the dump thread */
		lastchange = gethrtime();
		(void) cond_broadcast(&cv);
		break;
	case PKG_NOP:
		/* Do nothing but register the current client's pid. */
		break;
	default:
		goto err;
	}

	lastcall = gethrtime();
	(void) mutex_unlock(&mtx);
	(void) door_return(p, len != -1 ? len : p == NULL ? 0 : strlen(p) + 1,
	    dnum == 0 ? NULL : &ddp, dnum);
	return;

err:
	(void) mutex_unlock(&mtx);
	(void) door_return((void *)&one, 4, NULL, NULL);
}
Beispiel #9
0
void run_fba_emulator(const char *fn)
{
	char build_version[] = "Finalburn Alpha Plus for Pi  ("__DATE__")";

	// process rom path and name
	char romname[MAX_PATH];
	if (BurnCacheInit(fn, romname))
		goto finish;

	if(config_options.option_showfps)
		bShowFPS=true;

	BurnLibInit();
	
	// find rom by name
	for (nBurnDrvSelect=0; nBurnDrvSelect<nBurnDrvCount; nBurnDrvSelect++)
		if ( strcasecmp(romname, BurnDrvGetTextA(DRV_NAME)) == 0 )
			break;
	if (nBurnDrvSelect >= nBurnDrvCount) {
		// unsupport rom ...
		nBurnDrvSelect = ~0U;
		logoutput ("rom not supported!\n");
		printf ("rom not supported!\n");
		goto finish;
	}
	
	logoutput("Attempt to initialise '%s'\n", BurnDrvGetTextA(DRV_FULLNAME));
	
	memset (titlefb, 0, 320*240*2);
	DrawString (build_version, (uint16*)&titlefb, 10, 20, 320);
	DrawString ("Based on FinalBurnAlpha", (uint16*)&titlefb, 10, 35, 320);
	DrawString ("Now loading ... ", (uint16 *)&titlefb, 10, 105, 320);	
	show_rom_loading_text("Open Zip", 0, 0);
	memcpy (VideoBuffer, titlefb, 320*240*2); 
	pi_video_flip();
	 	
	InpInit();
	InpDIP();
	
	VideoInit();

	if (DrvInit(nBurnDrvSelect, false) != 0) {
		logoutput ("Driver initialisation failed! Likely causes are:\n- Corrupt/Missing ROM(s)\n- I/O Error\n- Memory error\n\n");
		printf ("Driver initialisation failed! Likely causes are:\n- Corrupt/Missing ROM(s)\n- I/O Error\n- Memory error\n\n");
		goto finish;
	}

	RunReset();

	frame_count = 0;
	GameLooping = true;

	EZX_StartTicks();

	logoutput ("Lets go!\n");
	logflush();

	if (config_options.option_sound_enable)
	{
		int timer = 0, tick=0, i=0, fps = 0;
		bool bRenderFrame;

		if (SndOpen() == 0)
		{		
			while (GameLooping)
			{
					if (bShowFPS)
					{
						timer = EZX_GetTicks();
						if(timer-tick>1000000)
						{
							fps = nFramesRendered;
							nFramesRendered = 0;
							tick = timer;
						}
					}
					//We need to render more audio:  
		
					bRenderFrame=true; // Render last frame
					RunOneFrame(bRenderFrame,fps);

					update_audio_stream(pBurnSoundOut);
					pi_process_events();
			}
		}
	}
	else
	{
		int now, done=0, timer = 0, ticks=0, tick=0, i=0, fps = 0;
		unsigned int frame_limit = nBurnFPS/100, frametime = 100000000/nBurnFPS;
		
		while (GameLooping)
		{
			timer = EZX_GetTicks()/frametime;;
			if(timer-tick>frame_limit && bShowFPS)
			{
				fps = nFramesRendered;
				nFramesRendered = 0;
				tick = timer;
			}
			now = timer;
			ticks=now-done;
			if(ticks<1) continue;
			if(ticks>10) ticks=10;
			for (i=0; i<ticks-1; i++)
			{
				RunOneFrame(false,fps);	
			} 
			if(ticks>=1)
			{
				RunOneFrame(true,fps);	
			}
			
			done = now;
		}
	}
	
	logoutput ("Finished emulating\n");
	
finish:
	logoutput("---- Shutdown Finalburn Alpha plus ----\n\n");
	DrvExit();
	BurnLibExit();

	if (config_options.option_sound_enable)
		SndExit();
	VideoExit();
	InpExit();
	BurnCacheExit();
}
Beispiel #10
0
/*
 * Log an SSH packet.
 * If n_blanks != 0, blank or omit some parts.
 * Set of blanking areas must be in increasing order.
 */
void log_packet(void *handle, int direction, int type,
		const char *texttype, const void *data, int len,
		int n_blanks, const struct logblank_t *blanks,
		const unsigned long *seq,
                unsigned downstream_id, const char *additional_log_text)
{
    struct LogContext *ctx = (struct LogContext *)handle;
    char dumpdata[80], smalldata[5];
    int p = 0, b = 0, omitted = 0;
    int output_pos = 0; /* NZ if pending output in dumpdata */

    if (!(ctx->logtype == LGTYP_SSHRAW ||
          (ctx->logtype == LGTYP_PACKETS && texttype)))
	return;

    /* Packet header. */
    if (texttype) {
        logprintf(ctx, "%s packet ",
                  direction == PKT_INCOMING ? "Incoming" : "Outgoing");

	if (seq)
	    logprintf(ctx, "#0x%lx, ", *seq);

        logprintf(ctx, "type %d / 0x%02x (%s)", type, type, texttype);

        if (downstream_id) {
	    logprintf(ctx, " on behalf of downstream #%u", downstream_id);
            if (additional_log_text)
                logprintf(ctx, " (%s)", additional_log_text);
        }

        logprintf(ctx, "\r\n");
    } else {
        /*
         * Raw data is logged with a timestamp, so that it's possible
         * to determine whether a mysterious delay occurred at the
         * client or server end. (Timestamping the raw data avoids
         * cluttering the normal case of only logging decrypted SSH
         * messages, and also adds conceptual rigour in the case where
         * an SSH message arrives in several pieces.)
         */
        char buf[256];
        struct tm tm;
	tm = ltime();
	strftime(buf, 24, "%Y-%m-%d %H:%M:%S", &tm);
        logprintf(ctx, "%s raw data at %s\r\n",
                  direction == PKT_INCOMING ? "Incoming" : "Outgoing",
                  buf);
    }

    /*
     * Output a hex/ASCII dump of the packet body, blanking/omitting
     * parts as specified.
     */
    while (p < len) {
	int blktype;

	/* Move to a current entry in the blanking array. */
	while ((b < n_blanks) &&
	       (p >= blanks[b].offset + blanks[b].len))
	    b++;
	/* Work out what type of blanking to apply to
	 * this byte. */
	blktype = PKTLOG_EMIT; /* default */
	if ((b < n_blanks) &&
	    (p >= blanks[b].offset) &&
	    (p < blanks[b].offset + blanks[b].len))
	    blktype = blanks[b].type;

	/* If we're about to stop omitting, it's time to say how
	 * much we omitted. */
	if ((blktype != PKTLOG_OMIT) && omitted) {
	    logprintf(ctx, "  (%d byte%s omitted)\r\n",
		      omitted, (omitted==1?"":"s"));
	    omitted = 0;
	}

	/* (Re-)initialise dumpdata as necessary
	 * (start of row, or if we've just stopped omitting) */
	if (!output_pos && !omitted)
	    sprintf(dumpdata, "  %08x%*s\r\n", p-(p%16), 1+3*16+2+16, "");

	/* Deal with the current byte. */
	if (blktype == PKTLOG_OMIT) {
	    omitted++;
	} else {
	    int c;
	    if (blktype == PKTLOG_BLANK) {
		c = 'X';
		sprintf(smalldata, "XX");
	    } else {  /* PKTLOG_EMIT */
		c = ((unsigned char *)data)[p];
		sprintf(smalldata, "%02x", c);
	    }
	    dumpdata[10+2+3*(p%16)] = smalldata[0];
	    dumpdata[10+2+3*(p%16)+1] = smalldata[1];
	    dumpdata[10+1+3*16+2+(p%16)] = (isprint(c) ? c : '.');
	    output_pos = (p%16) + 1;
	}

	p++;

	/* Flush row if necessary */
	if (((p % 16) == 0) || (p == len) || omitted) {
	    if (output_pos) {
		strcpy(dumpdata + 10+1+3*16+2+output_pos, "\r\n");
		logwrite(ctx, dumpdata, strlen(dumpdata));
		output_pos = 0;
	    }
	}

    }

    /* Tidy up */
    if (omitted)
	logprintf(ctx, "  (%d byte%s omitted)\r\n",
		  omitted, (omitted==1?"":"s"));
    logflush(ctx);
}
Beispiel #11
0
Datei: log.c Projekt: DonCN/haiku
static bool
log_vprintf_internal (struct logvprintf_state *state, const char *fmt,
                      va_list args)
{
  char smallmsg[128];
  char *write_ptr = smallmsg;
  int available_size = sizeof (smallmsg);
  int numwritten;
  FILE *fp = get_log_fp ();

  if (!save_context_p)
    {
      /* In the simple case just call vfprintf(), to avoid needless
         allocation and games with vsnprintf(). */
      vfprintf (fp, fmt, args);
      goto flush;
    }

  if (state->allocated != 0)
    {
      write_ptr = state->bigmsg;
      available_size = state->allocated;
    }

  /* The GNU coding standards advise not to rely on the return value
     of sprintf().  However, vsnprintf() is a relatively new function
     missing from legacy systems.  Therefore I consider it safe to
     assume that its return value is meaningful.  On the systems where
     vsnprintf() is not available, we use the implementation from
     snprintf.c which does return the correct value.  */
  numwritten = vsnprintf (write_ptr, available_size, fmt, args);

  /* vsnprintf() will not step over the limit given by available_size.
     If it fails, it returns either -1 (older implementations) or the
     number of characters (not counting the terminating \0) that
     *would have* been written if there had been enough room (C99).
     In the former case, we double available_size and malloc to get a
     larger buffer, and try again.  In the latter case, we use the
     returned information to build a buffer of the correct size.  */

  if (numwritten == -1)
    {
      /* Writing failed, and we don't know the needed size.  Try
         again with doubled size. */
      int newsize = available_size << 1;
      state->bigmsg = xrealloc (state->bigmsg, newsize);
      state->allocated = newsize;
      return false;
    }
  else if (numwritten >= available_size)
    {
      /* Writing failed, but we know exactly how much space we
         need. */
      int newsize = numwritten + 1;
      state->bigmsg = xrealloc (state->bigmsg, newsize);
      state->allocated = newsize;
      return false;
    }

  /* Writing succeeded. */
  saved_append (write_ptr);
  FPUTS (write_ptr, fp);
  if (state->bigmsg)
    xfree (state->bigmsg);

 flush:
  if (flush_log_p)
    logflush ();
  else
    needs_flushing = true;

  return true;
}
Beispiel #12
0
    void TxnContext::commit(int flags) {
        verify(!_retired);
        bool gotGTID = false;
        GTID gtid;
        // do this in case we are writing the first entry
        // we put something in that can be distinguished from
        // an initialized GTID that has never been touched
        gtid.inc_primary(); 
        // handle work related to logging of transaction for replication
        // this piece must be done before the _txn.commit
        try {
            if (hasParent()) {
                // This does something
                // a bit dangerous in that it may spill parent's stuff
                // with this child transaction that is committing. If something
                // goes wrong and this child transaction aborts, we will miss
                // some ops
                //
                // This ought to be ok, because we are in this try/catch block
                // where if something goes wrong, we will crash the server.
                // NOTHING better go wrong here, unless under bad rare
                // circumstances
                _txnOps.finishChildCommit();
            }
            else if (!_txnOps.empty()) {
                uint64_t timestamp = 0;
                uint64_t hash = 0;
                if (!_initiatingRS) {
                    dassert(txnGTIDManager);
                    txnGTIDManager->getGTIDForPrimary(&gtid, &timestamp, &hash);
                }
                else {
                    dassert(!txnGTIDManager);
                    timestamp = curTimeMillis64();
                }
                gotGTID = true;
                // In this case, the transaction we are committing has
                // no parent, so we must write the transaction's 
                // logged operations to the opLog, as part of this transaction
                dassert(logTxnOpsForReplication());
                dassert(_logTxnToOplog);
                _txnOps.rootCommit(gtid, timestamp, hash);
            }
            // handle work related to logging of transaction for chunk migrations
            if (!_txnOpsForSharding.empty()) {
                if (hasParent()) {
                    transferOpsForShardingToParent();
                }
                else {
                    writeTxnOpsToMigrateLog();
                }
            }

            _clientCursorRollback.preComplete();
            _txn.commit(flags);

            // if the commit of this transaction got a GTID, then notify 
            // the GTIDManager that the commit is now done.
            if (gotGTID && !_initiatingRS) {
                dassert(txnGTIDManager);
                // save the GTID for the client so that
                // getLastError will know what GTID slaves
                // need to be caught up to.
                cc().setLastOp(gtid);
                txnGTIDManager->noteLiveGTIDDone(gtid);
            }
        }
        catch (std::exception &e) {
            log() << "exception during critical section of txn commit, aborting system: " << e.what() << endl;
            printStackTrace();
            logflush();
            ::abort();
        }

        // These rollback items must be processed after the ydb transaction completes.
        if (hasParent()) {
            _cappedRollback.transfer(_parent->_cappedRollback);
            _nsIndexRollback.transfer(_parent->_nsIndexRollback);
        } else {
            _cappedRollback.commit();
            _nsIndexRollback.commit();
        }
        _retired = true;
    }
Beispiel #13
0
Datei: retr.c Projekt: aosm/wget
/* Show the dotted progress report of file loading.  Called with
   length and a flag to tell it whether to reset or not.  It keeps the
   offset information in static local variables.

   Return value: 1 or 0, designating whether any dots have been drawn.

   If the init argument is set, the routine will initialize.

   If the res is non-zero, res/line_bytes lines are skipped
   (meaning the appropriate number ok kilobytes), and the number of
   "dots" fitting on the first line are drawn as ','.  */
static int
show_progress (long res, long expected, enum spflags flags)
{
  static long line_bytes;
  static long offs;
  static int ndot, nrow;
  int any_output = 0;

  if (flags == SP_FINISH)
    {
      if (expected)
	{
	  int dot = ndot;
	  char *tmpstr = (char *)alloca (2 * opt.dots_in_line + 1);
	  char *tmpp = tmpstr;
	  for (; dot < opt.dots_in_line; dot++)
	    {
	      if (!(dot % opt.dot_spacing))
		*tmpp++ = ' ';
	      *tmpp++ = ' ';
	    }
	  *tmpp = '\0';
	  logputs (LOG_VERBOSE, tmpstr);
	  print_percentage (nrow * line_bytes + ndot * opt.dot_bytes + offs,
			    expected);
	}
      logputs (LOG_VERBOSE, "\n\n");
      return 0;
    }

  /* Temporarily disable flushing.  */
  opt.no_flush = 1;
  /* init set means initialization.  If res is set, it also means that
     the retrieval is *not* done from the beginning.  The part that
     was already retrieved is not shown again.  */
  if (flags == SP_INIT)
    {
      /* Generic initialization of static variables.  */
      offs = 0L;
      ndot = nrow = 0;
      line_bytes = (long)opt.dots_in_line * opt.dot_bytes;
      if (res)
	{
	  if (res >= line_bytes)
	    {
	      nrow = res / line_bytes;
	      res %= line_bytes;
	      logprintf (LOG_VERBOSE,
			 _("\n          [ skipping %dK ]"),
			 (int) ((nrow * line_bytes) / 1024));
	      ndot = 0;
	    }
	}
      logprintf (LOG_VERBOSE, "\n%5ldK ->", nrow * line_bytes / 1024);
    }
  /* Offset gets incremented by current value.  */
  offs += res;
  /* While offset is >= opt.dot_bytes, print dots, taking care to
     precede every 50th dot with a status message.  */
  for (; offs >= opt.dot_bytes; offs -= opt.dot_bytes)
    {
      if (!(ndot % opt.dot_spacing))
	logputs (LOG_VERBOSE, " ");
      any_output = 1;
      logputs (LOG_VERBOSE, flags == SP_INIT ? "," : ".");
      ++ndot;
      if (ndot == opt.dots_in_line)
	{
	  ndot = 0;
	  ++nrow;
	  if (expected)
	    print_percentage (nrow * line_bytes, expected);
	  logprintf (LOG_VERBOSE, "\n%5ldK ->", nrow * line_bytes / 1024);
	}
    }
  /* Reenable flushing.  */
  opt.no_flush = 0;
  if (any_output)
    /* Force flush.  #### Oh, what a kludge!  */
    logflush ();
  return any_output;
}