spawn.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C), 2000-2002 by Contributors to the monit codebase. 
00003  * All Rights Reserved.
00004  *
00005  * This program is free software; you can redistribute it and/or
00006  * modify it under the terms of the GNU General Public License as
00007  * published by the Free Software Foundation; either version 2 of the
00008  * License, or (at your option) any later version.
00009  *
00010  * This program is distributed in the hope that it will be useful, but
00011  * WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013  * General Public License for more details.
00014  * 
00015  * You should have received a copy of the GNU General Public License
00016  * along with this program; if not, write to the Free Software Foundation,
00017  * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
00018  */
00019 
00020 #include <config.h>
00021 
00022 #include <stdio.h>
00023 #include <signal.h>
00024 #include <errno.h>
00025 #include <stdlib.h>
00026 
00027 #ifdef HAVE_STRING_H
00028 #include <string.h>
00029 #endif
00030 
00031 #ifdef HAVE_STRINGS_H
00032 #include <strings.h>
00033 #endif
00034 
00035 #ifdef HAVE_UNISTD_H
00036 #include <unistd.h>
00037 #endif
00038 
00039 #ifdef HAVE_SYS_WAIT_H
00040 #include <sys/wait.h>
00041 #endif
00042 
00043 #ifdef HAVE_SYS_TYPES_H
00044 #include <sys/types.h>
00045 #endif
00046 
00047 #ifdef HAVE_SYS_STAT_H
00048 #include <sys/stat.h>
00049 #endif
00050 
00051 #include "alert.h"
00052 #include "monitor.h"
00053 #include "engine.h"
00054 
00055 /* Private prototypes */
00056 static void do_free();
00057 static Command_T copy_command(Command_T);
00058 static Mail_T create_exec_alert_list(Process_T, Command_T);
00059 
00060 
00074 /* ------------------------------------------------------------------ Public */
00075 
00076 
00084 void  spawn(Process_T P, Command_T C) {
00085   
00086   pid_t pid;
00087   sigset_t mask, save;
00088 
00089   /*
00090    * Block SIGCHLD
00091    */
00092   sigemptyset(&mask);
00093   sigaddset(&mask, SIGCHLD);
00094   pthread_sigmask(SIG_BLOCK, &mask, &save);
00095   
00096   if ((pid= fork ()) < 0) {
00097     
00098     log("Cannot fork of a new process\n");  
00099     exit (1);
00100     
00101   }  else if ( pid == 0 ) {
00102     
00103     if ( (pid= fork()) < 0 ) {
00104       
00105       log("Cannot fork of a new process\n");  
00106       exit (1);
00107       
00108     }
00109     
00110     else if ( pid > 0 ) {
00111       
00112       _exit(0);
00113       
00114     } else  {
00115 
00116       Command_T c= copy_command(C);
00117       Mail_T alert_list= create_exec_alert_list(P, C);
00118       
00119       /*
00120        * Reset all signals, so the child process is
00121        * *not* created with any inherited SIG_BLOCK
00122        */
00123       sigemptyset(&mask);
00124       pthread_sigmask(SIG_SETMASK, &mask, NULL);
00125       
00126       /* Unregister Signal handlers */
00127       signal(SIGTERM, SIG_DFL);
00128       signal(SIGUSR1, SIG_DFL);
00129       signal(SIGPIPE, SIG_DFL);
00130 
00131       /* Garbage collect */
00132       do_free();
00133 
00134       /*
00135        * Reset to the original umask so programs will inherit the
00136        * same file creation mask monit was started with
00137        */
00138       umask(Run.umask);
00139 
00140       /*
00141        * The exec statement done by the second child
00142        */
00143       (void) execv(c->arg[0], c->arg);
00144       sendmail(alert_list);
00145       log("Could not execute %s\n", c->arg[0]);
00146       gc_mail_list(&alert_list);
00147       _exit (1);
00148       
00149     }
00150   }
00151 
00152   /* Wait for first child - aka second parent, to exit */
00153   if ( waitpid(pid, NULL, 0) != pid ) {
00154     
00155       log("Waitpid error\n");
00156 
00157   }
00158 
00159   /*
00160    * Restore the signal mask
00161    */
00162   pthread_sigmask(SIG_SETMASK, &save, NULL);
00163   
00164   /*
00165    * We do not need to wait for the second child since we forked twice,
00166    * the init system-process will wait for it. So we just return
00167    */
00168   return ;
00169   
00170 } 
00171 
00172 
00173 /* ----------------------------------------------------------------- Private */
00174 
00175 
00176 /*
00177  * Free memory for the child process
00178  */
00179 static void do_free() {
00180   
00181   gc();
00182   destroy_hosts_allow();
00183   free(Run.controlfile);
00184   free(Run.pidfile);
00185   free(Run.logfile);
00186   free(Run.localhostname);
00187   free(Run.Env.user);
00188   free(Run.Env.home);
00189   free(Run.Env.cwd);
00190   free(Run.Auth.uname);
00191   free(Run.Auth.passwd);
00192   free(Run.MailFormat.from);
00193   free(Run.MailFormat.subject);
00194   free(Run.MailFormat.message);
00195   free(Run.bind_addr);
00196   /* Run.mailserver is not freed since it's used in exec alert */
00197 
00198 }
00199 
00200 
00201 /*
00202  * Return a deep copy of the given command object
00203  */
00204 static Command_T copy_command(Command_T C) {
00205 
00206   int i;
00207   Command_T P= NEW(P);
00208 
00209   for(i= 0; C->arg[i]; i++)
00210       P->arg[i]= xstrdup(C->arg[i]);
00211   P->arg[i]= NULL;
00212 
00213   return P;
00214   
00215 }
00216 
00217 
00218 /*
00219  * Create a list of mail addresses to send mail to in case the exec
00220  * fails. Only mail objects that has registred interest for restart
00221  * notification is used.
00222  */
00223 static Mail_T create_exec_alert_list(Process_T p, Command_T c) {
00224 
00225   Mail_T l= NULL;
00226   Mail_T h= p->maillist;
00227 
00228   for(; h; h= h->next)
00229       if(h->alert_on_restart) {
00230     
00231     Mail_T n= NEW(n);
00232     char *message= xmalloc(STRLEN);
00233     
00234     n->to= xstrdup(h->to);
00235     n->from= xstrdup("monit@localhost");
00236     n->subject= xstrdup("monit alert -- exec error");
00237     snprintf(message, STRLEN,
00238      "NOTE, THIS EMAIL TAKES PRECEDENCE OVER SUBSEQUENT RESTART ALERTS\n\n"
00239          "Could not execute program '%s' for process %s\n\n"
00240          "Your faithful employee,\nmonit",
00241            c->arg[0]?c->arg[0]:"null", p->name);
00242     n->message= message;
00243     n->next= l;
00244     l= n;
00245     
00246       }
00247 
00248   return l;
00249   
00250 }