cpl_nonsig.c

Go to the documentation of this file.
00001 /*
00002  * $Id: cpl_nonsig.c 4518 2008-07-28 15:39:28Z henningw $
00003  *
00004  * Copyright (C) 2001-2003 FhG Fokus
00005  *
00006  * This file is part of Kamailio, a free SIP server.
00007  *
00008  * Kamailio is free software; you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation; either version 2 of the License, or
00011  * (at your option) any later version
00012  *
00013  * Kamailio is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  * GNU General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU General Public License 
00019  * along with this program; if not, write to the Free Software 
00020  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00021  *
00022  * History:
00023  * -------
00024  * 2003-06-27: file created (bogdan)
00025  */
00026 
00027 #include <unistd.h>
00028 #include <errno.h>
00029 #include <string.h>
00030 #include <sys/types.h>
00031 #include <sys/stat.h>
00032 #include <fcntl.h>
00033 #include <time.h>
00034 #include <sys/uio.h>
00035 #include <signal.h>
00036 
00037 #include "../../mem/shm_mem.h"
00038 #include "../../mem/mem.h"
00039 #include "../../dprint.h"
00040 #include "cpl_nonsig.h"
00041 #include "CPL_tree.h"
00042 
00043 
00044 #define MAX_LOG_FILE_NAME      32
00045 
00046 #define FILE_NAME_SUFIX        ".log"
00047 #define FILE_NAME_SUFIX_LEN    (sizeof(FILE_NAME_SUFIX)-1)
00048 
00049 #define LOG_SEPARATOR          ": "
00050 #define LOG_SEPARATOR_LEN      (sizeof(LOG_SEPARATOR)-1)
00051 
00052 #define DEFAULT_LOG_NAME       "default_log"
00053 #define DEFAULT_LOG_NAME_LEN   (sizeof(DEFAULT_LOG_NAME)-1)
00054 
00055 #define LOG_TERMINATOR          "\n"
00056 #define LOG_TERMINATOR_LEN      (sizeof(LOG_TERMINATOR)-1)
00057 
00058 
00059 static char file[MAX_LOG_DIR_SIZE+1+MAX_LOG_FILE_NAME+FILE_NAME_SUFIX_LEN+1];
00060 static char *file_ptr;
00061 
00062 
00063 static inline void write_log( struct cpl_cmd *cmd)
00064 {
00065    struct iovec  wr_vec[5];
00066    time_t now;
00067    char *time_ptr;
00068    int fd;
00069    int ret;
00070 
00071    /* build file name (cmd->s1 is the user name)*/
00072    if (cmd->s1.len>MAX_LOG_FILE_NAME)
00073       cmd->s1.len = MAX_LOG_FILE_NAME;
00074    memcpy(file_ptr, cmd->s1.s, cmd->s1.len );
00075    memcpy(file_ptr+cmd->s1.len,FILE_NAME_SUFIX,FILE_NAME_SUFIX_LEN);
00076    file_ptr[cmd->s1.len+FILE_NAME_SUFIX_LEN] = 0;
00077 
00078    /* get current date+time -> wr_vec[0] */
00079    time( &now );
00080    time_ptr = ctime( &now );
00081    wr_vec[0].iov_base = time_ptr;
00082    wr_vec[0].iov_len = strlen( time_ptr );
00083    /* ctime_r adds a \n at the end -> overwrite it with space */
00084    time_ptr[ wr_vec[0].iov_len-1 ] = ' ';
00085 
00086    /* log name (cmd->s2) ->  wr_vec[1] */
00087    if (cmd->s2.s==0 || cmd->s2.len==0) {
00088       wr_vec[1].iov_base = DEFAULT_LOG_NAME;
00089       wr_vec[1].iov_len = DEFAULT_LOG_NAME_LEN;
00090    } else {
00091       wr_vec[1].iov_base = cmd->s2.s;
00092       wr_vec[1].iov_len = cmd->s2.len;
00093    }
00094 
00095    /* log separator ->  wr_vec[2] */
00096    wr_vec[2].iov_base = LOG_SEPARATOR;
00097    wr_vec[2].iov_len = LOG_SEPARATOR_LEN;
00098 
00099    /* log comment (cmd->s3) ->  wr_vec[3] */
00100    wr_vec[3].iov_base = cmd->s3.s;
00101    wr_vec[3].iov_len = cmd->s3.len;
00102 
00103    /* log terminator ->  wr_vec[2] */
00104    wr_vec[4].iov_base = LOG_TERMINATOR;
00105    wr_vec[4].iov_len = LOG_TERMINATOR_LEN;
00106 
00107    /* [create+]open the file */
00108    fd = open( file, O_CREAT|O_APPEND|O_WRONLY, 0664);
00109    if (fd==-1) {
00110       LM_ERR("cannot open file [%s] : %s\n",
00111          file, strerror(errno) );
00112       return;
00113    }
00114    /* get the log */
00115    LM_DBG("logging into [%s]... \n",file);
00116    /* I'm really not interested in the return code for write ;-) */
00117    while ( (ret=writev( fd, wr_vec, 5))==-1 ) {
00118       if (errno==EINTR)
00119          continue;
00120       LM_ERR("writing to log file [%s] : %s\n",
00121          file, strerror(errno) );
00122    }
00123    close (fd);
00124 
00125    shm_free( cmd->s1.s );
00126 }
00127 
00128 
00129 
00130 static inline void send_mail( struct cpl_cmd *cmd)
00131 {
00132    char *argv[5];
00133    int pfd[2];
00134    pid_t  pid;
00135    int i;
00136 
00137    if (pipe(pfd) < 0) {
00138       LM_ERR("pipe failed: %s\n",strerror(errno));
00139       return;
00140    }
00141 
00142    /* even if I haven't fork yet, I push the date on the pipe just to get
00143     * rid of one more malloc + copy */
00144    if (cmd->s3.len && cmd->s3.s) {
00145       if ( (i=write( pfd[1], cmd->s3.s, cmd->s3.len ))!=cmd->s3.len ) {
00146          LM_ERR("write returned error %s\n",
00147             strerror(errno));
00148          goto error;
00149       }
00150    }
00151 
00152    if ( (pid = fork()) < 0) {
00153       LM_ERR("fork failed: %s\n",strerror(errno));
00154       goto error;
00155    } else if (pid==0) {
00156       /* child -> close all descriptors excepting pfd[0] */
00157       /* 32 is the maximum number of inherited open file descriptors */
00158       for (i=3; i < 32; i++)
00159          if (i!=pfd[0])
00160             close(i);
00161       if (pfd[0] != STDIN_FILENO) {
00162          dup2(pfd[0], STDIN_FILENO);
00163          close(pfd[0]);
00164       }
00165 
00166       /* set the argument vector*/
00167       argv[0] = "mail";
00168       argv[1] = "-s";
00169       if (cmd->s2.s && cmd->s2.len) {
00170          /* put the subject in this format : <"$subject"\0> */
00171          if ( (argv[2]=(char*)pkg_malloc(1+cmd->s2.len+1+1))==0) {
00172             LM_ERR("cannot get pkg memory\n");
00173             goto child_exit;
00174          }
00175          argv[2][0] = '\"';
00176          memcpy(argv[2]+1,cmd->s2.s,cmd->s2.len);
00177          argv[2][cmd->s2.len+1] = '\"';
00178          argv[2][cmd->s2.len+2] = 0;
00179       } else {
00180          argv[2] = "\"[CPL notification]\"";
00181       }
00182       /* put the TO in <$to\0> format*/
00183       if ( (argv[3]=(char*)pkg_malloc(cmd->s1.len+1))==0) {
00184          LM_ERR("cannot get pkg memory\n");
00185          goto child_exit;
00186       }
00187       memcpy(argv[3],cmd->s1.s,cmd->s1.len);
00188       argv[3][cmd->s1.len] = 0;
00189       /* last element in vector mist be a null pointer */
00190       argv[4] = (char*)0;
00191       /* just debug */
00192       for(i=0;i<sizeof(argv)/sizeof(char*);i++)
00193          LM_DBG("argv[%d] = %s\n",i,argv[i]);
00194       /* once I copy localy all the data from shm mem -> free the shm */
00195       shm_free( cmd->s1.s );
00196 
00197       /* set an alarm -> sending the email shouldn't take more than 10 sec */
00198       alarm(10);
00199       /* run the external mailer */
00200       LM_DBG("new forked process created -> "
00201          "doing execv..\n");
00202       execv("/usr/bin/mail",argv);
00203       /* if we got here means execv exit with error :-( */
00204       LM_ERR("execv failed! (%s)\n",strerror(errno));
00205 child_exit:
00206       _exit(127);
00207    }
00208 
00209    /* parent -> close both ends of pipe */
00210    close(pfd[0]);
00211    close(pfd[1]);
00212    return;
00213 error:
00214    shm_free( cmd->s1.s );
00215    close(pfd[0]);
00216    close(pfd[1]);
00217    return;
00218 }
00219 
00220 
00221 
00222 
00223 void cpl_aux_process( int cmd_out, char *log_dir)
00224 {
00225    struct cpl_cmd cmd;
00226    int len;
00227 
00228    /* this process will ignore SIGCHLD signal */
00229    if (signal( SIGCHLD, SIG_IGN)==SIG_ERR) {
00230       LM_ERR("cannot set to IGNORE SIGCHLD signal\n");
00231    }
00232 
00233    /* set the path for logging */
00234    if (log_dir) {
00235       strcpy( file, log_dir);
00236       file_ptr = file + strlen(log_dir);
00237       *(file_ptr++) = '/';
00238    }
00239 
00240    while(1) {
00241       /* let's read a command from pipe */
00242       len = read( cmd_out, &cmd, sizeof(struct cpl_cmd));
00243       if (len!=sizeof(struct cpl_cmd)) {
00244          if (len>=0) {
00245             LM_ERR("truncated message"
00246                " read from pipe! -> discarded\n");
00247          } else if (errno!=EAGAIN) {
00248             LM_ERR("pipe reading failed: "
00249                " : %s\n",strerror(errno));
00250          }
00251          sleep(1);
00252          continue;
00253       }
00254 
00255       /* process the command*/
00256       switch (cmd.code) {
00257          case CPL_LOG_CMD:
00258             write_log( &cmd );
00259             break;
00260          case CPL_MAIL_CMD:
00261             send_mail( &cmd );
00262             break;
00263          default:
00264             LM_ERR("unknown command (%d) "
00265                "received! -> ignoring\n",cmd.code);
00266       } /* end switch*/
00267 
00268    }
00269 }
00270 

Generated on Mon May 21 18:00:25 2012 for Kamailio - The Open Source SIP Server by  doxygen 1.5.6