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   ASSERT(P);
00090   ASSERT(C);
00091   
00092   /*
00093    * Block SIGCHLD
00094    */
00095   sigemptyset(&mask);
00096   sigaddset(&mask, SIGCHLD);
00097   pthread_sigmask(SIG_BLOCK, &mask, &save);
00098   
00099   if((pid= fork()) < 0) {
00100     
00101     log("Cannot fork of a new process\n");  
00102     exit(1);
00103     
00104   }  else if(pid == 0) {
00105     
00106     if((pid= fork()) < 0) {
00107       
00108       log("Cannot fork of a new process\n");  
00109       exit(1);
00110       
00111     }
00112     
00113     else if(pid > 0) {
00114       
00115       _exit(0);
00116       
00117     } else  {
00118 
00119       Command_T c= copy_command(C);
00120       Mail_T alert_list= create_exec_alert_list(P, C);
00121       
00122       /*
00123        * Reset all signals, so the child process is
00124        * *not* created with any inherited SIG_BLOCK
00125        */
00126       sigemptyset(&mask);
00127       pthread_sigmask(SIG_SETMASK, &mask, NULL);
00128       
00129       /* Unregister Signal handlers */
00130       signal(SIGTERM, SIG_DFL);
00131       signal(SIGUSR1, SIG_DFL);
00132       signal(SIGPIPE, SIG_DFL);
00133 
00134       /* Garbage collect */
00135       do_free();
00136 
00137       /*
00138        * Reset to the original umask so programs will inherit the
00139        * same file creation mask monit was started with
00140        */
00141       umask(Run.umask);
00142 
00143       /*
00144        * Redirect the standard file descriptors
00145        */
00146       redirect_stdfd();
00147       
00148       /*
00149        * The exec statement done by the second child
00150        */
00151       (void) execv(c->arg[0], c->arg);
00152       sendmail(alert_list);
00153       log("Could not execute %s\n", c->arg[0]);
00154       gc_mail_list(&alert_list);
00155       _exit(1);
00156       
00157     }
00158   }
00159 
00160   /* Wait for first child - aka second parent, to exit */
00161   if(waitpid(pid, NULL, 0) != pid) {
00162     
00163       log("Waitpid error\n");
00164 
00165   }
00166 
00167   /*
00168    * Restore the signal mask
00169    */
00170   pthread_sigmask(SIG_SETMASK, &save, NULL);
00171   
00172   /*
00173    * We do not need to wait for the second child since we forked twice,
00174    * the init system-process will wait for it. So we just return
00175    */
00176   return ;
00177   
00178 } 
00179 
00180 
00181 /* ----------------------------------------------------------------- Private */
00182 
00183 
00184 /*
00185  * Free memory for the child process
00186  */
00187 static void do_free() {
00188   
00189   gc();
00190   destroy_hosts_allow();
00191   free(Run.controlfile);
00192   free(Run.pidfile);
00193   free(Run.logfile);
00194   free(Run.localhostname);
00195   free(Run.Env.user);
00196   free(Run.Env.home);
00197   free(Run.Env.cwd);
00198   free(Run.Auth.uname);
00199   free(Run.Auth.passwd);
00200   free(Run.MailFormat.from);
00201   free(Run.MailFormat.subject);
00202   free(Run.MailFormat.message);
00203   free(Run.bind_addr);
00204   /* Run.mailserver is not freed since it's used in exec alert */
00205 
00206 }
00207 
00208 
00209 /*
00210  * Return a deep copy of the given command object
00211  */
00212 static Command_T copy_command(Command_T C) {
00213 
00214   int i;
00215   Command_T P= NEW(P);
00216 
00217   for(i= 0; C->arg[i]; i++)
00218       P->arg[i]= xstrdup(C->arg[i]);
00219   P->arg[i]= NULL;
00220 
00221   return P;
00222   
00223 }
00224 
00225 
00226 /*
00227  * Create a list of mail addresses to send mail to in case the exec
00228  * fails. Only mail objects that has registred interest for restart
00229  * notification is used.
00230  */
00231 static Mail_T create_exec_alert_list(Process_T p, Command_T c) {
00232 
00233   Mail_T l= NULL;
00234   Mail_T h= p->maillist;
00235 
00236   for(; h; h= h->next)
00237       if(h->alert_on_restart) {
00238     
00239     Mail_T n= NEW(n);
00240     char *message= xmalloc(STRLEN);
00241     
00242     n->to= xstrdup(h->to);
00243     n->from= xstrdup("monit@localhost");
00244     n->subject= xstrdup("monit alert -- exec error");
00245     snprintf(message, STRLEN,
00246      "NOTE, THIS EMAIL TAKES PRECEDENCE OVER SUBSEQUENT RESTART ALERTS\n\n"
00247          "Could not execute program '%s' for process %s\n\n"
00248          "Your faithful employee,\nmonit",
00249            c->arg[0]?c->arg[0]:"null", p->name);
00250     n->message= message;
00251     n->next= l;
00252     l= n;
00253     
00254       }
00255 
00256   return l;
00257   
00258 }