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