run_erl.c

来自「OTP是开放电信平台的简称」· C语言 代码 · 共 1,281 行 · 第 1/3 页

C
1,281
字号
    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;        /* 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 = open(fifo2, O_RDONLY|DONT_BLOCK_PLEASE, 0)) < 0) {	ERROR((LOG_ERR,"Could not open FIFO %s for reading.\n", 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 */		ERROR((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)) {		    strlcpy(log_alive_buffer,			    "(could not format time in 256 positions "			    "with current format string.)", sizeof(log_alive_buffer));		}		log_alive_buffer[ALIVE_BUFFSIZ] = '\0';		sprintf(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 = 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();		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 = read(mfd, buf, BUFSIZ)) <= 0) {		close(rfd);		if(wfd) close(wfd);		close(mfd);		unlink(fifo1);		unlink(fifo2);		if (len < 0) {		    if(errno == EIO)			ERROR((LOG_ERR,"Erlang closed the connection.\n"));		    else			ERROR((LOG_ERR,"Error in reading from terminal: errno=%d\n",errno));		    exit(1);		}		exit(0);	    }	    write_to_log(&lfd, &lognum, buf, len);	    /*	     * Save in the output queue.	     */	    if (fifowrite && wfd) {		outbuf_append(buf, len);	    }	}	    	/*	 * Read from FIFO, write to master pty	 */	if (FD_ISSET(rfd, &readfds)) {#ifdef DEBUG	    status("FIFO read; ");#endif	    fifowrite = 1;	    if ((len = read(rfd, buf, BUFSIZ)) < 0) {		close(rfd);		if(wfd) close(wfd);		close(mfd);		unlink(fifo1);		unlink(fifo2);		ERROR((LOG_ERR,"Error in reading from FIFO.\n"));		exit(1);	    }	    /* 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(!len) {		close(rfd);		rfd = open(fifo2, O_RDONLY|DONT_BLOCK_PLEASE, 0);		if (rfd < 0) {		    ERROR((LOG_ERR,"Could not open FIFO %s for reading.\n", fifo2));		    exit(1);		}	    } else {		if(!wfd) {		    if ((wfd = open(fifo1, O_WRONLY|DONT_BLOCK_PLEASE, 0)) < 0) {			status("Client expected on FIFO %s, but can't open (len=%d)\n",			       fifo1, len);			close(rfd);			rfd = open(fifo2, O_RDONLY|DONT_BLOCK_PLEASE, 0);			if (rfd < 0) {			    ERROR((LOG_ERR,"Could not open FIFO %s for reading.\n", fifo2));			    exit(1);			}			wfd = 0;		    } else {#ifdef DEBUG			status("run_erl: %s opened for writing\n", fifo1);#endif		    }		}			/* Write the message */#ifdef DEBUG		status("Pty master write; ");#endif		if(len==1 && buf[0] == '\003') {		    kill(childpid,SIGINT);		} else if(write(mfd, buf, len) != len) {		    ERROR((LOG_ERR,"Error in writing to terminal.\n"));		    close(rfd);		    if(wfd) close(wfd);		    close(mfd);		    exit(1);		}	    }#ifdef DEBUG	    status("OK\n");#endif	}    }} /* pass_on() *//* * catch_sigpipe() * Called if there is an exception on a pipe. * This is normally because the to_erl program is no longer connected * to the pipe. We just set a flag that indicates that no writing to * the pipe is to be done. */static void catch_sigpipe(int sig){  switch(sig) {  case SIGPIPE:    fifowrite = 0;  default:    ;  }}static void catch_sigchild(int sig){}/* * next_log: * Returns the index number that follows the given index number. * (Wrapping after log_generations) */static int next_log(int log_num) {  return log_num>=log_generations?1:log_num+1;}/* * prev_log: * Returns the index number that precedes the given index number. * (Wrapping after log_generations) */static int prev_log(int log_num) {  return log_num<=1?log_generations:log_num-1;}/* * find_next_log_num() * Searches through the log directory to check which logs that already * exist. It finds the "hole" in the sequence, and returns the index * number for the last log in the log sequence. If there is no hole, index * 1 is returned. */static int find_next_log_num(void) {  int i, next_gen, log_gen;  DIR *dirp;  struct dirent *direntp;  int log_exists[LOG_MAX_GENERATIONS+1];  int stub_len = strlen(LOG_STUBNAME);  /* Initialize exiting log table */  for(i=log_generations; i>=0; i--)    log_exists[i] = 0;  dirp = opendir(log_dir);  if(!dirp) {    ERROR((LOG_ERR,"Can't access log directory %s.\n", log_dir));    exit(1);  }  /* Check the directory for existing logs */  while((direntp=readdir(dirp)) != NULL) {    if(strncmp(direntp->d_name,LOG_STUBNAME,stub_len)==0) {      int num = atoi(direntp->d_name+stub_len);      if(num < 1 || num > log_generations)	continue;      log_exists[num] = 1;    }  }	  closedir(dirp);  /* Find out the next available log file number */  next_gen = 0;  for(i=log_generations; i>=0; i--) {    if(log_exists[i])      if(next_gen)	break;      else 	;    else      next_gen = i;  }  /* Find out the current log file number */  if(next_gen)    log_gen = prev_log(next_gen);  else    log_gen = 1;  return log_gen;} /* find_next_log_num() *//* open_log() * Opens a log file (with given index) for writing. Writing may be * at the end or a trucnating write, according to flags. * A LOGGING STARTED and time stamp message is inserted into the log file */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];  int lfd;  /* Remove the next log (to keep a "hole" in the log sequence) */  sprintf(buf, "%s/%s%d", log_dir, LOG_STUBNAME, next_log(log_num));  unlink(buf);  /* Create or continue on the current log file */  sprintf(buf, "%s/%s%d", log_dir, LOG_STUBNAME, log_num);  if((lfd = open(buf, flags, LOG_PERM))<0){    ERROR((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)) {      strlcpy(log_buffer,	      "(could not format time in 256 positions "	      "with current format string.)", sizeof(log_buffer));  }  log_buffer[ALIVE_BUFFSIZ] = '\0';  sprintf(buf, "\n=====\n===== LOGGING STARTED %s\n=====\n", log_buffer);  if(write(lfd, buf, strlen(buf)) != strlen(buf))    status("Error in writing to log.\n");#if USE_FSYNC  fsync(lfd);#endif  return lfd;}/* write_to_log() * Writes a message to a log file. If the current log file is full, * a new log file is opened. */static void write_to_log(int* lfd, int* log_num, char* buf, int len) {  int size;  /* Decide if new logfile needed, and open if so */    size = lseek(*lfd,0,SEEK_END);  if(size+len > log_maxsize) {    close(*lfd);    *log_num = next_log(*log_num);    *lfd = open_log(*log_num, O_RDWR|O_CREAT|O_TRUNC|O_SYNC);   }  /* Write to log file */  if(write(*lfd, buf, len) != len) {    status("Error in writing to log.\n");  }#if USE_FSYNC  fsync(*lfd);#endif}/* create_fifo() * Creates a new fifo with the given name and permission. */static int create_fifo(char *name, int perm){  if ((mkfifo(name, perm) < 0) && (errno != EEXIST))    return -1;  return 0;}/* open_pty_master() * Find a master device, open and return fd and slave device name. */static int open_pty_master(char **ptyslave){  int mfd;#ifdef HAVE_OPENPTY# ifdef PATH_MAX#  define SLAVE_SIZE PATH_MAX

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?