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 + -
显示快捷键?