control.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C), 2000-2003 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 #include "ssl.h"
00042 
00043 
00044 /* Private Prototypes */
00045 static void wait_stop(Process_T);
00046 static void wait_start(Process_T);
00047 static void do_stop(Process_T);
00048 static void do_start(Process_T);
00049 static void do_depend(Process_T, char *);
00050 
00051 
00064 /* ------------------------------------------------------------------ Public */
00065 
00066 
00071 void control(char *action) {
00072 
00073   Process_T p;
00074 
00075   ASSERT(action);
00076 
00077   for(p= processlist; p; p= p->next) {
00078     if(p->visited)
00079     continue;
00080     if(exist_daemon()) {
00081       d_check_process(p->name, action);
00082     } else {
00083       check_process(p->name, action);
00084     }
00085   }
00086   
00087   reset_depend();
00088 
00089 }
00090 
00091 
00092 /*
00093  * Start/stop all processes in a group
00094  * @param G group name
00095  * @param action A string describing the action to execute
00096  */
00097 void control_group(char *G, char *action) {
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);
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, SSL_VERSION_AUTO);
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 to 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 
00194 void check_process(char *P, char *action) {
00195 
00196   Process_T p= NULL;
00197 
00198   ASSERT(P);
00199   ASSERT(action);
00200 
00201   if(NULL==(p= get_process(P))) {
00202     error("%s: Cannot %s program '%s' -- not found in %s\n",
00203           prog, action, P, Run.controlfile);
00204     return;
00205   }
00206 
00207   if(is(action, "start")) {
00208     
00209     if(is_process_running(p)) {
00210 
00211       if(!p->do_validate) {
00212 
00213         LOCK(Run.mutex)
00214           p->do_validate= TRUE;
00215         END_LOCK;
00216 
00217         if(Run.debug)
00218           log("Monitoring enabled -- process %s\n", p->name);
00219 
00220       }
00221 
00222       return;
00223     }
00224     
00225     if(!p->start) {
00226       error("%s: Start method not defined -- process %s\n",
00227         prog, P);
00228       return;
00229     }
00230     
00231     do_depend(p, "stop");
00232     do_start(p);
00233     do_depend(p, "start");
00234     
00235   } else if(is(action, "stop")) {
00236     
00237     if(!p->stop) {
00238       error("%s: Stop method not defined -- process %s\n",
00239         prog, P);
00240       return;
00241     }
00242     
00243     do_depend(p, "stop");
00244     do_stop(p);
00245     
00246   } else if(is(action, "restart")) {
00247     
00248     if(!p->start || !p->stop) {
00249       error("%s: Start or stop method not defined -- process %s\n",
00250         prog, P);
00251       return;
00252     }
00253     
00254     do_depend(p, "stop");
00255     do_stop(p);
00256     do_start(p);
00257     do_depend(p, "start");
00258     
00259   }
00260     
00261 }
00262 
00263 
00264 /*
00265  * Reset the visited flags used when handling dependencies
00266  */
00267 void reset_depend() {
00268 
00269   Process_T p;
00270   
00271   for (p= processlist; p; p= p->next) {
00272     p->visited= FALSE;
00273     p->depend_visited= FALSE;
00274   }
00275 
00276 }
00277 
00278 
00279 /* ----------------------------------------------------------------- Private */
00280 
00281 
00282 /*
00283  * This is a post- fix recursive function for starting every process
00284  * that p depends on before starting p.
00285  * @param p A Process_T object
00286  */
00287 static void do_start(Process_T p) {
00288 
00289   ASSERT(p);
00290 
00291   if(p->visited)
00292       return;
00293   
00294   p->visited= TRUE;
00295   
00296   if(p->dependantlist) {
00297     
00298     Dependant_T d;
00299     
00300     for(d= p->dependantlist; d; d= d->next ) {
00301       
00302       Process_T dp= get_process(d->dependant);
00303       ASSERT(dp);
00304       do_start(dp);
00305       
00306     }
00307   }
00308   
00309   if(p->start && (!is_process_running(p))) {
00310     log("start: (%s) %s\n", p->name, p->start->arg[0]);
00311     spawn(p, p->start);
00312     wait_start(p);
00313   }
00314   
00315   LOCK(Run.mutex)
00316     p->do_validate= TRUE;
00317   END_LOCK;
00318 
00319   if(Run.debug)
00320     log("Monitoring enabled -- process %s\n", p->name);
00321 
00322 }
00323 
00324 
00325 /*
00326  * This function simply stops the process p.
00327  * @param p A Process_T object
00328  */
00329 static void do_stop(Process_T p) {
00330 
00331   ASSERT(p);
00332 
00333   if(p->depend_visited)
00334       return;
00335   
00336   p->depend_visited= TRUE;
00337   
00338   LOCK(Run.mutex)
00339     p->do_validate= FALSE;
00340   END_LOCK;
00341 
00342   if(Run.debug)
00343     log("Monitoring disabled -- process %s\n", p->name);
00344 
00345   if(p->stop && is_process_running(p)) {
00346     log("stop: (%s) %s\n", p->name, p->stop->arg[0]);
00347     spawn(p, p->stop);
00348     wait_stop(p);
00349   }
00350 
00351   /* Reset the proc info object in case of a later restart */
00352   memset(p->procinfo, 0, sizeof *(p->procinfo));
00353   
00354 }
00355 
00356 
00357 /*
00358  * This is an in-fix recursive function called before p is started to
00359  * stop every process that depends on p, in reverse order *or* after p
00360  * was started to start again every process that depends on p. The
00361  * action parametere controls if this function should start or stop
00362  * the procceses that depends on p.
00363  * @param p A Process_T object
00364  * @param action An action to do on the dependant processes
00365  */
00366 static void do_depend(Process_T p, char *action) {
00367 
00368   Process_T parent;
00369   
00370   ASSERT(p);
00371 
00372   for(parent= processlist; parent; parent= parent->next) {
00373     
00374     if(parent->dependantlist) {
00375 
00376       Dependant_T d;
00377     
00378       for(d= parent->dependantlist; d; d= d->next)
00379       if(is(d->dependant, p->name))
00380          break;
00381       
00382       if(d) {
00383     
00384     if(is(action, "start"))
00385         do_start(parent);
00386     
00387     do_depend(parent, action);
00388     
00389     if(is(action, "stop"))
00390         do_stop(parent);
00391     
00392       }
00393     }
00394   }
00395 }
00396     
00397 
00398 /*
00399  * This function suspend the control until the process p is running.
00400  * @param p A Process to wait for
00401  */
00402 static void wait_start(Process_T p) {
00403 
00404   int max_tries= Run.polltime;
00405   
00406   ASSERT(p);
00407 
00408   while(max_tries--) {
00409     if(is_process_running(p))
00410     break;
00411     sleep(1);
00412   }
00413   
00414   if(!is_process_running(p))
00415       log("%s: Warning process '%s' was not started\n", prog, p->name);
00416   
00417 }
00418 
00419 
00420 /*
00421  * This function suspend the control until the process p is stopped.
00422  * @param p A Process to wait for
00423  */
00424 static void wait_stop(Process_T p) {
00425 
00426   int max_tries= Run.polltime;
00427   
00428   ASSERT(p);
00429 
00430   while(max_tries--) {
00431     if(!is_process_running(p))
00432     break;
00433     sleep(1);
00434   }
00435 
00436   if(is_process_running(p))
00437       log("%s: Warning process '%s' was not stopped\n", prog, p->name);
00438 
00439 }