run_erl.c

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

C
1,281
字号
/* ``The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in * compliance with the License. You should have received a copy of the * Erlang Public License along with this software. If not, it can be * retrieved via the world wide web at http://www.erlang.org/. *  * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See * the License for the specific language governing rights and limitations * under the License. *  * The Initial Developer of the Original Code is Ericsson Utvecklings AB. * Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings * AB. All Rights Reserved.'' *  *     $Id$ *//*  * Module: run_erl.c *  * This module implements a reader/writer process that opens two specified  * FIFOs, one for reading and one for writing; reads from the read FIFO * and writes to stdout and the write FIFO. * */#ifdef HAVE_CONFIG_H#  include "config.h"#endif#include <sys/types.h>#include <sys/wait.h>#include <sys/stat.h>#include <sys/time.h>#include <sys/types.h>#include <fcntl.h>#include <unistd.h>#include <stdio.h>#include <stdlib.h>#include <stdarg.h>#include <string.h>#include <errno.h>#include <signal.h>#include <dirent.h>#include <termios.h>#include <time.h>#if !defined(NO_SYSLOG)#include <syslog.h>#endif#ifdef HAVE_PTY_H#include <pty.h>#endif#ifdef HAVE_UTMP_H#include <utmp.h>#endif#ifdef HAVE_UTIL_H#include <util.h>#endif#ifndef HAVE_STRLCPYsize_t strlcpy(char *dst, const char *src, size_t siz);#endif#ifndef HAVE_STRLCATsize_t strlcat(char *dst, const char *src, size_t siz);#endif#if defined(O_NONBLOCK)# define DONT_BLOCK_PLEASE O_NONBLOCK#else# define DONT_BLOCK_PLEASE O_NDELAY# if !defined(EAGAIN)#  define EAGAIN -3898734# endif#endif#define noDEBUG#define DEFAULT_LOG_GENERATIONS 5#define LOG_MAX_GENERATIONS     1000      /* No more than 1000 log files */#define LOG_MIN_GENERATIONS     2         /* At least two to switch between */#define DEFAULT_LOG_MAXSIZE     100000#define LOG_MIN_MAXSIZE         1000      /* Smallast value for changing log file */#define LOG_STUBNAME            "erlang.log."#define LOG_PERM                0664#define DEFAULT_LOG_ACTIVITY_MINUTES    5#define DEFAULT_LOG_ALIVE_MINUTES       15#define DEFAULT_LOG_ALIVE_FORMAT        "%a %b %e %T %Z %Y"#define ALIVE_BUFFSIZ                   256#define PERM            0600#define STATUSFILENAME  "/run_erl.log"#define PIPE_STUBNAME   "erlang.pipe"#define PIPE_STUBLEN    strlen(PIPE_STUBNAME)#ifndef FILENAME_MAX#define FILENAME_MAX 250#endif#ifndef O_SYNC#define O_SYNC 0#define USE_FSYNC 1#endif#define MAX(x,y)  ((x) > (y) ? (x) : (y))#define FILENAME_BUFSIZ FILENAME_MAX/* prototypes */static void usage(char *);static int create_fifo(char *name, int perm);static int open_pty_master(char **name);static int open_pty_slave(char *name);static void pass_on(pid_t, int);static void exec_shell(char **);static void status(const char *format,...);static void stderr_error(int priority, const char *format,...);static void catch_sigpipe(int);static void catch_sigchild(int);static int next_log(int log_num);static int prev_log(int log_num);static int find_next_log_num(void);static int open_log(int log_num, int flags);static void write_to_log(int* lfd, int* log_num, char* buf, int len);static void daemon_init(void);static char *simple_basename(char *path);static void init_outbuf(void);static int outbuf_size(void);static void clear_outbuf(void);static char* outbuf_first(void);static void outbuf_delete(int bytes);static void outbuf_append(char* bytes, int n);#ifdef DEBUGstatic void show_terminal_settings(struct termios *t);#endif/* static data */static char fifo1[FILENAME_BUFSIZ], fifo2[FILENAME_BUFSIZ];static char statusfile[FILENAME_BUFSIZ];static char log_dir[FILENAME_BUFSIZ];static char pipename[FILENAME_BUFSIZ];static FILE *stdstatus = NULL;static struct sigaction sig_act;static int fifowrite = 0;static int log_generations = DEFAULT_LOG_GENERATIONS;static int log_maxsize     = DEFAULT_LOG_MAXSIZE;static int log_alive_minutes = DEFAULT_LOG_ALIVE_MINUTES;static int log_activity_minutes = DEFAULT_LOG_ACTIVITY_MINUTES;static int log_alive_in_gmt = 0;static char log_alive_format[ALIVE_BUFFSIZ+1];static int run_daemon = 0;static char *program_name;/* * Output buffer. * * outbuf_base <= outbuf_out <= outbuf_in <= outbuf_base+outbuf_total */static char* outbuf_base;static int outbuf_total;static char* outbuf_out;static char* outbuf_in;#if defined(NO_SYSCONF) || !defined(_SC_OPEN_MAX) #    if defined(OPEN_MAX)#        define HIGHEST_FILENO() OPEN_MAX#    else#        define HIGHEST_FILENO() 64 /* arbitrary value */#    endif#else #    define HIGHEST_FILENO() sysconf(_SC_OPEN_MAX)#endif#ifdef NO_SYSLOG#define OPEN_SYSLOG() ((void) 0)#define ERROR(Parameters) stderr_error Parameters#else#define OPEN_SYSLOG()\openlog(simple_basename(program_name),LOG_PID|LOG_CONS|LOG_NOWAIT,LOG_USER)#define ERROR(Parameters)			\do {						\    if (run_daemon) {			        \	syslog Parameters;			\    } else {					\	stderr_error Parameters;		\    }						\} while (0)#endif#define  CHECK_BUFFER(Need) 						   \do {									   \    if ((Need) >= FILENAME_BUFSIZ) {					   \	ERROR((LOG_ERR,"%s: Filename length (%d) exceeds maximum length "  \	      "of %d characters, exiting.",				   \	      program_name, (int)(Need), FILENAME_BUFSIZ));		   \	exit(1);							   \    }									   \} while (0)int main(int argc, char **argv){  int childpid;  int mfd, sfd;  int fd;  char *p, *ptyslave;  int i = 1;  int off_argv;  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;  strlcpy(pipename, argv[i++], sizeof(pipename));  strlcpy(log_dir, argv[i], sizeof(log_dir));  strlcpy(statusfile, log_dir, sizeof(statusfile));  CHECK_BUFFER(strlen(statusfile)+strlen(STATUSFILENAME));  strlcat(statusfile, STATUSFILENAME, sizeof(statusfile));#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) {	  ERROR((LOG_ERR,"Minumum value for RUN_ERL_LOG_ALIVE_MINUTES is 1 "		 "(current value is %s)\n",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) {	  ERROR((LOG_ERR,"Minumum value for RUN_ERL_LOG_ACTIVITY_MINUTES is 1 "		 "(current value is %s)\n",p));      }  }   if ((p = getenv("RUN_ERL_LOG_ALIVE_FORMAT"))) {      if (strlen(p) > ALIVE_BUFFSIZ) {	  ERROR((LOG_ERR, "RUN_ERL_LOG_ALIVE_FORMAT can contain a maximum of "		 "%d characters\n", ALIVE_BUFFSIZ));      }      strlcpy(log_alive_format, p, sizeof(log_alive_format));  } else {      strlcpy(log_alive_format, DEFAULT_LOG_ALIVE_FORMAT, sizeof(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)      ERROR((LOG_ERR,"Minumum RUN_ERL_LOG_GENERATIONS is %d\n", LOG_MIN_GENERATIONS));    if (log_generations > LOG_MAX_GENERATIONS)      ERROR((LOG_ERR,"Maximum RUN_ERL_LOG_GENERATIONS is %d\n", LOG_MAX_GENERATIONS));  }  if ((p = getenv("RUN_ERL_LOG_MAXSIZE"))) {    log_maxsize = atoi(p);    if (log_maxsize < LOG_MIN_MAXSIZE)      ERROR((LOG_ERR,"Minimum RUN_ERL_LOG_MAXSIZE is %d\n", 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 */    int highest_pipe_num = 0;    DIR *dirp;    struct dirent *direntp;    dirp = opendir(pipename);    if(!dirp) {      ERROR((LOG_ERR,"Can't access pipe directory %s.\n", 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);    CHECK_BUFFER(strlen(pipename)+10+strlen(PIPE_STUBNAME));    sprintf(pipename+strlen(pipename),	    "%s.%d",PIPE_STUBNAME,highest_pipe_num+1);  } /* if */  /* write FIFO - is read FIFO for `to_erl' program */  strlcpy(fifo1, pipename, sizeof(fifo1));  CHECK_BUFFER(strlen(fifo1)+2);  strlcat(fifo1, ".r", sizeof(fifo1));  if (create_fifo(fifo1, PERM) < 0) {    ERROR((LOG_ERR,"Cannot create FIFO %s for writing.\n", fifo1));    exit(1);  }  /* read FIFO - is write FIFO for `to_erl' program */  strlcpy(fifo2, pipename, sizeof(fifo2));  strlcat(fifo2, ".w", sizeof(fifo2));  /* Check that nobody is running run_erl already */  if ((fd = open (fifo2, O_WRONLY|DONT_BLOCK_PLEASE, 0)) >= 0) {    /* Open as client succeeded -- run_erl is already running! */    fprintf(stderr, "Erlang already running on pipe %s.\n", pipename);    close(fd);    exit(1);  }  if (create_fifo(fifo2, PERM) < 0) {     ERROR((LOG_ERR,"Cannot create FIFO %s for reading.\n", fifo2));    exit(1);  }  /*   * Open master pseudo-terminal   */  if ((mfd = open_pty_master(&ptyslave)) < 0) {    ERROR((LOG_ERR,"Could not open pty master\n"));    exit(1);  }  /*    * Now create a child process   */  if ((childpid = fork()) < 0) {    ERROR((LOG_ERR,"Cannot fork\n"));    exit(1);  }  if (childpid == 0) {    /* Child */    close(mfd);    /* disassociate from control terminal */#ifdef USE_SETPGRP_NOARGS       /* SysV */    setpgrp();#else#ifdef USE_SETPGRP              /* BSD */    setpgrp(0,getpid());#else                           /* POSIX */    setsid();#endif#endif    /* Open the slave pty */    if ((sfd = open_pty_slave(ptyslave)) < 0) {      ERROR((LOG_ERR,"Could not open pty slave %s\n", 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);    }#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 */    close(0);    close(1);    close(2);    if (dup(sfd) != 0 || dup(sfd) != 1 || dup(sfd) != 2) {      status("Cannot dup\n");    }    close(sfd);    exec_shell(argv+off_argv); /* exec_shell expects argv[2] to be */                        /* the command name, so we have to */                        /* adjust. */  } else {    /* Parent */    /* Catch the SIGPIPE signal */    sigemptyset(&sig_act.sa_mask);    sig_act.sa_flags = 0;    sig_act.sa_handler = catch_sigpipe;    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, mfd);  }  return 0;} /* main() *//* 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 mfd){

⌨️ 快捷键说明

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