control.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 
00024 #ifdef HAVE_SYS_TYPES_H
00025 #include <sys/types.h>
00026 #endif
00027 
00028 #include <sys/socket.h>
00029 #include <stdlib.h>
00030 
00031 #ifdef HAVE_STRING_H
00032 #include <string.h>
00033 #endif
00034 
00035 #ifdef HAVE_UNISTD_H
00036 #include <unistd.h>
00037 #endif
00038 
00039 #include "monitor.h"
00040 #include "net.h"
00041 
00042 
00043 /* Private Prototypes */
00044 static void wait_stop(Process_T);
00045 static void wait_start(Process_T);
00046 static void do_stop(Process_T, int);
00047 static void do_start(Process_T, int);
00048 static void do_depend(Process_T, char *, int);
00049 
00050 
00062 /* ------------------------------------------------------------------ Public */
00063 
00064 
00070 void control(char *action, int toggle_validate_flag) {
00071 
00072   Process_T p;
00073 
00074   ASSERT(action);
00075 
00076   for(p= processlist; p; p= p->next) {
00077     if(p->visited)
00078     continue;
00079     if(exist_daemon()) {
00080       d_check_process(p->name, action);
00081     } else {
00082       check_process(p->name, action, toggle_validate_flag);
00083     }
00084   }
00085   
00086   reset_depend();
00087 
00088 }
00089 
00090 
00091 /*
00092  * Start/stop all processes in a group
00093  * @param G group name
00094  * @param action A string describing the action to execute
00095  * @param toggle_validate_flag passed on to the start/stop functions
00096  */
00097 void control_group(char *G, char *action, int toggle_validate_flag) {
00098 
00099   Process_T p;
00100 
00101   ASSERT(G);
00102   ASSERT(action);
00103 
00104   for(p= processlist; p; p= p->next) {
00105     if(p->visited)
00106     continue;
00107     if(is(p->group, G)) {
00108       if(exist_daemon()) {
00109     d_check_process(p->name, action);
00110       } else {
00111     check_process(p->name, action, toggle_validate_flag);
00112       }
00113     }
00114   }
00115 
00116   reset_depend();
00117  
00118 }
00119 
00120 
00126 void d_check_process(char *P, char *action) {
00127 
00128   int s;
00129   char req[2*STRLEN];
00130   char *auth= get_basic_authentication_header();
00131   ssl_connection *ssl= NULL;
00132 
00133   ASSERT(P);
00134   ASSERT(action);
00135 
00136   if(Run.httpdssl) {
00137     
00138     ssl= new_ssl_connection(Run.httpsslpem);
00139     
00140   }
00141 
00142   s= create_socket(Run.bind_addr?Run.bind_addr:"localhost",
00143                    Run.httpdport, SOCK_STREAM);
00144   
00145   if(s < 0) {
00146     
00147     error("%s: Cannot connect to the monit daemon. "
00148           "Did you start it with http support?\n", prog);
00149     goto error;
00150     
00151   } else {
00152     snprintf(req, sizeof(req),
00153              "GET /%s?action=%s HTTP/1.0\r\n%s\r\n", P, action, auth);
00154     
00155     if(ssl) {
00156       
00157       if(!embed_ssl_socket(ssl, s)) {
00158     
00159     fprintf(stdout, "Failed establish SSL communication to monit"
00160         " server\n");
00161     goto error;
00162       }
00163       
00164       send_ssl_socket(ssl, req, sizeof(req));
00165       
00166       close_ssl_socket(ssl);
00167       close_socket(s);
00168       
00169     } else {
00170       
00171       sock_send(s, req, sizeof(req), 0);
00172       close_socket(s);
00173       
00174     }
00175   }
00176   
00177   if(Run.httpdssl) {
00178     
00179     delete_ssl_socket(ssl);
00180 
00181   }
00182   
00183   error:
00184   free(auth);
00185   
00186 }
00187 
00188 
00195 void check_process(char *P, char *action, int toggle_validate_flag) {
00196 
00197   Process_T p= NULL;
00198 
00199   ASSERT(P);
00200   ASSERT(action);
00201 
00202   if(NULL==(p= get_process(P))) {
00203     error("%s: Cannot %s program '%s' -- not found in %s\n",
00204           prog, action, P, Run.controlfile);
00205     return;
00206   }
00207 
00208   if(is(action, "start")) {
00209     
00210     if(is_process_running(p)) {
00211       return;
00212     }
00213     
00214     if(!p->start) {
00215       error("%s: Start method not defined -- process %s\n",
00216         prog, P);
00217       return;
00218     }
00219     
00220     do_depend(p, "stop", toggle_validate_flag);
00221     do_start(p, toggle_validate_flag);
00222     do_depend(p, "start", toggle_validate_flag);
00223     
00224   } else if(is(action, "stop")) {
00225     
00226     if(!p->stop) {
00227       error("%s: Stop method not defined -- process %s\n",
00228         prog, P);
00229       return;
00230     }
00231     
00232     do_depend(p, "stop", toggle_validate_flag);
00233     do_stop(p, toggle_validate_flag);
00234     
00235   }
00236     
00237 }
00238 
00239 
00240 /*
00241  * Reset the visited flags used when handling dependencies
00242  */
00243 void reset_depend() {
00244 
00245   Process_T p;
00246   
00247   for (p= processlist; p; p= p->next) {
00248     p->visited= FALSE;
00249     p->depend_visited= FALSE;
00250   }
00251 
00252 }
00253 
00254 
00255 /* ----------------------------------------------------------------- Private */
00256 
00257 
00258 /*
00259  * This is a post- fix recursive function for starting every process
00260  * that p depends on before starting p.
00261  * @param p A Process_T object
00262  * @param toggle_validate_flag Turn on validate if defined
00263  */
00264 static void do_start(Process_T p, int toggle_validate_flag) {
00265 
00266   ASSERT(p);
00267 
00268   if(p->visited)
00269       return;
00270   
00271   p->visited= TRUE;
00272   
00273   if(p->dependantlist) {
00274     
00275     Dependant_T d;
00276     
00277     for(d= p->dependantlist; d; d= d->next ) {
00278       
00279       Process_T dp= get_process(d->dependant);
00280       ASSERT(dp);
00281       do_start(dp, toggle_validate_flag);
00282       
00283     }
00284   }
00285   
00286   if(toggle_validate_flag) {
00287     LOCK(Run.mutex)
00288     p->do_validate= TRUE;
00289     END_LOCK;
00290     if(Run.debug)
00291     log("Monitoring enabled -- process %s\n", p->name);
00292   }
00293 
00294   if(p->start && p->do_validate && (!is_process_running(p))) {
00295     log("start: (%s) %s\n", p->name, p->start->arg[0]);
00296     spawn(p, p->start);
00297     wait_start(p);
00298   }
00299   
00300 }
00301 
00302 
00303 /*
00304  * This function simply stops the process p.
00305  * @param p A Process_T object
00306  * @param toggle_validate_flag Turn off validate if defined
00307  */
00308 static void do_stop(Process_T p, int toggle_validate_flag) {
00309 
00310   ASSERT(p);
00311 
00312   if(p->depend_visited)
00313       return;
00314   
00315   p->depend_visited= TRUE;
00316   
00317   if(p->stop && p->do_validate && is_process_running(p)) {
00318     log("stop: (%s) %s\n", p->name, p->stop->arg[0]);
00319     spawn(p, p->stop);
00320     memset(p->procinfo, 0, sizeof *(p->procinfo));
00321     wait_stop(p);
00322   }
00323 
00324   /* Reset the proc info object in case of a later restart */
00325   memset(p->procinfo, 0, sizeof *(p->procinfo));
00326   
00327   if(toggle_validate_flag) {
00328     LOCK(Run.mutex)
00329     p->do_validate= FALSE;
00330     END_LOCK;
00331     if(Run.debug)
00332     log("Monitoring disabled -- process %s\n", p->name);
00333   }
00334 
00335 }
00336 
00337 
00338 /*
00339  * This is an in-fix recursive function called before p is started to
00340  * stop every process that depends on p, in reverse order *or* after p
00341  * was started to start again every process that depends on p. The
00342  * action parametere controls if this function should start or stop
00343  * the procceses that depends on p.
00344  * @param p A Process_T object
00345  * @param action An action to do on the dependant processes
00346  * @param toggle_validate_flag passed to the start/stop functions
00347  */
00348 static void do_depend(Process_T p, char *action, int toggle_validate_flag) {
00349 
00350   Process_T parent;
00351   
00352   ASSERT(p);
00353 
00354   for(parent= processlist; parent; parent= parent->next) {
00355     
00356     if(parent->dependantlist) {
00357 
00358       Dependant_T d;
00359     
00360       for(d= parent->dependantlist; d; d= d->next)
00361       if(is(d->dependant, p->name))
00362          break;
00363       
00364       if(d) {
00365     
00366     if(is(action, "start"))
00367         do_start(parent, toggle_validate_flag);
00368     
00369     do_depend(parent, action, toggle_validate_flag);
00370     
00371     if(is(action, "stop"))
00372         do_stop(parent, toggle_validate_flag);
00373     
00374       }
00375     }
00376   }
00377 }
00378     
00379 
00380 /*
00381  * This function suspend the control until the process p is running.
00382  * @param p A Process to wait for
00383  */
00384 static void wait_start(Process_T p) {
00385 
00386   int max_tries= Run.polltime;
00387   
00388   ASSERT(p);
00389 
00390   while(max_tries--) {
00391     if(is_process_running(p))
00392     break;
00393     sleep(1);
00394   }
00395   
00396   if(!is_process_running(p))
00397       log("%s: Warning process '%s' was not started\n", p->name);
00398   
00399 }
00400 
00401 
00402 /*
00403  * This function suspend the control until the process p is stopped.
00404  * @param p A Process to wait for
00405  */
00406 static void wait_stop(Process_T p) {
00407 
00408   int max_tries= Run.polltime;
00409   
00410   ASSERT(p);
00411 
00412   while(max_tries--) {
00413     if(!is_process_running(p))
00414     break;
00415     sleep(1);
00416   }
00417 
00418   if(is_process_running(p))
00419       log("%s: Warning process '%s' was not stopped\n", p->name);
00420 
00421 }