Example #1
0
int erts_run_erl_log_activity(int timeout,time_t now,time_t last_activity) {
  char log_alive_buffer[ALIVE_BUFFSIZ+1];
  char buf[BUFSIZ];

  if (timeout || now - last_activity > LOG_ACTIVITY_MINUTES*60) {
    /* Either a time out: 15 minutes without action, */
    /* or something is coming in right now, but it's a long time */
    /* since last time, so let's write a time stamp this message */
    struct tm *tmptr;
    if (LOG_ALIVE_IN_GMT) {
      tmptr = gmtime(&now);
    } else {
      tmptr = localtime(&now);
    }
    if (!strftime(log_alive_buffer, ALIVE_BUFFSIZ, LOG_ALIVE_FORMAT,
		  tmptr)) {
      strn_cpy(log_alive_buffer, sizeof(log_alive_buffer),
	       "(could not format time in 256 positions "
	       "with current format string.)");
    }
    log_alive_buffer[ALIVE_BUFFSIZ] = '\0';

    sn_printf(buf, sizeof(buf), "\n===== %s%s\n",
	      timeout?"ALIVE ":"", log_alive_buffer);
    return erts_run_erl_log_write(buf, strlen(buf));
  }
  return 0;
}
Example #2
0
main()
{
	char s[] = "Amelia";
	char t[] = "Fazackerley";
	strn_cpy(t, s, 5);
	printf("%s\n", s);
	return 0;
}
Example #3
0
static int open_log(int log_num, int flags)
{
  char buf[FILENAME_MAX];
  time_t now;
  struct tm *tmptr;
  char log_buffer[ALIVE_BUFFSIZ+1];

  /* Remove the next log (to keep a "hole" in the log sequence) */
  sn_printf(buf, sizeof(buf), "%s/%s%d",
	    LOG_DIR, LOG_STUBNAME, next_log(log_num));
  unlink(buf);

  /* Create or continue on the current log file */
  sn_printf(buf, sizeof(buf), "%s/%s%d", LOG_DIR, LOG_STUBNAME, log_num);

  LFD = sf_open(buf, flags, LOG_PERM);

  if(LFD <0){
      ERRNO_ERR1(LOG_ERR,"Can't open log file '%s'.", buf);
    exit(1);
  }

  /* Write a LOGGING STARTED and time stamp into the log file */
  time(&now);
  if (LOG_ALIVE_IN_GMT) {
      tmptr = gmtime(&now);
  } else {
      tmptr = localtime(&now);
  }
  if (!strftime(log_buffer, ALIVE_BUFFSIZ, LOG_ALIVE_FORMAT,
		tmptr)) {
      strn_cpy(log_buffer, sizeof(log_buffer),
	      "(could not format time in 256 positions "
	      "with current format string.)");
  }
  log_buffer[ALIVE_BUFFSIZ] = '\0';

  sn_printf(buf, sizeof(buf), "\n=====\n===== LOGGING STARTED %s\n=====\n",
	    log_buffer);
  if (erts_run_erl_write_all(LFD, buf, strlen(buf)) < 0)
      erts_run_erl_log_status("Error in writing to log.\n");

#if USE_FSYNC
  fsync(LFD);
#endif

  return LFD;
}
Example #4
0
/* pass_on()
 * Is the work loop of the logger. Selects on the pipe to the to_erl
 * program erlang. If input arrives from to_erl it is passed on to
 * erlang.
 */
static void pass_on(pid_t childpid)
{
    int len;
    fd_set readfds;
    fd_set writefds;
    fd_set* writefds_ptr;
    struct timeval timeout;
    time_t last_activity;
    char buf[BUFSIZ];
    char log_alive_buffer[ALIVE_BUFFSIZ+1];
    int lognum;
    int rfd, wfd=0, lfd=0;
    int maxfd;
    int ready;
    int got_some = 0; /* from to_erl */
    
    /* Open the to_erl pipe for reading.
     * We can't open the writing side because nobody is reading and 
     * we'd either hang or get an error.
     */
    if ((rfd = sf_open(fifo2, O_RDONLY|DONT_BLOCK_PLEASE, 0)) < 0) {
	ERRNO_ERR1(LOG_ERR,"Could not open FIFO '%s' for reading.", fifo2);
	exit(1);
    }
    
#ifdef DEBUG
    status("run_erl: %s opened for reading\n", fifo2);
#endif
    
    /* Open the log file */
    
    lognum = find_next_log_num();
    lfd = open_log(lognum, O_RDWR|O_APPEND|O_CREAT|O_SYNC);
    
    /* Enter the work loop */
    
    while (1) {
	int exit_status;
	maxfd = MAX(rfd, mfd);
	maxfd = MAX(wfd, maxfd);
	FD_ZERO(&readfds);
	FD_SET(rfd, &readfds);
	FD_SET(mfd, &readfds);
	FD_ZERO(&writefds);
	if (outbuf_size() == 0) {
	    writefds_ptr = NULL;
	} else {
	    FD_SET(wfd, &writefds);
	    writefds_ptr = &writefds;
	}
	time(&last_activity);
	timeout.tv_sec  = log_alive_minutes*60; /* don't assume old BSD bug */
	timeout.tv_usec = 0;
	ready = select(maxfd + 1, &readfds, writefds_ptr, NULL, &timeout);
	if (ready < 0) {
	    if (errno == EINTR) {
		if (waitpid(childpid, &exit_status, WNOHANG) == childpid) {
		    /*
		     * The Erlang emulator has terminated. Give us some more
		     * time to write out any pending data before we terminate too.
		     */
		    alarm(5);
		}
		FD_ZERO(&readfds);
		FD_ZERO(&writefds);
	    } else {
		/* Some error occured */
		ERRNO_ERR0(LOG_ERR,"Error in select.");
		exit(1);
	    }
	} else {
	    time_t now;

	    if (waitpid(childpid, &exit_status, WNOHANG) == childpid) {
		alarm(5);
		FD_ZERO(&readfds);
		FD_ZERO(&writefds);
	    }

	    /* Check how long time we've been inactive */
	    time(&now);
	    if(!ready || now - last_activity > log_activity_minutes*60) {
		/* Either a time out: 15 minutes without action, */
		/* or something is coming in right now, but it's a long time */
		/* since last time, so let's write a time stamp this message */
		struct tm *tmptr;
		if (log_alive_in_gmt) {
		    tmptr = gmtime(&now);
		} else {
		    tmptr = localtime(&now);
		}
		if (!strftime(log_alive_buffer, ALIVE_BUFFSIZ, log_alive_format,
			      tmptr)) {
		    strn_cpy(log_alive_buffer, sizeof(log_alive_buffer),
			     "(could not format time in 256 positions "
			     "with current format string.)");
		}
		log_alive_buffer[ALIVE_BUFFSIZ] = '\0';

		sn_printf(buf, sizeof(buf), "\n===== %s%s\n", 
			  ready?"":"ALIVE ", log_alive_buffer);
		write_to_log(&lfd, &lognum, buf, strlen(buf));
	    }
	}

	/*
	 * Write any pending output first.
	 */
	if (FD_ISSET(wfd, &writefds)) {
	    int written;
	    char* buf = outbuf_first();

	    len = outbuf_size();
	    written = sf_write(wfd, buf, len);
	    if (written < 0 && errno == EAGAIN) {
		/*
		 * Nothing was written - this is really strange because
		 * select() told us we could write. Ignore.
		 */
	    } else if (written < 0) {
		/*
		 * A write error. Assume that to_erl has terminated.
		 */
		clear_outbuf();
		sf_close(wfd);
		wfd = 0;
	    } else {
		/* Delete the written part (or all) from the buffer. */
		outbuf_delete(written);
	    }
	}
	
	/*
	 * Read master pty and write to FIFO.
	 */
	if (FD_ISSET(mfd, &readfds)) {
#ifdef DEBUG
	    status("Pty master read; ");
#endif
	    if ((len = sf_read(mfd, buf, BUFSIZ)) <= 0) {
		sf_close(rfd);
		if(wfd) sf_close(wfd);
		sf_close(mfd);
		unlink(fifo1);
		unlink(fifo2);
		if (len < 0) {
		    if(errno == EIO)
			ERROR0(LOG_ERR,"Erlang closed the connection.");
		    else
			ERRNO_ERR0(LOG_ERR,"Error in reading from terminal");
		    exit(1);
		}
		exit(0);
	    }

	    write_to_log(&lfd, &lognum, buf, len);

	    /*
	     * Save in the output queue.
	     */

	    if (wfd) {
		outbuf_append(buf, len);
	    }
	}	    

	/*
	 * Read from FIFO, write to master pty
	 */
	if (FD_ISSET(rfd, &readfds)) {
#ifdef DEBUG
	    status("FIFO read; ");
#endif
	    if ((len = sf_read(rfd, buf, BUFSIZ)) < 0) {
		sf_close(rfd);
		if(wfd) sf_close(wfd);
		sf_close(mfd);
		unlink(fifo1);
		unlink(fifo2);
		ERRNO_ERR0(LOG_ERR,"Error in reading from FIFO.");
		exit(1);
	    }

	    if(!len) {
		/* to_erl closed its end of the pipe */
		sf_close(rfd);
		rfd = sf_open(fifo2, O_RDONLY|DONT_BLOCK_PLEASE, 0);
		if (rfd < 0) {
		    ERRNO_ERR1(LOG_ERR,"Could not open FIFO '%s' for reading.", fifo2);
		    exit(1);
		}
		got_some = 0; /* reset for next session */
	    }
	    else { 
		if(!wfd) {
		    /* Try to open the write pipe to to_erl. Now that we got some data
		     * from to_erl, to_erl should already be reading this pipe - open
		     * should succeed. But in case of error, we just ignore it.
		     */
		    if ((wfd = sf_open(fifo1, O_WRONLY|DONT_BLOCK_PLEASE, 0)) < 0) {
			status("Client expected on FIFO %s, but can't open (len=%d)\n",
			       fifo1, len);
			sf_close(rfd);
			rfd = sf_open(fifo2, O_RDONLY|DONT_BLOCK_PLEASE, 0);
			if (rfd < 0) {
			    ERRNO_ERR1(LOG_ERR,"Could not open FIFO '%s' for reading.", fifo2);
			    exit(1);
			}
			wfd = 0;
		    } 
		    else {
#ifdef DEBUG
			status("run_erl: %s opened for writing\n", fifo1);
#endif
		    }
		}

		if (!got_some && wfd && buf[0] == '\014') {
		    char wbuf[30];
		    int wlen = sn_printf(wbuf,sizeof(wbuf),"[run_erl v%u-%u]\n",
					 RUN_ERL_HI_VER, RUN_ERL_LO_VER);
		    outbuf_append(wbuf,wlen);
		}
		got_some = 1;


		/* Write the message */
#ifdef DEBUG
		status("Pty master write; ");
#endif
		len = extract_ctrl_seq(buf, len);

		if(len==1 && buf[0] == '\003') {
		    kill(childpid,SIGINT);
		} 
		else if (len>0 && write_all(mfd, buf, len) != len) {
		    ERRNO_ERR0(LOG_ERR,"Error in writing to terminal.");
		    sf_close(rfd);
		    if(wfd) sf_close(wfd);
		    sf_close(mfd);
		    exit(1);
		}
	    }
#ifdef DEBUG
	    status("OK\n");
#endif
	}
    }
} /* pass_on() */
Example #5
0
int main(int argc, char **argv)
{
  int childpid;
  int sfd = -1;
  int fd;
  char *p, *ptyslave=NULL;
  int i = 1;
  int off_argv;
  int calculated_pipename = 0;
  int highest_pipe_num = 0;

  program_name = argv[0];

  if(argc<4) {
    usage(argv[0]);
    exit(1);
  }

  init_outbuf();

  if (!strcmp(argv[1],"-daemon")) {
      daemon_init();
      ++i;
  }

  off_argv = i;
  strn_cpy(pipename, sizeof(pipename), argv[i++]);
  strn_cpy(log_dir, sizeof(log_dir), argv[i]);
  strn_cpy(statusfile, sizeof(statusfile), log_dir);
  strn_cat(statusfile, sizeof(statusfile), STATUSFILENAME);

#ifdef DEBUG
  status("%s: pid is : %d\n", argv[0], getpid());
#endif

  /* Get values for LOG file handling from the environment */
  if ((p = getenv("RUN_ERL_LOG_ALIVE_MINUTES"))) {
      log_alive_minutes = atoi(p);
      if (!log_alive_minutes) {
	  ERROR1(LOG_ERR,"Minimum value for RUN_ERL_LOG_ALIVE_MINUTES is 1 "
		 "(current value is %s)",p);
      }
      log_activity_minutes = log_alive_minutes / 3;
      if (!log_activity_minutes) {
	  ++log_activity_minutes;
      }
  }
  if ((p = getenv("RUN_ERL_LOG_ACTIVITY_MINUTES"))) {
     log_activity_minutes = atoi(p);
      if (!log_activity_minutes) {
	  ERROR1(LOG_ERR,"Minimum value for RUN_ERL_LOG_ACTIVITY_MINUTES is 1 "
		 "(current value is %s)",p);
      }
  } 
  if ((p = getenv("RUN_ERL_LOG_ALIVE_FORMAT"))) {
      if (strlen(p) > ALIVE_BUFFSIZ) {
	  ERROR1(LOG_ERR, "RUN_ERL_LOG_ALIVE_FORMAT can contain a maximum of "
		 "%d characters", ALIVE_BUFFSIZ);
      }
      strn_cpy(log_alive_format, sizeof(log_alive_format), p);
  } else {
      strn_cpy(log_alive_format, sizeof(log_alive_format), DEFAULT_LOG_ALIVE_FORMAT);
  }
  if ((p = getenv("RUN_ERL_LOG_ALIVE_IN_UTC")) && strcmp(p,"0")) {
      ++log_alive_in_gmt;
  }
  if ((p = getenv("RUN_ERL_LOG_GENERATIONS"))) {
    log_generations = atoi(p);
    if (log_generations < LOG_MIN_GENERATIONS)
      ERROR1(LOG_ERR,"Minimum RUN_ERL_LOG_GENERATIONS is %d", LOG_MIN_GENERATIONS);
    if (log_generations > LOG_MAX_GENERATIONS)
      ERROR1(LOG_ERR,"Maximum RUN_ERL_LOG_GENERATIONS is %d", LOG_MAX_GENERATIONS);
  }

  if ((p = getenv("RUN_ERL_LOG_MAXSIZE"))) {
    log_maxsize = atoi(p);
    if (log_maxsize < LOG_MIN_MAXSIZE)
      ERROR1(LOG_ERR,"Minimum RUN_ERL_LOG_MAXSIZE is %d", LOG_MIN_MAXSIZE);
  }

  /*
   * Create FIFOs and open them 
   */

  if(*pipename && pipename[strlen(pipename)-1] == '/') {
    /* The user wishes us to find a unique pipe name in the specified */
    /* directory */
    DIR *dirp;
    struct dirent *direntp;

    calculated_pipename = 1;
    dirp = opendir(pipename);
    if(!dirp) {
      ERRNO_ERR1(LOG_ERR,"Can't access pipe directory '%s'.", pipename);
      exit(1);
    }

    /* Check the directory for existing pipes */
    
    while((direntp=readdir(dirp)) != NULL) {
      if(strncmp(direntp->d_name,PIPE_STUBNAME,PIPE_STUBLEN)==0) {
	int num = atoi(direntp->d_name+PIPE_STUBLEN+1);
	if(num > highest_pipe_num)
	  highest_pipe_num = num;
      }
    }	
    closedir(dirp);
    strn_catf(pipename, sizeof(pipename), "%s.%d",
	      PIPE_STUBNAME, highest_pipe_num+1);
  } /* if */

  for(;;) {
      /* write FIFO - is read FIFO for `to_erl' program */
      strn_cpy(fifo1, sizeof(fifo1), pipename);
      strn_cat(fifo1, sizeof(fifo1), ".r");
      if (create_fifo(fifo1, PERM) < 0) {
	  ERRNO_ERR1(LOG_ERR,"Cannot create FIFO %s for writing.", fifo1);
	  exit(1);
      }
      
      /* read FIFO - is write FIFO for `to_erl' program */
      strn_cpy(fifo2, sizeof(fifo2), pipename);
      strn_cat(fifo2, sizeof(fifo2), ".w");
      
      /* Check that nobody is running run_erl already */
      if ((fd = sf_open(fifo2, O_WRONLY|DONT_BLOCK_PLEASE, 0)) >= 0) {
	  /* Open as client succeeded -- run_erl is already running! */
	  sf_close(fd);
	  if (calculated_pipename) {
	      ++highest_pipe_num;
	      strn_catf(pipename, sizeof(pipename), "%s.%d",
			PIPE_STUBNAME, highest_pipe_num+1);
	      continue;
	  } 
	  fprintf(stderr, "Erlang already running on pipe %s.\n", pipename);
	  exit(1);
      }
      if (create_fifo(fifo2, PERM) < 0) { 
	  ERRNO_ERR1(LOG_ERR,"Cannot create FIFO %s for reading.", fifo2);
	  exit(1);
      }
      break;
  }

  /*
   * Open master pseudo-terminal
   */

  if ((mfd = open_pty_master(&ptyslave, &sfd)) < 0) {
    ERRNO_ERR0(LOG_ERR,"Could not open pty master");
    exit(1);
  }

  /* 
   * Now create a child process
   */

  if ((childpid = fork()) < 0) {
    ERRNO_ERR0(LOG_ERR,"Cannot fork");
    exit(1);
  }
  if (childpid == 0) {
    /* Child */
    sf_close(mfd);
    /* disassociate from control terminal */
#ifdef USE_SETPGRP_NOARGS       /* SysV */
    setpgrp();
#elif defined(USE_SETPGRP)       /* BSD */
    setpgrp(0,getpid());
#else                           /* POSIX */
    setsid();
#endif
    /* Open the slave pty */
    if (sfd < 0) {
	/* not allocated by open_pty_master */
	if ((sfd = open_pty_slave(ptyslave)) < 0) {
	    ERRNO_ERR1(LOG_ERR,"Could not open pty slave '%s'", ptyslave);
	    exit(1);
	}
	/* But sfd may be one of the stdio fd's now, and we should be unmodern and not use dup2... */
	/* easiest to dup it up... */
	while (sfd < 3) {
	    sfd = dup(sfd);
	}
    }
#if defined(HAVE_OPENPTY) && defined(TIOCSCTTY)
    else {
	/* sfd is from open_pty_master 
	 * openpty -> fork -> login_tty (forkpty)
	 * 
	 * It would be preferable to implement a portable 
	 * forkpty instead of open_pty_master / open_pty_slave
	 */
	/* login_tty(sfd);  <- FAIL */
	ioctl(sfd, TIOCSCTTY, (char *)NULL);
    }
#endif

#ifndef NO_SYSLOG
    /* Before fiddling with file descriptors we make sure syslog is turned off
       or "closed". In the single case where we might want it again, 
       we will open it again instead. Would not want syslog to
       go to some other fd... */
    if (run_daemon) {
	closelog();
    }
#endif

    /* Close stdio */
    sf_close(0);
    sf_close(1);
    sf_close(2);

    if (dup(sfd) != 0 || dup(sfd) != 1 || dup(sfd) != 2) {
      status("Cannot dup\n");
    }
    sf_close(sfd);
    exec_shell(argv+off_argv); /* exec_shell expects argv[2] to be */
                        /* the command name, so we have to */
                        /* adjust. */
  } else {
    /* Parent */
    /* Ignore the SIGPIPE signal, write() will return errno=EPIPE */
    struct sigaction sig_act;
    sigemptyset(&sig_act.sa_mask);
    sig_act.sa_flags = 0;
    sig_act.sa_handler = SIG_IGN;
    sigaction(SIGPIPE, &sig_act, (struct sigaction *)NULL);

    sigemptyset(&sig_act.sa_mask);
    sig_act.sa_flags = SA_NOCLDSTOP;
    sig_act.sa_handler = catch_sigchild;
    sigaction(SIGCHLD, &sig_act, (struct sigaction *)NULL);

    /*
     * read and write: enter the workloop
     */

    pass_on(childpid);
  }
  return 0;
} /* main() */
Example #6
0
File: to_erl.c Project: cabrero/otp
int main(int argc, char **argv)
{
    char  FIFO1[FILENAME_MAX], FIFO2[FILENAME_MAX];
    int i, len, wfd, rfd;
    fd_set readfds;
    char buf[BUFSIZ];
    char pipename[FILENAME_MAX];
    int pipeIx = 1;
    int force_lock = 0;
    int got_some = 0;

    if (argc >= 2 && argv[1][0]=='-') {
	switch (argv[1][1]) {
	case 'h':
	    usage(argv[0]);
	    exit(1);
	case 'F':
	    force_lock = 1;
	    break;
	default:
	    fprintf(stderr,"Invalid option '%s'\n",argv[1]);
	    exit(1);
	}
	pipeIx = 2;
    }
    
#ifdef DEBUG
    fprintf(stderr, "%s: pid is : %d\n", argv[0], (int)getpid());
#endif
    
    strn_cpy(pipename, sizeof(pipename),
	     (argv[pipeIx] ? argv[pipeIx] : PIPE_DIR));
    
    if(*pipename && pipename[strlen(pipename)-1] == '/') {
	/* The user wishes us to find a pipe name in the specified */
	/* directory */
	int highest_pipe_num = 0;
	DIR *dirp;
	struct dirent *direntp;

	dirp = opendir(pipename);
	if(!dirp) {
	    fprintf(stderr, "Can't access pipe directory %s: %s\n", pipename, strerror(errno));
	    exit(1);
	}

	/* Check the directory for existing pipes */
    
	while((direntp=readdir(dirp)) != NULL) {
	    if(strncmp(direntp->d_name,PIPE_STUBNAME,PIPE_STUBLEN)==0) {
		int num = atoi(direntp->d_name+PIPE_STUBLEN+1);
		if(num > highest_pipe_num)
		    highest_pipe_num = num;
	    }
	}	
	closedir(dirp);
	strn_catf(pipename, sizeof(pipename), (highest_pipe_num?"%s.%d":"%s"),
		  PIPE_STUBNAME, highest_pipe_num);
    } /* if */

    /* read FIFO */
    sn_printf(FIFO1,sizeof(FIFO1),"%s.r",pipename);
    /* write FIFO */
    sn_printf(FIFO2,sizeof(FIFO2),"%s.w",pipename);

    /* Check that nobody is running to_erl on this pipe already */
    if ((wfd = open (FIFO1, O_WRONLY|DONT_BLOCK_PLEASE, 0)) >= 0) {
	/* Open as server succeeded -- to_erl is already running! */
	close(wfd);
	fprintf(stderr, "Another to_erl process already attached to pipe "
			"%s.\n", pipename);
	if (force_lock) {
	    fprintf(stderr, "But we proceed anyway by force (-F).\n");
	} 
	else {
	    exit(1);
	}
    }

    if ((rfd = open (FIFO1, O_RDONLY|DONT_BLOCK_PLEASE, 0)) < 0) {
#ifdef DEBUG
	fprintf(stderr, "Could not open FIFO %s for reading.\n", FIFO1);
#endif
	fprintf(stderr, "No running Erlang on pipe %s: %s\n", pipename, strerror(errno));
	exit(1);
    }
#ifdef DEBUG
    fprintf(stderr, "to_erl: %s opened for reading\n", FIFO1);
#endif
    
    if ((wfd = open (FIFO2, O_WRONLY|DONT_BLOCK_PLEASE, 0)) < 0) {
#ifdef DEBUG
	fprintf(stderr, "Could not open FIFO %s for writing.\n", FIFO2);
#endif
	fprintf(stderr, "No running Erlang on pipe %s: %s\n", pipename, strerror(errno));
	close(rfd);
	exit(1);
    }
#ifdef DEBUG
    fprintf(stderr, "to_erl: %s opened for writing\n", FIFO2);
#endif
    
    fprintf(stderr, "Attaching to %s (^D to exit)\n\n", pipename);
    
    /* Set break handler to our handler */
    signal(SIGINT,handle_ctrlc);

    /* 
     * Save the current state of the terminal, and set raw mode.
     */
    if (tcgetattr(0, &tty_rmode) , 0) {
	fprintf(stderr, "Cannot get terminals current mode\n");
	exit(-1);
    }
    tty_smode = tty_rmode;
    tty_eof = '\004'; /* Ctrl+D to exit */
#ifdef DEBUG
    show_terminal_settings(&tty_rmode);
#endif
    tty_smode.c_iflag =
	1*BRKINT |/*Signal interrupt on break.*/
	    1*IGNPAR |/*Ignore characters with parity errors.*/
		1*ISTRIP |/*Strip character.*/
		    0;
    
#if 0
0*IGNBRK |/*Ignore break condition.*/
0*PARMRK |/*Mark parity errors.*/
0*INPCK  |/*Enable input parity check.*/
0*INLCR  |/*Map NL to CR on input.*/
0*IGNCR  |/*Ignore CR.*/
0*ICRNL  |/*Map CR to NL on input.*/
0*IUCLC  |/*Map upper-case to lower-case on input.*/
0*IXON   |/*Enable start/stop output control.*/
0*IXANY  |/*Enable any character to restart output.*/
0*IXOFF  |/*Enable start/stop input control.*/
0*IMAXBEL|/*Echo BEL on input line too long.*/
#endif
						
    tty_smode.c_oflag =
	1*OPOST  |/*Post-process output.*/
	    1*ONLCR  |/*Map NL to CR-NL on output.*/
#ifdef XTABS
		1*XTABS  |/*Expand tabs to spaces. (Linux)*/
#endif
#ifdef OXTABS
		    1*OXTABS  |/*Expand tabs to spaces. (FreeBSD)*/
#endif
#ifdef NL0
			1*NL0    |/*Select newline delays*/
#endif
#ifdef CR0
			    1*CR0    |/*Select carriage-return delays*/
#endif
#ifdef TAB0
				1*TAB0   |/*Select horizontal tab delays*/
#endif
#ifdef BS0
				    1*BS0    |/*Select backspace delays*/
#endif
#ifdef VT0
					1*VT0    |/*Select vertical tab delays*/
#endif
#ifdef FF0
					    1*FF0    |/*Select form feed delays*/
#endif
											    0;
    
#if 0
0*OLCUC  |/*Map lower case to upper on output.*/
0*OCRNL  |/*Map CR to NL on output.*/
0*ONOCR  |/*No CR output at column 0.*/
0*ONLRET |/*NL performs CR function.*/
0*OFILL  |/*Use fill characters for delay.*/
0*OFDEL  |/*Fill is DEL, else NULL.*/
0*NL1    |
0*CR1    |
0*CR2    |
0*CR3    |
0*TAB1   |
0*TAB2   |
0*TAB3   |/*Expand tabs to spaces.*/
0*BS1    |
0*VT1    |
0*FF1    |
#endif
								    
    /* JALI: removed setting the tty_smode.c_cflag flags, since this is not */
    /* advisable if this is a *real* terminal, such as the console. In fact */
    /* this may hang the entire machine, deep, deep down (signalling break */
    /* or toggling the abort switch doesn't help) */
    
    tty_smode.c_lflag =
									0;
    
#if 0
0*ISIG   |/*Enable signals.*/
0*ICANON |/*Canonical input (erase and kill processing).*/
0*XCASE  |/*Canonical upper/lower presentation.*/
0*ECHO   |/*Enable echo.*/
0*ECHOE  |/*Echo erase character as BS-SP-BS.*/
0*ECHOK  |/*Echo NL after kill character.*/
0*ECHONL |/*Echo NL.*/
0*NOFLSH |/*Disable flush after interrupt or quit.*/
0*TOSTOP |/*Send SIGTTOU for background output.*/
0*ECHOCTL|/*Echo control characters as ^char, delete as ^?.*/
0*ECHOPRT|/*Echo erase character as character erased.*/
0*ECHOKE |/*BS-SP-BS erase entire line on line kill.*/
0*FLUSHO |/*Output is being flushed.*/
0*PENDIN |/*Retype pending input at next read or input character.*/
0*IEXTEN |/*Enable extended (implementation-defined) functions.*/
#endif
								
    tty_smode.c_cc[VMIN]      =0;/* Note that VMIN is the same as VEOF! */
    tty_smode.c_cc[VTIME]     =0;/* Note that VTIME is the same as VEOL! */
    tty_smode.c_cc[VINTR]     =3;
    
    tcsetattr(0, TCSANOW, &tty_smode);
    
#ifdef DEBUG
    show_terminal_settings(&tty_smode);
#endif
    /*
     * 	 "Write a ^R to the FIFO which causes the other end to redisplay
     *    the input line."
     * This does not seem to work as was intended in old comment above.
     * However, this control character is now (R12B-3) used by run_erl
     * to trigger the version handshaking between to_erl and run_erl
     * at the start of every new to_erl-session.
     */

    if (write(wfd, "\014", 1) < 0) {
	fprintf(stderr, "Error in writing ^R to FIFO.\n");
    }

    /*
     * read and write
     */
    while (1) {
	FD_ZERO(&readfds);
	FD_SET(0, &readfds);
	FD_SET(rfd, &readfds);
	if (select(rfd + 1, &readfds, NULL, NULL, NULL) < 0) {
	    if (recv_sig) {
		FD_ZERO(&readfds);
	    }
	    else {
		fprintf(stderr, "Error in select.\n");
		break;
	    }
	}
	len = 0;

	/*
	 * Read from terminal and write to FIFO
         */
	if (recv_sig) {
	    switch (recv_sig) {
	    case SIGINT:
		fprintf(stderr, "[Break]\n\r");
		buf[0] = '\003';
		len = 1;
		break;
	    case SIGWINCH:
		len = window_size_seq(buf,sizeof(buf));
		break;
	    default:
		fprintf(stderr,"Unexpected signal: %u\n",recv_sig);
	    }
	    recv_sig = 0;
	}
	else if (FD_ISSET(0, &readfds)) {
	    len = read(0, buf, sizeof(buf));
	    if (len <= 0) {
		close(rfd);
		close(wfd);
		if (len < 0) {
		    fprintf(stderr, "Error in reading from stdin.\n");
		} else {
		    fprintf(stderr, "[EOF]\n\r");
		}
		break;
	    }
	    /* check if there is an eof character in input */
	    for (i = 0; i < len && buf[i] != tty_eof; i++);
	    if (buf[i] == tty_eof) {
		fprintf(stderr, "[Quit]\n\r");
		break;
	    }
	}

	if (len) {
#ifdef DEBUG
	    if(write(1, buf, len));
#endif
	    if (write_all(wfd, buf, len) != len) {
		fprintf(stderr, "Error in writing to FIFO.\n");
		close(rfd);
		close(wfd);
		break;
	    }
	    STATUS("\" OK\r\n");
	}

	/*
	 * Read from FIFO, write to terminal.
	 */
	if (FD_ISSET(rfd, &readfds)) {
	    STATUS("FIFO read: ");
	    len = read(rfd, buf, BUFSIZ);
	    if (len < 0 && errno == EAGAIN) {
		/*
		 * No data this time, but the writing end of the FIFO is still open.
		 * Do nothing.
		 */
		;
	    } else if (len <= 0) {
		/*
		 * Either an error or end of file. In either case, break out
		 * of the loop.
		 */
		close(rfd);
		close(wfd);
		if (len < 0) {
		    fprintf(stderr, "Error in reading from FIFO.\n");
		} else
		    fprintf(stderr, "[End]\n\r");
		break;
	    } else {
		if (!got_some) {
		    if ((len=version_handshake(buf,len,wfd)) < 0) {
			close(rfd);
			close(wfd);
			break;
		    }
		    if (protocol_ver >= 1) {
			/* Tell run_erl size of terminal window */
			signal(SIGWINCH, handle_sigwinch);
			raise(SIGWINCH);
		    }
		    got_some = 1;
		}

		/*
		 * We successfully read at least one character. Write what we got.
		 */
		STATUS("Terminal write: \"");
		if (write_all(1, buf, len) != len) {
		    fprintf(stderr, "Error in writing to terminal.\n");
		    close(rfd);
		    close(wfd);
		    break;
		}
		STATUS("\" OK\r\n");
	    }
	}
    }

    /* 
     * Reset terminal characterstics 
     * XXX
     */
    tcsetattr(0, TCSANOW, &tty_rmode);
    return 0;
}
Example #7
0
/*
 * w- and r_pipename have to be pre-allocated of atleast FILENAME_MAX size
 */
int erts_run_erl_open_fifo(char *pipename,char *w_pipename,char *r_pipename) {
  int calculated_pipename = 0;
  int highest_pipe_num = 0;
  int fd;

  /*
   * Create FIFOs and open them
   */

  if(*pipename && pipename[strlen(pipename)-1] == '/') {
    /* The user wishes us to find a unique pipe name in the specified */
    /* directory */
    DIR *dirp;
    struct dirent *direntp;

    calculated_pipename = 1;
    dirp = opendir(pipename);
    if(!dirp) {
      ERRNO_ERR1(LOG_ERR,"Can't access pipe directory '%s'.", pipename);
      return 1;
    }

    /* Check the directory for existing pipes */

    while((direntp=readdir(dirp)) != NULL) {
      if(strncmp(direntp->d_name,PIPE_STUBNAME,PIPE_STUBLEN)==0) {
	int num = atoi(direntp->d_name+PIPE_STUBLEN+1);
	if(num > highest_pipe_num)
	  highest_pipe_num = num;
      }
    }
    closedir(dirp);
    strn_catf(pipename, BUFSIZ, "%s.%d",
	      PIPE_STUBNAME, highest_pipe_num+1);
  } /* if */

  for(;;) {
      /* write FIFO - is read FIFO for `to_erl' program */
      strn_cpy(w_pipename, BUFSIZ, pipename);
      strn_cat(w_pipename, BUFSIZ, ".r");
      if (create_fifo(w_pipename, PERM) < 0) {
	  ERRNO_ERR1(LOG_ERR,"Cannot create FIFO %s for writing.",
		     w_pipename);
	  return 1;
      }

      /* read FIFO - is write FIFO for `to_erl' program */
      strn_cpy(r_pipename, BUFSIZ, pipename);
      strn_cat(r_pipename, BUFSIZ, ".w");

      /* Check that nobody is running run_erl already */
      if ((fd = sf_open(r_pipename, O_WRONLY|DONT_BLOCK_PLEASE, 0)) >= 0) {
	  /* Open as client succeeded -- run_erl is already running! */
	  sf_close(fd);
	  if (calculated_pipename) {
	      ++highest_pipe_num;
	      strn_catf(pipename, BUFSIZ, "%s.%d",
			PIPE_STUBNAME, highest_pipe_num+1);
	      continue;
	  }
	  ERROR1(LOG_ERR, "Erlang already running on pipe %s.\n", pipename);
	  unlink(w_pipename);
	  return 1;
      }
      if (create_fifo(r_pipename, PERM) < 0) {
	  unlink(w_pipename);
	  ERRNO_ERR1(LOG_ERR,"Cannot create FIFO %s for reading.",
		     r_pipename);
	  return 1;
      }
      break;
  }
  return 0;
}
Example #8
0
int erts_run_erl_log_init(int daemon, char* logdir) {
  char *p;

#ifdef __OSE__
  run_erl **re_pp;
  if (!run_erl_pp_key)
     ose_create_ppdata("run_erl_ppdata",&run_erl_pp_key);
  re_pp = (run_erl **)ose_get_ppdata(run_erl_pp_key);
  *re_pp = malloc(sizeof(run_erl));
#endif

  STDSTATUS = NULL;
  LOG_GENERATIONS = DEFAULT_LOG_GENERATIONS;
  LOG_MAXSIZE     = DEFAULT_LOG_MAXSIZE;
  LOG_ACTIVITY_MINUTES = DEFAULT_LOG_ACTIVITY_MINUTES;
  LOG_ALIVE_IN_GMT = 0;
  RUN_DAEMON = 0;
  LOG_ALIVE_MINUTES = DEFAULT_LOG_ALIVE_MINUTES;
  LFD = 0;
  PROTOCOL_VER = RUN_ERL_LO_VER; /* assume lowest to begin with */

  /* Get values for LOG file handling from the environment */
  if ((p = getenv_int("RUN_ERL_LOG_ALIVE_MINUTES"))) {
      LOG_ALIVE_MINUTES = atoi(p);
      if (!LOG_ALIVE_MINUTES) {
	  ERROR1(LOG_ERR,"Minimum value for RUN_ERL_LOG_ALIVE_MINUTES is 1 "
		 "(current value is %s)",p);
      }
      LOG_ACTIVITY_MINUTES = LOG_ALIVE_MINUTES / 3;
      if (!LOG_ACTIVITY_MINUTES) {
	  ++LOG_ACTIVITY_MINUTES;
      }
  }
  if ((p = getenv_int(
		   "RUN_ERL_LOG_ACTIVITY_MINUTES"))) {
     LOG_ACTIVITY_MINUTES = atoi(p);
      if (!LOG_ACTIVITY_MINUTES) {
	  ERROR1(LOG_ERR,"Minimum value for RUN_ERL_LOG_ACTIVITY_MINUTES is 1 "
		 "(current value is %s)",p);
      }
  }
  if ((p = getenv_int("RUN_ERL_LOG_ALIVE_FORMAT"))) {
      if (strlen(p) > ALIVE_BUFFSIZ) {
	  ERROR1(LOG_ERR, "RUN_ERL_LOG_ALIVE_FORMAT can contain a maximum of "
		 "%d characters", ALIVE_BUFFSIZ);
      }
      strn_cpy(LOG_ALIVE_FORMAT, sizeof(LOG_ALIVE_FORMAT), p);
  } else {
      strn_cpy(LOG_ALIVE_FORMAT, sizeof(LOG_ALIVE_FORMAT),
	       DEFAULT_LOG_ALIVE_FORMAT);
  }
  if ((p = getenv_int("RUN_ERL_LOG_ALIVE_IN_UTC"))
      && strcmp(p,"0")) {
      ++LOG_ALIVE_IN_GMT;
  }
  if ((p = getenv_int("RUN_ERL_LOG_GENERATIONS"))) {
    LOG_GENERATIONS = atoi(p);
    if (LOG_GENERATIONS < LOG_MIN_GENERATIONS)
      ERROR1(LOG_ERR,"Minimum RUN_ERL_LOG_GENERATIONS is %d",
	     LOG_MIN_GENERATIONS);
    if (LOG_GENERATIONS > LOG_MAX_GENERATIONS)
      ERROR1(LOG_ERR,"Maximum RUN_ERL_LOG_GENERATIONS is %d",
	     LOG_MAX_GENERATIONS);
  }

  if ((p = getenv_int("RUN_ERL_LOG_MAXSIZE"))) {
    LOG_MAXSIZE = atoi(p);
    if (LOG_MAXSIZE < LOG_MIN_MAXSIZE)
      ERROR1(LOG_ERR,"Minimum RUN_ERL_LOG_MAXSIZE is %d", LOG_MIN_MAXSIZE);
  }

  RUN_DAEMON = daemon;

  strn_cpy(LOG_DIR, sizeof(LOG_DIR), logdir);
  strn_cpy(STATUSFILE, sizeof(STATUSFILE), LOG_DIR);
  strn_cat(STATUSFILE, sizeof(STATUSFILE), STATUSFILENAME);

  return 0;
}
Example #9
0
int to_erl(int argc, char **argv)
{
    char  FIFO1[FILENAME_MAX], FIFO2[FILENAME_MAX];
    int i, len, wfd, rfd;
    char pipename[FILENAME_MAX];
    int pipeIx = 1;
    int force_lock = 0;
    int got_some = 0;

#ifdef __OSE__
    struct aiocb stdin_read_req, pipe_read_req;
    FmHandle stdin_fh, pipe_fh;
    char *stdin_buf, *pipe_buf;
    char *buf;
    union SIGNAL *sig;
#else /* __UNIX__ */
    char buf[BUFSIZ];
    fd_set readfds;
#endif

    if (argc >= 2 && argv[1][0]=='-') {
	switch (argv[1][1]) {
	case 'h':
	    usage(argv[0]);
	    exit(1);
	case 'F':
	    force_lock = 1;
	    break;
	default:
	    fprintf(stderr,"Invalid option '%s'\n",argv[1]);
	    exit(1);
	}
	pipeIx = 2;
    }

#ifdef DEBUG
    fprintf(stderr, "%s: pid is : %d\n", argv[0],(int)
#ifdef __OSE__
	    current_process()
#else /* __UNIX__ */
	    getpid()
#endif
	    );
#endif

    strn_cpy(pipename, sizeof(pipename),
	     (argv[pipeIx] ? argv[pipeIx] : PIPE_DIR));

    if(*pipename && pipename[strlen(pipename)-1] == '/') {
	/* The user wishes us to find a pipe name in the specified */
	/* directory */
	int highest_pipe_num = 0;
	DIR *dirp;
	struct dirent *direntp;

	dirp = opendir(pipename);
	if(!dirp) {
	    fprintf(stderr, "Can't access pipe directory %s: %s\n", pipename, strerror(errno));
	    exit(1);
	}

	/* Check the directory for existing pipes */

	while((direntp=readdir(dirp)) != NULL) {
	    if(strncmp(direntp->d_name,PIPE_STUBNAME,PIPE_STUBLEN)==0) {
		int num = atoi(direntp->d_name+PIPE_STUBLEN+1);
		if(num > highest_pipe_num)
		    highest_pipe_num = num;
	    }
	}
	closedir(dirp);
	strn_catf(pipename, sizeof(pipename), (highest_pipe_num?"%s.%d":"%s"),
		  PIPE_STUBNAME, highest_pipe_num);
    } /* if */

    /* read FIFO */
    sn_printf(FIFO1,sizeof(FIFO1),"%s.r",pipename);
    /* write FIFO */
    sn_printf(FIFO2,sizeof(FIFO2),"%s.w",pipename);

#ifndef __OSE__
    /* Check that nobody is running to_erl on this pipe already */
    if ((wfd = open (FIFO1, O_WRONLY|DONT_BLOCK_PLEASE, 0)) >= 0) {
	/* Open as server succeeded -- to_erl is already running! */
	close(wfd);
	fprintf(stderr, "Another to_erl process already attached to pipe "
			"%s.\n", pipename);
	if (force_lock) {
	    fprintf(stderr, "But we proceed anyway by force (-F).\n");
	}
	else {
	    exit(1);
	}
    }
#endif

    if ((rfd = open (FIFO1, O_RDONLY|DONT_BLOCK_PLEASE, 0)) < 0) {
#ifdef DEBUG
	fprintf(stderr, "Could not open FIFO %s for reading.\n", FIFO1);
#endif
	fprintf(stderr, "No running Erlang on pipe %s: %s\n", pipename, strerror(errno));
	exit(1);
    }
#ifdef DEBUG
    fprintf(stderr, "to_erl: %s opened for reading\n", FIFO1);
#endif

    if ((wfd = open (FIFO2, O_WRONLY|DONT_BLOCK_PLEASE, 0)) < 0) {
#ifdef DEBUG
	fprintf(stderr, "Could not open FIFO %s for writing.\n", FIFO2);
#endif
	fprintf(stderr, "No running Erlang on pipe %s: %s\n", pipename, strerror(errno));
	close(rfd);
	exit(1);
    }
#ifdef DEBUG
    fprintf(stderr, "to_erl: %s opened for writing\n", FIFO2);
#endif

#ifndef __OSE__
    fprintf(stderr, "Attaching to %s (^D to exit)\n\n", pipename);
#else
    fprintf(stderr, "Attaching to %s (^C to exit)\n\n", pipename);
#endif

#ifndef __OSE__
    /* Set break handler to our handler */
    signal(SIGINT,handle_ctrlc);

    /*
     * Save the current state of the terminal, and set raw mode.
     */
    if (tcgetattr(0, &tty_rmode) , 0) {
	fprintf(stderr, "Cannot get terminals current mode\n");
	exit(-1);
    }
    tty_smode = tty_rmode;
    tty_eof = '\004'; /* Ctrl+D to exit */
#ifdef DEBUG
    show_terminal_settings(&tty_rmode);
#endif
    tty_smode.c_iflag =
	1*BRKINT |/*Signal interrupt on break.*/
	    1*IGNPAR |/*Ignore characters with parity errors.*/
		1*ISTRIP |/*Strip character.*/
		    0;

#if 0
0*IGNBRK |/*Ignore break condition.*/
0*PARMRK |/*Mark parity errors.*/
0*INPCK  |/*Enable input parity check.*/
0*INLCR  |/*Map NL to CR on input.*/
0*IGNCR  |/*Ignore CR.*/
0*ICRNL  |/*Map CR to NL on input.*/
0*IUCLC  |/*Map upper-case to lower-case on input.*/
0*IXON   |/*Enable start/stop output control.*/
0*IXANY  |/*Enable any character to restart output.*/
0*IXOFF  |/*Enable start/stop input control.*/
0*IMAXBEL|/*Echo BEL on input line too long.*/
#endif

    tty_smode.c_oflag =
	1*OPOST  |/*Post-process output.*/
	    1*ONLCR  |/*Map NL to CR-NL on output.*/
#ifdef XTABS
		1*XTABS  |/*Expand tabs to spaces. (Linux)*/
#endif
#ifdef OXTABS
		    1*OXTABS  |/*Expand tabs to spaces. (FreeBSD)*/
#endif
#ifdef NL0
			1*NL0    |/*Select newline delays*/
#endif
#ifdef CR0
			    1*CR0    |/*Select carriage-return delays*/
#endif
#ifdef TAB0
				1*TAB0   |/*Select horizontal tab delays*/
#endif
#ifdef BS0
				    1*BS0    |/*Select backspace delays*/
#endif
#ifdef VT0
					1*VT0    |/*Select vertical tab delays*/
#endif
#ifdef FF0
					    1*FF0    |/*Select form feed delays*/
#endif
											    0;

#if 0
0*OLCUC  |/*Map lower case to upper on output.*/
0*OCRNL  |/*Map CR to NL on output.*/
0*ONOCR  |/*No CR output at column 0.*/
0*ONLRET |/*NL performs CR function.*/
0*OFILL  |/*Use fill characters for delay.*/
0*OFDEL  |/*Fill is DEL, else NULL.*/
0*NL1    |
0*CR1    |
0*CR2    |
0*CR3    |
0*TAB1   |
0*TAB2   |
0*TAB3   |/*Expand tabs to spaces.*/
0*BS1    |
0*VT1    |
0*FF1    |
#endif

    /* JALI: removed setting the tty_smode.c_cflag flags, since this is not */
    /* advisable if this is a *real* terminal, such as the console. In fact */
    /* this may hang the entire machine, deep, deep down (signalling break */
    /* or toggling the abort switch doesn't help) */

    tty_smode.c_lflag =
									0;

#if 0
0*ISIG   |/*Enable signals.*/
0*ICANON |/*Canonical input (erase and kill processing).*/
0*XCASE  |/*Canonical upper/lower presentation.*/
0*ECHO   |/*Enable echo.*/
0*ECHOE  |/*Echo erase character as BS-SP-BS.*/
0*ECHOK  |/*Echo NL after kill character.*/
0*ECHONL |/*Echo NL.*/
0*NOFLSH |/*Disable flush after interrupt or quit.*/
0*TOSTOP |/*Send SIGTTOU for background output.*/
0*ECHOCTL|/*Echo control characters as ^char, delete as ^?.*/
0*ECHOPRT|/*Echo erase character as character erased.*/
0*ECHOKE |/*BS-SP-BS erase entire line on line kill.*/
0*FLUSHO |/*Output is being flushed.*/
0*PENDIN |/*Retype pending input at next read or input character.*/
0*IEXTEN |/*Enable extended (implementation-defined) functions.*/
#endif

    tty_smode.c_cc[VMIN]      =0;/* Note that VMIN is the same as VEOF! */
    tty_smode.c_cc[VTIME]     =0;/* Note that VTIME is the same as VEOL! */
    tty_smode.c_cc[VINTR]     =3;

    tcsetattr(0, TCSADRAIN, &tty_smode);

#ifdef DEBUG
    show_terminal_settings(&tty_smode);
#endif

#endif /* !__OSE__ */
    /*
     * 	 "Write a ^L to the FIFO which causes the other end to redisplay
     *    the input line."
     * This does not seem to work as was intended in old comment above.
     * However, this control character is now (R12B-3) used by run_erl
     * to trigger the version handshaking between to_erl and run_erl
     * at the start of every new to_erl-session.
     */

    if (write(wfd, "\014", 1) < 0) {
	fprintf(stderr, "Error in writing ^L to FIFO.\n");
    }

#ifdef __OSE__
    /* we have a tiny stack so we malloc the buffers */
    stdin_buf = malloc(sizeof(char) * BUFSIZ);
    pipe_buf = malloc(sizeof(char) * BUFSIZ);

    efs_examine_fd(rfd,FLIB_FD_HANDLE,&pipe_fh);
    efs_examine_fd(0,FLIB_FD_HANDLE,&stdin_fh);
    READ_AIO(stdin_read_req,0,BUFSIZ,stdin_buf);
    READ_AIO(pipe_read_req,rfd,BUFSIZ,pipe_buf);
#endif

    /*
     * read and write
     */
    while (1) {
#ifndef __OSE__
	FD_ZERO(&readfds);
	FD_SET(0, &readfds);
	FD_SET(rfd, &readfds);
	if (select(rfd + 1, &readfds, NULL, NULL, NULL) < 0) {
	    if (recv_sig) {
		FD_ZERO(&readfds);
	    }
	    else {
		fprintf(stderr, "Error in select.\n");
		break;
	    }
	}
	len = 0;

	/*
	 * Read from terminal and write to FIFO
         */
	if (recv_sig) {
	    switch (recv_sig) {
	    case SIGINT:
		fprintf(stderr, "[Break]\n\r");
		buf[0] = '\003';
		len = 1;
		break;
	    case SIGWINCH:
		len = window_size_seq(buf,sizeof(buf));
		break;
	    default:
		fprintf(stderr,"Unexpected signal: %u\n",recv_sig);
	    }
	    recv_sig = 0;
	}
	else
#else /* __OSE__ */
	SIGSELECT sigsel[] = {0};
	sig = receive(sigsel);
	len = 0;
#endif
#ifndef __OSE__
	  if (FD_ISSET(0,&readfds)) {
	    len = read(0, buf, sizeof(buf));
#else /* __OSE__ */
	  if (sig->signo == FM_READ_PTR_REPLY &&
	      sig->fm_read_ptr.handle == stdin_fh) {
	    len = sig->fm_read_ptr.status == EFS_SUCCESS ? sig->fm_read_ptr.actual : -1;
	    buf = sig->fm_read_ptr.buffer;
#endif
	    if (len <= 0) {
		close(rfd);
		close(wfd);
		if (len < 0) {
		    fprintf(stderr, "Error in reading from stdin.\n");
		} else {
		    fprintf(stderr, "[EOF]\n\r");
		}
		break;
	    }
	    /* check if there is an eof character in input */
	    for (i = 0; i < len-1 && buf[i] != tty_eof; i++);
	    if (buf[i] == tty_eof) {
		fprintf(stderr, "[Quit]\n\r");
		break;
	    }
	}

	if (len) {
#ifdef DEBUG
	    if(write(1, buf, len));
#endif
	    if (write_all(wfd, buf, len) != len) {
		fprintf(stderr, "Error in writing to FIFO.\n");
		close(rfd);
		close(wfd);
		break;
	    }
	    STATUS("\" OK\r\n");
#ifdef __OSE__
	    aio_dispatch(sig);
	    READ_AIO(stdin_read_req, 0, BUFSIZ, stdin_buf);
#endif
	}

	/*
	 * Read from FIFO, write to terminal.
	 */
#ifndef __OSE__
	if (FD_ISSET(rfd, &readfds)) {
	    STATUS("FIFO read: ");
	    len = read(rfd, buf, BUFSIZ);
#else /* __OSE__ */
        if (sig->signo == FM_READ_PTR_REPLY &&
	    sig->fm_read_ptr.handle == pipe_fh) {
	    len = sig->fm_read_ptr.status == EFS_SUCCESS ? sig->fm_read_ptr.actual : -1;
	    buf = sig->fm_read_ptr.buffer;
#endif
	    if (len < 0 && errno == EAGAIN) {
		/*
		 * No data this time, but the writing end of the FIFO is still open.
		 * Do nothing.
		 */
		;
	    } else if (len <= 0) {
		/*
		 * Either an error or end of file. In either case, break out
		 * of the loop.
		 */
		close(rfd);
		close(wfd);
		if (len < 0) {
		    fprintf(stderr, "Error in reading from FIFO.\n");
		} else
		    fprintf(stderr, "[End]\n\r");
		break;
	    } else {
		if (!got_some) {
		    if ((len=version_handshake(buf,len,wfd)) < 0) {
			close(rfd);
			close(wfd);
			break;
		    }
#ifndef __OSE__
		    if (protocol_ver >= 1) {
			/* Tell run_erl size of terminal window */
			signal(SIGWINCH, handle_sigwinch);
			raise(SIGWINCH);
		    }
#endif
		    got_some = 1;
		}

		/*
		 * We successfully read at least one character. Write what we got.
		 */
		STATUS("Terminal write: \"");
		if (write_all(1, buf, len) != len) {
		    fprintf(stderr, "Error in writing to terminal.\n");
		    close(rfd);
		    close(wfd);
		    break;
		}
		STATUS("\" OK\r\n");
#ifdef __OSE__
		aio_dispatch(sig);
		READ_AIO(pipe_read_req, rfd, BUFSIZ, pipe_buf);
#endif
	    }
	}
    }

#ifndef __OSE__
    /*
     * Reset terminal characterstics
     * XXX
     */
    tcsetattr(0, TCSADRAIN, &tty_rmode);
#endif
    return 0;
}

/* Call write() until entire buffer has been written or error.
 * Return len or -1.
 */
static int write_all(int fd, const char* buf, int len)
{
    int left = len;
    int written;
    while (left) {
	written = write(fd,buf,left);
	if (written < 0) {
	    return -1;
	}
	left -= written;
	buf += written;
    }
    return len;
}

#ifndef __OSE__
static int window_size_seq(char* buf, size_t bufsz)
{
#ifdef TIOCGWINSZ
    struct winsize ws;
    static const char prefix[] = "\033_";
    static const char suffix[] = "\033\\";
    /* This Esc sequence is called "Application Program Command"
       and seems suitable to use for our own customized stuff. */

    if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) == 0) {
	int len = sn_printf(buf, bufsz, "%swinsize=%u,%u%s",
			    prefix, ws.ws_col, ws.ws_row, suffix);
	return len;
    }
#endif /* TIOCGWINSZ */
    return 0;
}
#endif /* !__OSE__ */

/*   to_erl                     run_erl
 *     |                           |
 *     |---------- '\014' -------->| (session start)
 *     |                           |
 *     |<---- "[run_erl v1-0]" ----| (version interval)
 *     |                           |
 *     |--- Esc_"version=1"Esc\ -->| (common version)
 *     |                           |
 */
static int version_handshake(char* buf, int len, int wfd)
{
    unsigned re_high=0, re_low;
    char *end = find_str(buf,len,"]\n");

    if (end && sscanf(buf,"[run_erl v%u-%u",&re_high,&re_low)==2) {
	char wbuf[30];
	int wlen;

	if (re_low > RUN_ERL_HI_VER || re_high < RUN_ERL_LO_VER) {
	    fprintf(stderr,"Incompatible versions: to_erl=v%u-%u run_erl=v%u-%u\n",
		    RUN_ERL_HI_VER, RUN_ERL_LO_VER, re_high, re_low);
	    return -1;
	}
	/* Choose highest common version */
	protocol_ver = re_high < RUN_ERL_HI_VER ? re_high : RUN_ERL_HI_VER;

	wlen = sn_printf(wbuf, sizeof(wbuf), "\033_version=%u\033\\",
			 protocol_ver);
	if (write_all(wfd, wbuf, wlen) < 0) {
	    fprintf(stderr,"Failed to send version handshake\n");
	    return -1;
	}
	end += 2;
	len -= (end-buf);
	memmove(buf,end,len);

    }
    else {  /* we assume old run_erl without version handshake */
	protocol_ver = 0;
    }

    if (re_high != RUN_ERL_HI_VER) {
	fprintf(stderr,"run_erl has different version, "
		"using common protocol level %u\n", protocol_ver);
    }

    return len;
}