Example #1
0
static void
fli_info(char *title)
{
    struct fli_head fh;
    FILE *fd;
    char buf1[40];
    char buf2[40];
    char buf3[40];
    char *bufs[8];

    if ((fd = read_fli_head(title, &fh)) == 0)
        return;
    jclose(fd);
    sprintf(buf1, browse_123 /* "%d frames in %ld bytes" */,
            fh.frame_count, fh.size);
    sprintf(buf2, browse_124 /* "Average frame size %ld" */,
            fh.size/(fh.frame_count+1));
    sprintf(buf3, browse_125 /* "Speed %d jiffies/frame" */,
            fh.speed);
    bufs[0] = title;
    bufs[1] = cst_;
    bufs[2] = buf1;
    bufs[3] = buf2;
    bufs[4] = buf3;
    bufs[5] = NULL;
    continu_box(bufs);
}
Example #2
0
int mtnexec_poll()
{
  int c;
  int i;
  int r;
  int w;
  pid_t pid;
  int status;
  char data;
  struct epoll_event ev[64];
  struct timeval  polltv;
  struct timeval keikatv;
  static int wtime = 200;

  gettimeofday(&polltv, NULL);
  timersub(&polltv, &(ctx->polltv), &keikatv);
  if(wtime < (keikatv.tv_sec * 1000 + keikatv.tv_usec / 1000)){
    memcpy(&(ctx->polltv), &polltv, sizeof(struct timeval));
    ctx->cpu_use = scheprocess(mtn, ctx->job, ctx->job_max, ctx->cpu_lim, ctx->cpu_num);
    wtime = getwaittime(ctx->job, ctx->job_max);
  }

  c = 0;
  w = wtime;
  if(!(r = epoll_wait(ctx->efd, ev, 64, w))){
    return(c);
  }
  if(r == -1){
    if(errno != EINTR){
      mtnlogger(mtn, 0, "[error] %s: %s\n", __func__, strerror(errno));
    }
    return(c);
  }

  while(r--){
    if(ev[r].data.ptr){
      mtnexec_stdout(ev[r].data.ptr);
      mtnexec_stderr(ev[r].data.ptr);
    }else{
      read(ctx->fsig[0], &data, sizeof(data));
      while((pid = waitpid(-1, &status, WNOHANG)) > 0){
        for(i=0;i<ctx->job_max;i++){
          if(pid == ctx->job[i].pid){
            if(WIFEXITED(status)){
              ctx->job[i].exit = WEXITSTATUS(status);
            }
            jclose(&(ctx->job[i]));
            c++;
            w = 0;
            break;
          }
        }
      }

    }
  }
  return(c);
}
Example #3
0
/* fclose() wrapper */
int jfclose(struct jfs *stream)
{
	int rv;
	rv = jclose(stream);
	free(stream);

	if (rv == 0)
		return 0;
	else
		return EOF;
}
Example #4
0
int main(int argc, char **argv)
{
	int nthreads;
	unsigned long i;
	pthread_t *threads;
	struct jfsck_result ckres;

	if (argc != 4) {
		help();
		return 1;
	}

	mb = atoi(argv[1]);
	blocksize = atoi(argv[2]) * 1024;
	nthreads = atoi(argv[3]);
	towrite = mb * 1024 * 1024;

	threads = malloc(sizeof(pthread_t) * nthreads);
	if (threads == NULL) {
		perror("malloc()");
		return 1;
	}

	fs = jopen(FILENAME, O_RDWR | O_CREAT | O_TRUNC, 0600, 0);
	if (fs == NULL) {
		perror("jopen()");
		return 1;
	}

	jtruncate(fs, towrite * nthreads);

	for (i = 0; i < nthreads; i++) {
		pthread_create(threads + i, NULL, &worker, (void *) i);
	}

	for (i = 0; i < nthreads; i++) {
		pthread_join(*(threads + i), NULL);
	}

	jclose(fs);
	jfsck(FILENAME, NULL, &ckres, 0);
	if (ckres.total != 0) {
		fprintf(stderr, "There were %d errors during the test\n",
				ckres.total);
		fprintf(stderr, "jfsck() was used to fix them, but that ");
		fprintf(stderr, "shouldn't happen.\n");
		return 1;
	}

	return 0;
}
Example #5
0
void
watcher(void)
{
	Json *jv, *jtop;
	vlong id;
	char *text, *created_at, *user;
	char *buf;
	int fd, n, i;
	char fname[64];

	buf = malloc(BUFSIZ);
	if(buf == nil)
		sysfatal("malloc: %r");

	for(;;){
		fetch(fname);
		fd = open(fname, OREAD);
		n = readn(fd, buf, BUFSIZ);
		if(n <= 0){
			fprint(2, "read failed.\n");
			sleep(INTERVAL);
			continue;
		}
		/*print("(read %d bytes in %s)\n", n, fname);*/
		buf[n] = 0;

		jtop = parsejson(buf);
		if(jtop == nil){
			fprint(2, "parsejson failed.\n");
			sleep(INTERVAL);
			continue;
		}
		jv = jtop->value[0]; /* FIXME */

		for(i = jv->len - 1; i >= 0; i--){
			id = jint(jlookup(jv->value[i], "id"));
			if(id <= lastid)
				continue;
			text = jstring(jlookup(jv->value[i], "text"));
			created_at = jstring(jlookup(jv->value[i], "created_at"));
			user = jstring(jlookup(jv->value[i], "from_user"));
			print("[%s] %s (%s)\n", user, text, created_at);
			lastid = id;
		}

		jclose(jv);
		close(fd);
		sleep(INTERVAL);
	}
}
Example #6
0
/*
 * When we have multiple commands and are writing to a prefix set, we can
 * 'background' the output and/or mirroring command and have the background
 * processes feed off the prefix set the foreground process is writing to.
 */
static void
fork_subprocess(struct jfile *jftoclose,
	void (*func)(struct jfile *, const char *, const char *, int64_t),
	const char *input_prefix, const char *transid_file, const char *info,
	int64_t transid)
{
    pid_t pid;
    struct jfile *jf;

    if ((pid = fork()) == 0) {
	jmodes &= ~(JMODEF_DEBUG | JMODEF_INPUT_PIPE);
	jmodes |= JMODEF_LOOP_FOREVER;	/* keep checking for new input */
	jclose(jftoclose);
	jf = jopen_prefix(input_prefix, 0);
	jmodes |= JMODEF_INPUT_PREFIX;
	func(jf, transid_file, info, transid);
	jclose(jf);
	exit(0);
    } else if (pid < 0) {
	fprintf(stderr, "fork(): %s\n", strerror(errno));
	exit(1);
    }
}
Example #7
0
check_exe(char *name)
{
int file;
Vlib ev;
int ok;

if ((file = jopen(name, 0)) == 0)
	{
	cant_find(name);
	return(0);
	}
ok = verify_exe_head(file, &ev.eh);
jclose(file);
return(ok);
}
Example #8
0
static int
view_fli(char *name, Vscreen *screen, int loop)
{
    struct fli_head fh;
    FILE *fd;
    long clock;
    int i;
    long f1off;

    if ((fd = read_fli_head(name, &fh)) == 0)
        return(0);
    clock = get80hz();
    mouse_on = 0;
    if (loop)
    {
        if (!read_next_frame(name,fd,screen,1))
            goto OUT;
        f1off = jtell(fd);
        clock += fh.speed;
        if (!wait_til(clock))
            goto OUT;
        if (clock > get80hz())
            clock = get80hz();
    }
    do
    {
        for (i=0; i<fh.frame_count; i++)
        {
            if (!read_next_frame(name,fd,screen,1))
                goto OUT;
            clock += fh.speed;
            if (!wait_til(clock))
                goto OUT;
            if (clock > get80hz())
                clock = get80hz();
        }
        if (loop)
            jseek(fd, f1off, 0);
    }
    while (loop);
OUT:
    jclose(fd);
    mouse_on = 1;
}
Example #9
0
int main(void)
{
	int r;
	jfs_t *file;
	struct jtrans *trans;
	struct jfsck_result result;

	/* check the file is OK */
	jfsck(FILENAME, NULL, &result, 0);

	/* and open it */
	file = jopen(FILENAME, O_RDWR | O_CREAT | O_TRUNC, 0600, 0);
	if (file == NULL) {
		perror("jopen");
		return 1;
	}

	/* write two "Hello world"s next to each other */
	trans = jtrans_new(file, 0);
	jtrans_add_w(trans, TEXT, strlen(TEXT), 0);
	jtrans_add_w(trans, TEXT, strlen(TEXT), strlen(TEXT));
	r = jtrans_commit(trans);
	if (r < 0) {
		perror("jtrans_commit");
		return 1;
	}

	/* at this point the file has "Hello world!\nHello world!\n" */

	/* now we rollback */
	r = jtrans_rollback(trans);
	if (r < 0) {
		perror("jtrans_rollback");
		return 1;
	}

	/* and now the file is empty! */

	jtrans_free(trans);
	jclose(file);
	return 0;
}
Example #10
0
int main(int argc, char **argv)
{
	int rv;
	jfs_t *fs;
	jtrans_t *ts;

	fs = jopen("test3", O_RDWR | O_CREAT, 0660, 0);
	if (fs == NULL)
		perror("jopen()");

	ts = jtrans_new(fs, 0);
	if (ts == NULL)
		perror("jtrans_new()");

#define str1 "1ROLLBACKTEST1!\n"
	jtrans_add_w(ts, str1, strlen(str1), 0);

#define str2 "2ROLLBACKTEST2!\n"
	jtrans_add_w(ts, str2, strlen(str2), strlen(str1));

#define str3 "3ROLLBACKTEST3!\n"
	jtrans_add_w(ts, str3, strlen(str3), strlen(str1) + strlen(str2));

	rv = jtrans_commit(ts);
	if (rv < 0)
		perror("jtrans_commit()");
	printf("commit ok: %d\n", rv);

	rv = jtrans_rollback(ts);
	if (rv < 0)
		perror("jtrans_rollback()");
	printf("rollback ok: %d\n", rv);

	jtrans_free(ts);

	if (jclose(fs))
		perror("jclose()");

	return 0;
}
Example #11
0
void *load_exe(char *filename, Exe_head *eh)
{
long retval;
char *alligned_buf;
char *alloc_buf = NULL;
long (*rfunc)();
unsigned long code_offset;
unsigned long init_size;
unsigned long bss_size;
unsigned long total_size;
void *v;
unsigned long fixup_offset;
UWORD fixup[2];
UWORD *segpt;
UWORD code_seg;
int f;
unsigned i;
int ok = 0;

if ((f = jopen(filename, JREADONLY)) == 0)
	{
	cant_find(filename);
	return(NULL);
	}
if (!verify_exe_head(f, eh))
	goto OUT;
code_offset = eh->head_size;
code_offset *= 16;	/* make it a paragraph */
init_size = eh->blocks;
init_size *= 512;
init_size += eh->mod512;
if (eh->mod512 != 0)
	init_size -= 512;
init_size -= code_offset;
bss_size = eh->min_data;
bss_size *= 16;
total_size = init_size + bss_size;
if ((alloc_buf = begmem((unsigned)total_size+16)) == NULL)
	goto OUT;
code_seg = ptr_seg(alloc_buf) + 1;
alligned_buf = make_ptr(0, code_seg);
zero_structure(alligned_buf, (unsigned)total_size);
jseek(f, code_offset, JSEEK_START);
if (jread(f, alligned_buf, init_size) < init_size)
	{
	truncated(filename);
	goto OUT;
	}
v = alligned_buf;
eh->entry_point = v;
if (eh->reloc_count > 0)
	{
	fixup_offset = eh->reloc_list;
	jseek(f, fixup_offset, JSEEK_START);
	for (i=0; i<eh->reloc_count; i++)
		{
		if (jread(f, fixup, sizeof(fixup)) != sizeof(fixup))
			{
			truncated(filename);
			goto OUT;
			}
		segpt = make_ptr(fixup[0], code_seg + fixup[1]);
		segpt[0] += code_seg;
		}
	}
ok = 1;
OUT:
if (!ok)
	{
	gentle_freemem(alloc_buf);
	alloc_buf = NULL;
	}
jclose(f);
return(alloc_buf);
}
Example #12
0
JmolWrapper::~JmolWrapper() {
	jclose(sock);
}
Example #13
0
int mtnexec_fork(MTNSVR *svr, ARG arg)
{
  int f;
  int pp[3][2];
  MTNJOB *job;
  struct epoll_event ev;

  if(!(job = mtnexec_wait())){
    return(-1);
  }
  mtnexec_initjob(job, arg);
  job->svr    = svr;
  job->argc   = cmdargs(job);
  job->cmd    = joinarg(job->argc, " ");
  job->std    = stdname(job);
  job->echo   = (ctx->echo) ? convarg(newstr(ctx->echo), job) : NULL;
  job->putarg = cpconvarg(ctx->putarg, ctx->conv ? job : NULL);
  job->getarg = cpconvarg(ctx->getarg, ctx->conv ? job : NULL);
  if(is_empty(job->cmd)){
    jclose(job);
    return(-1);
  }
  if(ctx->dryrun){
    mtnexec_dryrun(job);
    jclose(job);
    return(0);
  }
  if(ctx->verbose){
    mtnexec_verbose(job);
  }
  pipe(pp[0]);
  pipe(pp[1]);
  pipe(pp[2]);
  gettimeofday(&(job->start), NULL);
  job->pid = fork();
  if(job->pid == -1){
    job->pid = 0;
    close(pp[0][0]);
    close(pp[0][1]);
    close(pp[1][0]);
    close(pp[1][1]);
    close(pp[2][0]);
    close(pp[2][1]);
    mtnlogger(mtn, 0, "[error] %s: %s\n", __func__, strerror(errno));
    return(-1);
  }
  if(job->pid){
    close(pp[0][1]);
    close(pp[1][1]);
    close(pp[2][1]);
    job->ctl   = pp[0][0];
    job->out   = pp[1][0];
    job->err   = pp[2][0];
    job->cct   = 1;
    job->pstat = calloc(1, sizeof(MTNPROCSTAT));
    job->pstat[0].pid = job->pid;
    fcntl(job->ctl, F_SETFD, FD_CLOEXEC);
    fcntl(job->out, F_SETFD, FD_CLOEXEC);
    fcntl(job->err, F_SETFD, FD_CLOEXEC);
    fcntl(job->out, F_SETFL, O_NONBLOCK);
    fcntl(job->err, F_SETFL, O_NONBLOCK);
    ev.data.ptr = job;
    ev.events   = EPOLLIN;
    if(epoll_ctl(ctx->efd, EPOLL_CTL_ADD, job->out, &ev) == -1){
      mtnlogger(mtn, 0, "[error] %s: epoll_ctl %s stdout fd=%d\n", __func__, strerror(errno), job->out);
    }
    if(epoll_ctl(ctx->efd, EPOLL_CTL_ADD, job->err, &ev) == -1){
      mtnlogger(mtn, 0, "[error] %s: epoll_ctl %s stderr fd=%d\n", __func__, strerror(errno), job->err);
    }
    char d;
    while(read(job->ctl,&d,1));
    close(job->ctl);
    job->ctl = 0;
    return(0);
  }

  //===== execute process =====
  setpgid(0,0);
  close(pp[0][0]);
  close(pp[1][0]);
  close(pp[2][0]);
  if(strlen(job->std[0])){
    f = open(job->std[0], O_RDONLY);
    if(f == -1){
      mtnlogger(mtn, 0, "[error] %s: %s %s\n", __func__, strerror(errno), job->std[0]);
      _exit(1);
    }
    close(0);
    dup2(f, 0);
    close(f);
  }

  if(strlen(job->std[1])){
    f = open(job->std[1], O_WRONLY | O_TRUNC | O_CREAT, 0660);
    if(f == -1){
      mtnlogger(mtn, 0, "[error] %s: %s %s\n", __func__, strerror(errno), job->std[1]);
      _exit(1);
    }
    close(1);
    if(dup2(f, 1) == -1){
      mtnlogger(mtn, 0, "[error] %s: %s\n", __func__, strerror(errno));
      _exit(1);
    }
    close(f);
  }else{
    close(1);
    dup2(pp[1][1], 1);
  }

  if(strlen(job->std[2])){
    f = open(job->std[2], O_WRONLY | O_TRUNC | O_CREAT, 0660);
    if(f == -1){
      mtnlogger(mtn, 0, "[error] %s: %s %s\n", __func__, strerror(errno), job->std[2]);
      _exit(1);
    }
    close(2);
    dup2(f, 2);
    close(f);
  }else{
    close(2);
    dup2(pp[2][1], 2);
  }
  close(pp[1][1]);
  close(pp[2][1]);
  job->ctl = pp[0][1];

  if(job->svr){
    /*===== remote execute process =====*/
    mtn_exec(mtn, job);
    mtnlogger(mtn, 0, "[error] %s: host=%s addr=%s %s '%s'\n", __func__, job->svr->host, inet_ntoa(job->svr->addr.addr.in.sin_addr), strerror(errno), job->cmd);
  }else{
    /*===== local exec process =====*/
    close(job->ctl);
    job->ctl = 0;
    execl("/bin/sh", "/bin/sh", "-c", job->cmd, NULL);
    mtnlogger(mtn, 0, "[error] %s: %s '%s'\n", __func__, strerror(errno), job->cmd);
  }
  _exit(127);
}
Example #14
0
int
main(int ac, char **av)
{
    const char *input_prefix = NULL;
    char *output_transid_file = NULL;
    char *mirror_transid_file = NULL;
    const char *mirror_directory = ".";
    char *record_prefix = NULL;
    char *record_transid_file = NULL;
    struct jsession jsdebug;
    struct jsession jsoutput;
    struct jsession jsmirror;
    char *ptr;
    int64_t mirror_transid;
    int64_t output_transid;
    int64_t record_transid;
    int64_t transid;
    int input_fd;
    struct stat st;
    struct jfile *jf;
    struct jdata *jd;
    int ch;

    while ((ch = getopt(ac, av, "2c:dfm:o:s:uvw:D:O:W:F")) != -1) {
	switch(ch) {
	case '2':
	    jmodes |= JMODEF_INPUT_FULL;
	    break;
	case 'c':
	    trans_count = strtoll(optarg, &ptr, 0);
	    switch(*ptr) {
	    case 't':
		trans_count *= 1024;
		/* fall through */
	    case 'g':
		trans_count *= 1024;
		/* fall through */
	    case 'm':
		trans_count *= 1024;
		/* fall through */
	    case 'k':
		trans_count *= 1024;
		break;
	    case 0:
		break;
	    default:
		fprintf(stderr, "Bad suffix for value specified with -c, use 'k', 'm', 'g', 't', or nothing\n");
		usage(av[0]);
	    }
	    break;
	case 'd':
	    jmodes |= JMODEF_DEBUG;
	    break;
	case 'f':
	    jmodes |= JMODEF_LOOP_FOREVER;
	    break;
	case 'v':
	    ++verbose_opt;
	    break;
	case 'm':
	    jmodes |= JMODEF_MIRROR;
	    if (strcmp(optarg, "none") != 0)
		mirror_transid_file = optarg;
	    break;
	case 'O':
	    jmodes |= JMODEF_OUTPUT_FULL;
	    /* fall through */
	case 'o':
	    jmodes |= JMODEF_OUTPUT;
	    if (strcmp(optarg, "none") != 0)
		output_transid_file = optarg;
	    break;
	case 's':
	    prefix_file_size = strtoll(optarg, &ptr, 0);
	    switch(*ptr) {
	    case 't':
		prefix_file_size *= 1024;
		/* fall through */
	    case 'g':
		prefix_file_size *= 1024;
		/* fall through */
	    case 'm':
		prefix_file_size *= 1024;
		/* fall through */
	    case 'k':
		prefix_file_size *= 1024;
		break;
	    case 0:
		break;
	    default:
		fprintf(stderr, "Bad suffix for value specified with -s, use 'k', 'm', 'g', 't', or nothing\n");
		usage(av[0]);
	    }
	    break;
	case 'u':
	    jdirection = JD_BACKWARDS;
	    break;
	case 'W':
	    jmodes |= JMODEF_RECORD_TMP;
	    /* fall through */
	case 'w':
	    jmodes |= JMODEF_RECORD;
	    record_prefix = optarg;
	    asprintf(&record_transid_file, "%s.transid", record_prefix);
	    break;
	case 'D':
	    mirror_directory = optarg;
	    break;
	case 'F':
	    ++fsync_opt;
	    break;
	default:
	    fprintf(stderr, "unknown option: -%c\n", optopt);
	    usage(av[0]);
	}
    }

    /*
     * Sanity checks
     */
    if ((jmodes & JMODEF_COMMAND_MASK) == 0)
	usage(av[0]);
    if (optind > ac + 1)  {
	fprintf(stderr, "Only one input file or prefix may be specified,\n"
			"or zero if stdin is to be the input.\n");
	usage(av[0]);
    }
    if (strcmp(mirror_directory, ".") != 0) {
	struct stat sb;
	if (stat(mirror_directory, &sb) != 0) {
	    perror ("Could not stat mirror directory");
	    usage(av[0]);
	}
	if (!S_ISDIR(sb.st_mode))
	{
	    fprintf (stderr, "Mirror directory '%s' is not a directory\n", mirror_directory);
	    usage(av[0]);
	}
    }
    if (jdirection == JD_BACKWARDS && (jmodes & (JMODEF_RECORD|JMODEF_OUTPUT))) {
	fprintf(stderr, "Undo mode is only good in mirroring mode and "
			"cannot be mixed with other modes.\n");
	exit(1);
    }

    /*
     * STEP1 - OPEN INPUT
     *
     * The input will either be a pipe, a regular file, or a journaling 
     * file prefix.
     */
    jf = NULL;
    if (optind == ac) {
	input_prefix = "<stdin>";
	input_fd = 0;
	if (fstat(0, &st) < 0 || !S_ISREG(st.st_mode)) {
	    jmodes |= JMODEF_INPUT_PIPE;
	    if (jdirection == JD_BACKWARDS) {
		fprintf(stderr, "Cannot scan journals on pipes backwards\n");
		usage(av[0]);
	    }
	}
	jf = jopen_fd(input_fd);
    } else if (stat(av[optind], &st) == 0 && S_ISREG(st.st_mode)) {
	input_prefix = av[optind];
	if ((input_fd = open(av[optind], O_RDONLY)) != 0) {
	    jf = jopen_fd(input_fd);
	} else {
	    jf = NULL;
	}
    } else {
	input_prefix = av[optind];
	jf = jopen_prefix(input_prefix, 0);
	jmodes |= JMODEF_INPUT_PREFIX;
    }
    if (jf == NULL) {
	fprintf(stderr, "Unable to open input %s: %s\n", 
		input_prefix, strerror(errno));
	exit(1);
    }

    /*
     * STEP 1 - SYNCHRONIZING THE INPUT STREAM
     *
     * Figure out the starting point for our various output modes.  Figure
     * out the earliest transaction id and try to seek to that point,
     * otherwise we might have to scan through terrabytes of data.
     *
     * Invalid transid's will be set to 0, but it should also be noted
     * that 0 is also a valid transid.
     */
    get_transid_from_file(output_transid_file, &output_transid,
			  JMODEF_OUTPUT_TRANSID_GOOD);
    get_transid_from_file(mirror_transid_file, &mirror_transid, 
			  JMODEF_MIRROR_TRANSID_GOOD);
    get_transid_from_file(record_transid_file, &record_transid, 
			  JMODEF_RECORD_TRANSID_GOOD);
    transid = LLONG_MAX;
    if ((jmodes & JMODEF_OUTPUT_TRANSID_GOOD) && output_transid < transid)
	transid = output_transid;
    if ((jmodes & JMODEF_MIRROR_TRANSID_GOOD) && mirror_transid < transid)
	transid = mirror_transid;
    if ((jmodes & JMODEF_RECORD_TRANSID_GOOD) && record_transid < transid)
	transid = record_transid;
    if ((jmodes & JMODEF_TRANSID_GOOD_MASK) == 0)
	transid = 0;
    if (verbose_opt) {
	if (jmodes & JMODEF_OUTPUT) {
	    fprintf(stderr, "Starting transid for OUTPUT: %016jx\n",
		    (uintmax_t)output_transid);
	}
	if (jmodes & JMODEF_MIRROR) {
	    fprintf(stderr, "Starting transid for MIRROR: %016jx\n",
		    (uintmax_t)mirror_transid);
	}
	if (jmodes & JMODEF_RECORD) {
	    fprintf(stderr, "Starting transid for RECORD: %016jx\n",
		    (uintmax_t)record_transid);
	}
    }

    if (strcmp(mirror_directory, ".") != 0) {
	if (chdir (mirror_directory) != 0) {
	    perror ("Could not enter mirror directory");
	    exit (1);
	}
    }

    /*
     * Now it gets more difficult.  If we are recording then the input
     * could be representative of continuing data and not have any
     * prior, older data that the output or mirror modes might need.  Those
     * modes must work off the recording data even as we write to it.
     * In that case we fork and have the sub-processes work off the
     * record output.
     *
     * Then we take the input and start recording.
     */
    if (jmodes & JMODEF_RECORD) {
	if (jrecord_init(record_prefix) < 0) {
	    fprintf(stderr, "Unable to initialize file set for: %s\n", 
		    record_prefix);
	    exit(1);
	}
	if (jmodes & JMODEF_MIRROR) {
	    fork_subprocess(jf, jscan_do_mirror, record_prefix, 
			    mirror_transid_file,
			    mirror_directory, mirror_transid);
	    /* XXX ack stream for temporary record file removal */
	}
	if (jmodes & JMODEF_OUTPUT) {
	    fork_subprocess(jf, jscan_do_output, record_prefix,
			    record_transid_file,
			    NULL, output_transid);
	    /* XXX ack stream for temporary record file removal */
	}
	jscan_do_record(jf, record_transid_file, record_prefix, record_transid);
	exit(0);
    }

    /*
     * If the input is a prefix set we can just pass it to the appropriate
     * jscan_do_*() function.  If we are doing both output and mirroring
     * we fork the mirror and do the output in the foreground since that
     * is going to stdout.
     */
    if (jmodes & JMODEF_INPUT_PREFIX) {
	if ((jmodes & JMODEF_OUTPUT) && (jmodes & JMODEF_MIRROR)) {
	    fork_subprocess(jf, jscan_do_mirror, input_prefix, 
			    mirror_transid_file,
			    mirror_directory, mirror_transid);
	    jscan_do_output(jf, output_transid_file, NULL, output_transid);
	} else if (jmodes & JMODEF_OUTPUT) {
	    jscan_do_output(jf, output_transid_file, NULL, output_transid);
	} else if (jmodes & JMODEF_MIRROR) {
	    jscan_do_mirror(jf, mirror_transid_file, mirror_directory,
			    mirror_transid);
	} else if (jmodes & JMODEF_DEBUG) {
	    jscan_do_debug(jf, NULL, NULL, 0);
	}
	exit(0);
    }

    /*
     * The input is not a prefix set and we are not recording, which means
     * we have to transfer the data on the input pipe to the output and
     * mirroring code on the fly.  This also means that we must keep track
     * of meta-data records in-memory.  However, if the input is a regular
     * file we *CAN* try to optimize where we start reading.
     *
     * NOTE: If the mirroring code encounters a transaction record that is
     * not marked begin, and it does not have the begin record, it will
     * attempt to locate the begin record if the input is not a pipe, then
     * seek back.
     */
    if ((jmodes & JMODEF_TRANSID_GOOD_MASK) && !(jmodes & JMODEF_INPUT_PIPE))
	jd = jseek(jf, transid, jdirection);
    else
	jd = jread(jf, NULL, jdirection);
    jmodes |= JMODEF_MEMORY_TRACKING;

    jsession_init(&jsdebug, jf, jdirection,
		  NULL, 0);
    jsession_init(&jsoutput, jf, jdirection, 
		  output_transid_file, output_transid);
    jsession_init(&jsmirror, jf, jdirection,
		  mirror_transid_file, mirror_transid);
    jsmirror.ss_mirror_directory = mirror_directory;

    while (jd != NULL) {
	if ((jmodes & JMODEF_DEBUG) && jsession_check(&jsdebug, jd))
	    dump_debug(&jsdebug, jd);
	if ((jmodes & JMODEF_OUTPUT) && jsession_check(&jsoutput, jd))
	    dump_output(&jsoutput, jd);
	if ((jmodes & JMODEF_MIRROR) && jsession_check(&jsmirror, jd))
	    dump_mirror(&jsmirror, jd);
	if (donecheck(jdirection, jd, transid)) {
	    jfree(jf, jd);
	    break;
	}
	jd = jread(jf, jd, jdirection);
    }
    jclose(jf);
    jsession_term(&jsdebug);
    jsession_term(&jsoutput);
    jsession_term(&jsmirror);
    return(0);
}