monitor.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 <stdlib.h>
00024 #include <errno.h>
00025 #include <signal.h>
00026 
00027 #ifdef HAVE_GETOPT_H
00028 #include <getopt.h>
00029 #endif
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 #ifdef HAVE_SYS_TYPES_H
00040 #include <sys/types.h>
00041 #endif
00042 
00043 #ifdef HAVE_SYS_STAT_H
00044 #include <sys/stat.h>
00045 #endif
00046 
00047 
00048 #include "monitor.h"
00049 #include "net.h"
00050 #include "monit_process.h"
00051 
00067 /* --- Private Prototypes -------------------------------------------------- */
00068 static void  do_init();                       /* Initialize this application */
00069 static void  do_reinit();           /* Re-initialize the runtime application */
00070 static void  do_action(char **);         /* Dispatch to the submitted action */
00071 static RETSIGTYPE  do_destroy(int);             /* Finalize this application */
00072 static void  do_default();                              /* Do default action */
00073 static RETSIGTYPE  do_wakeup(int); /* Signalhandler for a daemon wakeup call */
00074 static int   do_wakeupcall();              /* Wakeup a sleeping monit daemon */
00075 static void  do_wait();                               /* Wait for 10 seconds */
00076 static void  handle_options(int, char **);         /* Handle program options */
00077 static void  help();                 /* Print program help message to stdout */
00078 static void  version();                         /* Print version information */
00079 static void  stop_http();                                 /* Stop monit http */
00080 static void  start_http();                               /* Start monit http */
00081 
00082 
00086 int main(int argc, char **argv) {
00087 
00088   prog= stripfilename(argv[0]);
00089   init_env();
00090   handle_options(argc, argv);
00091  
00092   do_init();
00093   do_action(argv); 
00094   do_destroy(SIGSTOP);
00095 
00096   exit(0);
00097   
00098 }
00099 
00100 
00101 /* ----------------------------------------------------------------- Private */
00102 
00103 
00109 static void do_init() {
00110 
00111   int status;
00112 
00113   /*
00114    * Register interest for the SIGTERM signal,
00115    * in case we run in daemon mode this signal
00116    * will terminate a running daemon.
00117    */
00118   signal(SIGTERM, do_destroy);
00119 
00120   /*
00121    * Register interest for the SIGUSER1 signal,
00122    * in case we run in daemon mode this signal
00123    * will wakeup a sleeping daemon.
00124    */
00125   signal(SIGUSR1, do_wakeup);
00126 
00127   /*
00128    * Register no interest for the SIGPIPE signal,
00129    */
00130   signal(SIGPIPE, SIG_IGN);
00131 
00132   /*
00133    * Initialize the Runtime mutex. This mutex
00134    * is used to synchronize handling of global
00135    * process data
00136    */
00137   status= pthread_mutex_init(&Run.mutex, NULL);
00138   if ( status != 0 ) {
00139     
00140     error("%s: Cannot initialize mutex -- %s\n", prog, strerror(status));
00141     exit(1);
00142     
00143   }
00144 
00145   /* Controlfile */
00146   if ( ! Run.controlfile ) {
00147     
00148     Run.controlfile= find_rcfile();
00149     
00150   }
00151   
00152   /* Initialize proc interface */
00153   Run.doprocess= init_process_info();
00154 
00155   /*
00156    * Start the Parser and create the process list. This will also set
00157    * any Runtime constants defined in the controlfile.
00158    */
00159   if ( ! parse(Run.controlfile) ) {
00160     
00161     exit(1);
00162     
00163   }
00164   
00165   /* Initialize the log system */
00166   if ( ! log_init() ) {
00167     
00168     exit(1);
00169     
00170   }
00171 
00172   /* Did we find any process ?  */
00173   if ( ! processlist ) {
00174     
00175     error("%s: No programs have been specified\n", prog);
00176     exit(0);
00177     
00178   }
00179   
00180   /* Initialize Runtime file variables */
00181   init_files();
00182 
00183   /* Should we print debug information ? */
00184   if ( Run.debug && have_tty ) {
00185     
00186     printrunlist();
00187     printprocesslist();
00188     
00189   }
00190 
00191 }
00192 
00193 
00199 static void do_reinit() {
00200 
00201   log("Reinitializing %s - Control file '%s' was changed\n",
00202       prog, Run.controlfile);
00203   
00204   /* Run the garbage collector */
00205   gc();
00206 
00207   if ( ! parse(Run.controlfile) ) {
00208     
00209     log("%s daemon died\n", prog);
00210     exit(1);
00211     
00212   }
00213 
00214   /* Close the current log */
00215   log_close();
00216 
00217   /* Reinstall the log system */
00218   if ( ! log_init() ) {
00219     
00220     exit(1);
00221     
00222   }
00223 
00224   /* Did we find any process ?  */
00225   if ( ! processlist ) {
00226     
00227     error("%s: No programs have been specified\n", prog);
00228     exit(0);
00229     
00230   }
00231 
00232   /* Re-Initialize Runtime file variables */
00233   re_init_files();
00234   
00235 }
00236 
00237 
00241 static void do_action(char **args) {
00242   
00243   char *action= args[optind];
00244   char *P= args[++optind];
00245   
00246   if( ! action ) {
00247     
00248     do_default();
00249     
00250   }
00251   else if( is(action, "start") ) {
00252     
00253     if ( P ) dstart_process(P); else
00254        if ( mygroup ) start_group(mygroup); else start();
00255   
00256   }
00257   else if( is(action, "stop") ) {
00258     
00259     if ( P ) dstop_process(P); else
00260        if ( mygroup ) stop_group(mygroup); else stop();
00261     
00262   }
00263   else if( is(action, "restart") ) {
00264     
00265     if ( P ) {
00266       
00267       if ( ! exist_process(P) ) {
00268     
00269     error("%s: Cannot restart program '%s' -- not found in %s\n",
00270           prog, P, Run.controlfile);
00271     
00272     return;
00273     
00274       }
00275       
00276       dstop_process(P);
00277       
00278     } else
00279     if ( mygroup ) stop_group(mygroup); else stop();
00280     
00281     do_wait();
00282     
00283     if ( P ) dstart_process(P); else
00284        if ( mygroup ) start_group(mygroup); else start();
00285     
00286   }
00287   else if( is(action, "status") ) {
00288     
00289     if ( mygroup ) status_group(mygroup); else status();
00290     
00291   }
00292   else if( is(action, "quit") ) {
00293     
00294     log("Stopping monit daemon\n", prog);
00295     kill_daemon();
00296     
00297   }
00298   else if( is(action, "validate") ) {
00299     
00300     validate();
00301     
00302   }
00303   else {
00304     
00305     error("%s: invalid argument -- %s  (-h will show valid arguments)\n",
00306       prog, action);
00307     exit(1);
00308     
00309   }
00310   
00311 }
00312 
00313 
00317 static RETSIGTYPE do_wakeup(int sig) {
00318 
00319   signal(SIGUSR1, SIG_IGN);
00320   log("Awakened by User defined signal 1\n");
00321   signal(SIGUSR1, do_wakeup);
00322 
00323 }
00324 
00325 
00330 static int do_wakeupcall() {
00331 
00332   pid_t pid;
00333   
00334   if ( (pid= exist_daemon()) > 0 ) {
00335     
00336     kill(pid, SIGUSR1);
00337     error("%s daemon at %d awakened\n", prog, pid);
00338     
00339     return TRUE;
00340     
00341   }
00342   
00343   return FALSE;
00344   
00345 }
00346 
00347 
00351 static RETSIGTYPE do_destroy(int sig) {
00352   
00353   switch ( sig ) {
00354     
00355   case SIGTERM:
00356       
00357       stop_http();
00358       
00359       if ( Run.isdaemon ) {
00360     
00361     log("%s daemon with pid [%d] killed\n", prog, (int)getpid());
00362     
00363       }
00364       
00365       finalize_files();
00366       /* Fall trough */
00367       
00368   default:
00369       
00370       gc();
00371       log_close();
00372       exit(0);
00373       
00374   }
00375  
00376 }
00377 
00378 
00384 static void do_default() {
00385 
00386   if ( Run.isdaemon ) {
00387     
00388     if ( do_wakeupcall() ) {
00389       
00390       exit(0);
00391       
00392     }
00393   
00394     log("Starting %s daemon\n", prog);
00395     if(!Run.debug) printf("Starting %s daemon\n", prog);
00396     
00397     if ( can_http() ) {
00398       
00399       printf("Starting httpd at port [%d]\n", Run.httpdport);
00400       
00401     }
00402    
00403     have_tty= FALSE;
00404 
00405     if (Run.Init != TRUE)
00406     daemonize(); 
00407     
00408     if ( !create_pidfile(Run.pidfile) ) {
00409       
00410       log("%s daemon died\n", prog);
00411       exit(1);
00412       
00413     }
00414 
00415     if ( can_http() ) {
00416 
00417       start_http();
00418       
00419     }
00420     
00421     for (;;) {
00422       
00423       if (Run.validate != TRUE)
00424     {
00425       validate();
00426     } else {
00427       Run.validate= FALSE;
00428     }
00429 
00430       sleep(Run.polltime);
00431       
00432       if ( is_rcfile_changed() ) {
00433     
00434     int port= Run.httpdport;
00435 
00436     do_reinit();
00437     
00438     if ( ! can_http() ) {
00439       
00440       stop_http();
00441       
00442     } else if ( port != Run.httpdport ) {
00443       
00444       stop_http();
00445       start_http();
00446       
00447     } else if ( ! check_httpd() ) {
00448 
00449       start_http();
00450 
00451     }
00452 
00453       }
00454       
00455     }
00456     
00457   }
00458   else {
00459     
00460     validate();
00461     
00462   }
00463 
00464 }
00465 
00466 
00471 static void handle_options(int argc, char **argv) {
00472   
00473   char opt;
00474   opterr= 0;
00475 
00476   mygroup=0;
00477 
00478   while((opt= getopt(argc,argv,"c:l:d:g:iIvVh")) != -1) {
00479     
00480     switch(opt) {
00481 
00482     case 'i':
00483         Run.validate= TRUE;
00484         break;
00485 
00486     case 'I':
00487     Run.Init= TRUE;
00488     break;
00489       
00490     case 'c':
00491         Run.controlfile= xstrdup(optarg);
00492         break;
00493     
00494     case 'l':
00495         Run.logfile= xstrdup(optarg);
00496     if ( is(Run.logfile, "syslog") )
00497         Run.use_syslog= TRUE;
00498     Run.dolog= TRUE;
00499         break;
00500    
00501     case 'g':
00502         mygroup= xstrdup(optarg);
00503         break;
00504     
00505     case 'd':
00506     Run.isdaemon= TRUE;
00507     sscanf(optarg, "%d", &Run.polltime);
00508     if (Run.polltime<1) {
00509       error("%s: option -%c requires a natural number\n", prog, opt);
00510       exit(1);
00511     }
00512     break;
00513 
00514     case 'v':
00515         Run.debug= TRUE;
00516         break;
00517     
00518     case 'V':
00519         version();
00520         exit(0);
00521     break;
00522     
00523     case 'h':
00524         help();
00525         exit(0);
00526     break;
00527     
00528     case '?':
00529     switch ( optopt ) {
00530       
00531     case 'c':
00532     case 'g':
00533     case 'l':
00534     case 'd':
00535         error("%s: option -- %c requires an argument\n", prog, optopt);
00536         break;
00537     default:
00538         error("%s: invalid option -- %c  (-h will show valid options)\n",
00539           prog, optopt);
00540         
00541     }
00542     
00543     exit(1);
00544     
00545     }
00546     
00547   }
00548   
00549 }
00550 
00551 
00555 static void help() {
00556   
00557   printf("Usage: %s [options] {arguments}\n", prog);
00558   printf("Options are as follows:\n");
00559   printf(" -c file, Use this control file\n");
00560   printf(" -l logfile, Print log information to this file\n");
00561   printf(" -d n, run as a daemon once per n seconds\n");
00562   printf(" -i, Validate mode, startup in validate mode\n");
00563   printf(" -I, Init mode, run from init\n");
00564   printf(" -v Verbose mode, work noisy (diagnostic output)\n");
00565   printf(" -V Print version number and patchlevel\n");
00566   printf(" -g Set group name for start, stop, restart and status\n");
00567   printf(" -h Print this text\n");
00568   printf("Optional action arguments for non-daemon mode are as follows:\n");
00569   printf(" start        - Start all programs listed in the control file\n");
00570   printf(" start name   - Only start the named program in the control file\n");
00571   printf(" stop         - Stop all programs listed in the control file\n");
00572   printf(" stop name    - Only stop the named program in the control file\n");
00573   printf(" restart      - Stop and start all programs\n");
00574   printf(" restart name - Only restart the named program in the control file\n");
00575   printf(" status       - Print status information for each program\n");
00576   printf(" quit         - Kill monit daemon process\n");
00577   printf(" validate     - Check all programs and start if not running.\n");
00578 
00579 }
00580 
00581 
00585 static void version() {
00586 
00587   printf("This is monit version %s\n", VERSION);
00588   printf("Copyright (C) 2000-2002 by Contributors to the monit codebase\n");
00589  
00590 }
00591 
00592 
00596 static void do_wait() {
00597   
00598   int i;
00599 
00600   if ( have_tty ) {
00601     
00602     fprintf(stdout, "Please wait for restart: ");
00603     
00604     for (i= 0; i<10; i++) {
00605       
00606       fprintf(stdout, "."); fflush(stdout);
00607       sleep(1);
00608       
00609     }
00610     
00611     fprintf(stdout, "\n");
00612     
00613   } else {
00614     
00615     sleep(10);
00616     
00617   }
00618   
00619 }
00620 
00621 
00625 static void stop_http() {
00626 
00627   monit_http(STOP_HTTP);
00628 
00629 }
00630 
00631 
00635 static void start_http() {
00636 
00637   monit_http(START_HTTP);
00638 
00639 }