monitor.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 #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 "ssl.h"
00051 #include "monit_process.h"
00052 
00070 /* --- Private Prototypes -------------------------------------------------- */
00071 static void  do_init();                       /* Initialize this application */
00072 static RETSIGTYPE do_reload(int);       /* Signalhandler for a daemon reload */
00073 static void  do_reinit();           /* Re-initialize the runtime application */
00074 static void  do_action(char **);         /* Dispatch to the submitted action */
00075 static RETSIGTYPE  do_destroy(int);             /* Finalize this application */
00076 static void  do_default();                              /* Do default action */
00077 static RETSIGTYPE  do_wakeup(int); /* Signalhandler for a daemon wakeup call */
00078 static int   do_wakeupcall();              /* Wakeup a sleeping monit daemon */
00079 static void  handle_options(int, char **);         /* Handle program options */
00080 static void  help();                 /* Print program help message to stdout */
00081 static void  version();                         /* Print version information */
00082 static void  stop_http();                                 /* Stop monit http */
00083 static void  start_http();                               /* Start monit http */
00084 
00085 
00089 int main(int argc, char **argv) {
00090 
00091   prog= stripfilename(argv[0]);
00092   init_env();
00093   handle_options(argc, argv);
00094  
00095   do_init();
00096   do_action(argv); 
00097   do_destroy(SIGSTOP);
00098 
00099   exit(0);
00100   
00101 }
00102 
00103 
00104 /* ----------------------------------------------------------------- Private */
00105 
00106 
00112 static void do_init() {
00113 
00114   int status;
00115 
00116   /*
00117    * Register interest for the SIGTERM signal,
00118    * in case we run in daemon mode this signal
00119    * will terminate a running daemon.
00120    */
00121   signal(SIGTERM, do_destroy);
00122 
00123   /*
00124    * Register interest for the SIGUSER1 signal,
00125    * in case we run in daemon mode this signal
00126    * will wakeup a sleeping daemon.
00127    */
00128   signal(SIGUSR1, do_wakeup);
00129 
00130   /*
00131    * Register interest for the SIGHUP signal,
00132    * in case we run in daemon mode this signal
00133    * will reload the configuration.
00134    */
00135   signal(SIGHUP, do_reload);
00136 
00137   /*
00138    * Register no interest for the SIGPIPE signal,
00139    */
00140   signal(SIGPIPE, SIG_IGN);
00141 
00142   /*
00143    * Initialize the Runtime mutex. This mutex
00144    * is used to synchronize handling of global
00145    * process data
00146    */
00147   status= pthread_mutex_init(&Run.mutex, NULL);
00148   if(status != 0) {
00149     
00150     log("%s: Cannot initialize mutex -- %s\n", prog, strerror(status));
00151     exit(1);
00152     
00153   }
00154 
00155   /* 
00156    * Get the position of the control file 
00157    */
00158   if(! Run.controlfile) {
00159     
00160     Run.controlfile= find_rcfile();
00161     
00162   }
00163   
00164   /*
00165    * Initialize the process information gathering interface
00166    */
00167   Run.doprocess= init_process_info();
00168 
00169   /*
00170    * Start the Parser and create the process list. This will also set
00171    * any Runtime constants defined in the controlfile.
00172    */
00173   if(! parse(Run.controlfile)) {
00174     
00175     exit(1);
00176     
00177   }
00178 
00179   /*
00180    * Stop and report success if we are just validating the Control
00181    * file syntax. The previous parse statement exits the program with
00182    * an error message if a syntax error is present in the control
00183    * file.
00184    */
00185   if(Run.testing) {
00186 
00187     error("Control file syntax OK\n");
00188     exit(0);
00189 
00190   }
00191 
00192   /*
00193    * Initialize the log system 
00194    */
00195   if(! log_init()) {
00196     
00197     exit(1);
00198     
00199   }
00200 
00201   /* 
00202    * Did we find any process ?  
00203    */
00204   if(! processlist) {
00205     
00206     log("%s: No programs have been specified\n", prog);
00207     exit(0);
00208     
00209   }
00210   
00211   /* 
00212    * Initialize Runtime file variables 
00213    */
00214   init_files();
00215 
00216   /* 
00217    * Should we print debug information ? 
00218    */
00219   if(Run.debug && Run.have_tty) {
00220     
00221     printrunlist();
00222     printprocesslist();
00223     
00224   }
00225 
00226 }
00227 
00228 
00233 static void do_reinit() {
00234 
00235   char *bind_addr;
00236   int port= Run.httpdport;
00237 
00238   Run.doreload= FALSE;
00239   
00240   bind_addr= Run.bind_addr?xstrdup(Run.bind_addr):NULL;
00241 
00242   log("Awakened by the SIGHUP signal\n");
00243   log("Reinitializing %s - Control file '%s'\n",
00244       prog, Run.controlfile);
00245   
00246   /* Run the garbage collector */
00247   gc();
00248 
00249   finalize_files();
00250 
00251   if(! parse(Run.controlfile)) {
00252     
00253     log("%s daemon died\n", prog);
00254     exit(1);
00255     
00256   }
00257 
00258   /* Close the current log */
00259   log_close();
00260 
00261   /* Reinstall the log system */
00262   if(! log_init()) {
00263     
00264     exit(1);
00265     
00266   }
00267 
00268   /* Did we find any process ?  */
00269   if(! processlist) {
00270     
00271     log("%s: No programs have been specified\n", prog);
00272     exit(0);
00273     
00274   }
00275 
00276   /* Reinitialize Runtime file variables */
00277   init_files();
00278 
00279   if(! create_pidfile(Run.pidfile)) {
00280       
00281     log("%s daemon died\n", prog);
00282     exit(1);
00283       
00284   }
00285 
00286   if(! can_http()) {
00287       
00288     stop_http();
00289       
00290   } else if(!is(bind_addr, Run.bind_addr) || port != Run.httpdport) {
00291       
00292     stop_http();
00293     start_http();
00294       
00295   } else if(! check_httpd()) {
00296 
00297     start_http();
00298       
00299   }
00300 
00301   free(bind_addr);
00302 
00303 }
00304 
00305 
00309 static void do_action(char **args) {
00310   
00311   char *action= args[optind];
00312   char *P= args[++optind];
00313   
00314   if(! action) {
00315     
00316     do_default();
00317     
00318   } else if(is(action, "start")) {
00319     
00320     if(P) {
00321       if(exist_daemon()) {
00322     d_check_process(P, "start");
00323       } else {
00324     check_process(P, "start");
00325       }
00326     } else {
00327       
00328       if(Run.mygroup)
00329     control_group(Run.mygroup, "start");
00330       else
00331     control("start");
00332     }
00333   
00334   } else if(is(action, "stop")) {
00335     
00336     if(P) {
00337       if(exist_daemon()) {
00338     d_check_process(P, "stop");
00339       } else {
00340     check_process(P, "stop");
00341       }
00342     } else {
00343       
00344       if(Run.mygroup)
00345     control_group(Run.mygroup, "stop");
00346       else
00347     control("stop");
00348     }
00349     
00350   } else if(is(action, "reload")) {
00351     
00352     error("Reinitializing monit daemon\n", prog);
00353     kill_daemon(SIGHUP);
00354     
00355   } else if(is(action, "restart")) {
00356     
00357     if(P) {
00358       
00359       if(! exist_process(P)) {
00360     
00361     error("%s: Cannot restart program '%s' -- not found in %s\n",
00362           prog, P, Run.controlfile);
00363     
00364     return;
00365     
00366       }
00367       
00368       if(exist_daemon()) {
00369     d_check_process(P, "restart");
00370       } else {
00371     check_process(P, "restart");
00372       }
00373       
00374     } else {
00375       
00376       if(Run.mygroup)
00377       control_group(Run.mygroup, "restart");
00378       else
00379       control("restart");
00380     }
00381     
00382   } else if(is(action, "status")) {
00383     
00384     if(Run.mygroup) {
00385       status_group(Run.mygroup);
00386     } else {
00387       status();
00388     }
00389     
00390   } else if(is(action, "quit")) {
00391     
00392     error("Stopping monit daemon\n", prog);
00393     kill_daemon(SIGTERM);
00394     
00395   } else if(is(action, "validate")) {
00396     
00397     validate();
00398     
00399   } else {
00400     
00401     error("%s: invalid argument -- %s  (-h will show valid arguments)\n",
00402       prog, action);
00403     exit(1);
00404     
00405   }
00406   
00407   reset_depend();
00408   
00409 }
00410 
00411 
00415 static RETSIGTYPE do_wakeup(int sig) {
00416 
00417   signal(SIGUSR1, SIG_IGN);
00418   log("Awakened by User defined signal 1\n");
00419   signal(SIGUSR1, do_wakeup);
00420 
00421 }
00422 
00423 
00427 static RETSIGTYPE do_reload(int sig) {
00428 
00429   signal(SIGHUP, SIG_IGN);
00430   Run.doreload= TRUE;
00431   signal(SIGHUP, do_reload);
00432   
00433 }
00434 
00435 
00440 static int do_wakeupcall() {
00441 
00442   pid_t pid;
00443   
00444   if((pid= exist_daemon()) > 0) {
00445     
00446     kill(pid, SIGUSR1);
00447     error("%s daemon at %d awakened\n", prog, pid);
00448     
00449     return TRUE;
00450     
00451   }
00452   
00453   return FALSE;
00454   
00455 }
00456 
00457 
00461 static RETSIGTYPE do_destroy(int sig) {
00462   
00463   switch(sig) {
00464     
00465   case SIGTERM:
00466       
00467       stop_http();
00468       
00469       if(Run.isdaemon) {
00470     
00471     log("%s daemon with pid [%d] killed\n", prog, (int)getpid());
00472     
00473       }
00474       
00475       finalize_files();
00476       /* Fall trough */
00477       
00478   default:
00479       
00480       gc();
00481       log_close();
00482       exit(0);
00483       
00484   }
00485  
00486 }
00487 
00488 
00494 static void do_default() {
00495 
00496   if(Run.isdaemon) {
00497     
00498     if(do_wakeupcall()) {
00499       
00500       exit(0);
00501       
00502     }
00503   
00504     log("Starting %s daemon\n", prog);
00505     
00506     if(can_http()) {
00507       
00508       log("Starting httpd at [%s:%d]\n",
00509       Run.bind_addr?Run.bind_addr:"*", Run.httpdport);
00510       
00511     }
00512     
00513     if(Run.init != TRUE)
00514     daemonize(); 
00515     
00516     if(! create_pidfile(Run.pidfile)) {
00517       
00518       log("%s daemon died\n", prog);
00519       exit(1);
00520       
00521     }
00522 
00523     if(can_http()) {
00524 
00525       start_http();
00526       
00527     }
00528     
00529     for(;;) {
00530 
00531       if(Run.validate != TRUE) {
00532     validate();
00533       } else {
00534     Run.validate= FALSE;
00535       }
00536 
00537       sleep(Run.polltime);
00538 
00539       if(Run.doreload)
00540       do_reinit();
00541 
00542     }
00543     
00544   }
00545   else {
00546     
00547     validate();
00548     
00549   }
00550 
00551 }
00552 
00553 
00558 static void handle_options(int argc, char **argv) {
00559   
00560   int opt;
00561 
00562   opterr= 0;
00563 
00564   Run.mygroup=0;
00565 
00566   while((opt= getopt(argc,argv,"c:d:g:l:p:iItvVh")) != -1) {
00567 
00568     switch(opt) {
00569 
00570     case 'c':
00571         Run.controlfile= xstrdup(optarg);
00572         break;
00573     
00574     case 'd':
00575     Run.isdaemon= TRUE;
00576     sscanf(optarg, "%d", &Run.polltime);
00577     if(Run.polltime<1) {
00578       error("%s: option -%c requires a natural number\n", prog, opt);
00579       exit(1);
00580     }
00581     break;
00582 
00583     case 'g':
00584         Run.mygroup= xstrdup(optarg);
00585         break;
00586     
00587     case 'l':
00588         Run.logfile= xstrdup(optarg);
00589     if(is(Run.logfile, "syslog"))
00590         Run.use_syslog= TRUE;
00591     Run.dolog= TRUE;
00592         break;
00593    
00594     case 'p':
00595         Run.pidfile= xstrdup(optarg);
00596         break;
00597 
00598     case 'i':
00599         Run.validate= TRUE;
00600         break;
00601 
00602     case 'I':
00603     Run.init= TRUE;
00604     break;
00605       
00606     case 't':
00607         Run.testing= TRUE;
00608         break;
00609     
00610     case 'v':
00611         Run.debug= TRUE;
00612         break;
00613     
00614     case 'V':
00615         version();
00616         exit(0);
00617     break;
00618     
00619     case 'h':
00620         help();
00621         exit(0);
00622     break;
00623     
00624     case '?':
00625     switch(optopt) {
00626       
00627     case 'c':
00628     case 'd':
00629     case 'g':
00630     case 'l':
00631     case 'p':
00632         error("%s: option -- %c requires an argument\n", prog, optopt);
00633         break;
00634     default:
00635         error("%s: invalid option -- %c  (-h will show valid options)\n",
00636           prog, optopt);
00637         
00638     }
00639     
00640     exit(1);
00641     
00642     }
00643     
00644   }
00645   
00646 }
00647 
00648 
00652 static void help() {
00653   
00654   printf("Usage: %s [options] {arguments}\n", prog);
00655   printf("Options are as follows:\n");
00656   printf(" -c file     Use this control file\n");
00657   printf(" -d n        Run as a daemon once per n seconds\n");
00658   printf(" -g name     Set group name for start, stop, restart and status\n");
00659   printf(" -l logfile  Print log information to this file\n");
00660   printf(" -p pidfile  Use this lock file in daemon mode\n");
00661   printf(" -i          Validate mode, startup in validate mode\n");
00662   printf(" -I          Init mode, run from init\n");
00663   printf(" -t          Run syntax check for the control file\n");
00664   printf(" -v          Verbose mode, work noisy (diagnostic output)\n");
00665   printf(" -V          Print version number and patchlevel\n");
00666   printf(" -h          Print this text\n");
00667   printf("Optional action arguments for non-daemon mode are as follows:\n");
00668   printf(" start        - Start all programs listed in the control file\n");
00669   printf(" start name   - Only start the named program in the control file\n");
00670   printf(" stop         - Stop all programs listed in the control file\n");
00671   printf(" stop name    - Only stop the named program in the control file\n");
00672   printf(" reload       - Reinitialize monit\n");
00673   printf(" restart      - Stop and start all programs\n");
00674   printf(" restart name - Only restart the named program in the control file\n");
00675   printf(" status       - Print status information for each program\n");
00676   printf(" quit         - Kill monit daemon process\n");
00677   printf(" validate     - Check all programs and start if not running.\n");
00678 
00679 }
00680 
00681 
00685 static void version() {
00686 
00687   printf("This is monit version %s\n", VERSION);
00688   printf("Copyright (C) 2000-2003 by Contributors to the monit codebase\n");
00689  
00690 }
00691 
00692 
00696 static void stop_http() {
00697 
00698   monit_http(STOP_HTTP);
00699 
00700 }
00701 
00702 
00706 static void start_http() {
00707 
00708   monit_http(START_HTTP);
00709 
00710 }
00711 
00712