util.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 <stdarg.h>
00024 #include <errno.h>
00025 #include <ctype.h>
00026 #include <signal.h>
00027 #include <time.h>
00028 #include <stdlib.h>
00029 #include <sys/socket.h>
00030 
00031 #ifdef HAVE_STRING_H
00032 #include <string.h>
00033 #endif
00034 
00035 #ifdef HAVE_STRINGS_H
00036 #include <strings.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 #include "monitor.h"
00048 #include "engine.h"
00049 #include "md5.h"
00050 #include "base64.h"
00051 #include "alert.h"
00052 #include "monit_process.h"
00053 
00054 /* Private prototypes */
00055 static int is_unsafe(unsigned char *c);
00056 static char *is_str_defined(char *);
00057 static char *is_str_defined_default(char *);
00058 
00073 /* ------------------------------------------------------------------ Public */
00074 
00075 
00081 void error(const char *format, ...) {
00082   
00083   char msg[1024];
00084   va_list ap;
00085   
00086   va_start(ap,format);
00087   vsnprintf(msg, 1024, format, ap);
00088   va_end(ap);
00089   
00090   if (have_tty) {
00091     
00092     fprintf(stderr,"%s", msg);
00093     fflush(stderr);
00094     
00095   }
00096   else {
00097     
00098     log("%s", msg);
00099     
00100   }
00101   
00102 }
00103 
00104 
00108 int is_strdefined(char *p) {
00109   
00110   return (p && p[0] != '\0' && strlen(p) > 0);
00111   
00112 }
00113 
00114 
00120 char *stripfilename(char* path) {
00121   
00122   char *fname= strrchr(path, '/');
00123   
00124   return (fname ? ++fname : path);
00125   
00126 }
00127 
00128 
00133 void chomp(char *string) {
00134   
00135   char *p;
00136 
00137   if ((p= strchr(string, '\r'))   ||
00138        (p= strchr(string, '\n'))) {
00139     
00140     *p= '\0';
00141     
00142   }
00143   
00144 }
00145 
00146 
00152 char *trim(char *s) {
00153   
00154   ltrim(s);
00155   rtrim(s);
00156 
00157   return s;
00158   
00159 }
00160 
00161 
00167 char *ltrim(char *s) {
00168 
00169   char *t= s;
00170 
00171   while (*t==' ' || *t=='\t' || *t=='\r' || *t=='\n') t++;
00172 
00173   return strcpy(s, t);
00174 
00175 }
00176 
00177 
00183 char *rtrim(char *s) {
00184   
00185   char *t= s;
00186 
00187   while (*s) s++; 
00188   while (*--s==' ' || *s=='\t' || *s=='\r' || *s=='\n') *s= '\0';
00189 
00190   return t;
00191   
00192 }
00193 
00194 
00201 char *trim_quotes(char *s) {
00202 
00203   char *t= s;
00204   char tmp=0;
00205 
00206   while (*t==39 || *t==34 ) {
00207 
00208     tmp=*t;
00209     t++;
00210     break;
00211 
00212   }  
00213 
00214   if (t[strlen(t)-1]==tmp) t[strlen(t)-1]= '\0';
00215 
00216   return strcpy(s, t);
00217 
00218 }
00219 
00220 
00227 int starts_with(char *a, char *b) {
00228 
00229   if((!a || !b) || *a!=*b) return FALSE;
00230 
00231   while(*a && *b) {
00232     
00233     if(*a++ != *b++) return FALSE;
00234     
00235   }
00236 
00237   return TRUE;
00238 
00239 }
00240 
00241 
00247 void handle_string_escapes(char *buf) {
00248 
00249   int editpos;
00250   int insertpos;
00251 
00252   for(editpos=insertpos=0; *(buf+editpos)!='\0'; editpos++, insertpos++) {
00253 
00254     if(*(buf+editpos) == '\\' ) {
00255       
00256       switch (*(buf+editpos+1)) {
00257 
00258       case 'n': 
00259         *(buf+insertpos)='\n';
00260         editpos++;
00261     break;
00262 
00263       case 't':
00264         *(buf+insertpos)='\t';
00265         editpos++;
00266     break;
00267 
00268       case 'r':
00269         *(buf+insertpos)='\r';
00270         editpos++;
00271     break;
00272 
00273       case ' ':
00274         *(buf+insertpos)=' ';
00275         editpos++;
00276     break;
00277 
00278       case '\\':
00279         *(buf+insertpos)='\\';
00280         editpos++;
00281     break;
00282 
00283       default:
00284         *(buf+insertpos)=*(buf+editpos);
00285 
00286       }  
00287 
00288     } else {
00289 
00290       *(buf+insertpos)=*(buf+editpos);
00291 
00292     }  
00293 
00294   }
00295   *(buf+insertpos)='\0';
00296 
00297 }
00298 
00299 
00304 Process_T get_process(char *name) {
00305   
00306   Process_T p;
00307 
00308   for (p= processlist; p; p= p->next)
00309       if (is(p->name, name)) return p;
00310 
00311   return NULL;
00312 
00313 }
00314 
00315 
00321 int exist_process(char *name) {
00322   
00323   Process_T p;
00324 
00325   for (p= processlist; p; p= p->next)
00326       if (is(p->name, name)) return TRUE;
00327 
00328   return FALSE;
00329 
00330 }
00331 
00332 
00336 void printrunlist() {
00337   
00338   printf("Runtime constants:\n");
00339   printf(" %-18s = %s\n", "Control file", is_str_defined(Run.controlfile));
00340   printf(" %-18s = %s\n", "Log file", is_str_defined(Run.logfile));
00341   printf(" %-18s = %s\n", "Pid file", is_str_defined(Run.pidfile));
00342   printf(" %-18s = %s\n", "Debug", Run.debug?"True":"False");
00343   printf(" %-18s = %s\n", "Log", Run.dolog?"True":"False");
00344   printf(" %-18s = %s\n", "Use syslog", Run.use_syslog?"True":"False");
00345   printf(" %-18s = %s\n", "Is Daemon", Run.isdaemon?"True":"False");
00346   printf(" %-18s = %s\n", "Use process engine", Run.doprocess?"True":"False");
00347   printf(" %-18s = %d seconds\n", "Poll time", Run.polltime);
00348   printf(" %-18s = %s\n", "Mail server", is_str_defined(Run.mailserver));
00349   printf(" %-18s = %s\n", "Mail from", is_str_defined(Run.MailFormat.from));
00350   printf(" %-18s = %s\n", "Mail subject",
00351      is_str_defined(Run.MailFormat.subject));
00352   printf(" %-18s = %-.20s%s\n", "Mail message",
00353      Run.MailFormat.message?
00354      Run.MailFormat.message:"(not defined)",
00355      Run.MailFormat.message?"..(truncated)":"");
00356      
00357   printf(" %-18s = %s\n", "Start monit httpd", Run.dohttpd?"True":"False");
00358   
00359   if (Run.dohttpd) {
00360     
00361     printf(" %-18s = %d\n", "httpd portnumber", Run.httpdport);
00362     printf(" %-18s = %s\n", "httpd bind address",
00363        Run.bind_addr?Run.bind_addr:"Any/All");
00364     printf(" %-18s = %s\n", "httpd auth. style",
00365        Run.Auth.defined&&has_hosts_allow()?
00366        "Basic Authentication and Host allow list":
00367        Run.Auth.defined?"Basic Authentication":
00368        has_hosts_allow()?"Host allow list":
00369        "No authentication!");
00370      
00371   }
00372 
00373   printf("\n");
00374   
00375 }
00376 
00377 
00382 void printprocess(Process_T p) {
00383   
00384   Port_T n;
00385   Mail_T r;
00386   Resource_T q;
00387   Checksum_T c;
00388  
00389   printf("%-21s = %s\n", "Process Name", p->name);
00390   printf(" %-20s = %s\n", "Group", is_str_defined(p->group));
00391   printf(" %-20s = %s\n", "Pid file", p->pidfile);
00392   if(p->start)
00393       printf(" %-20s = %s\n", "Start program", is_str_defined(p->start->arg[0]));
00394   if(p->stop)
00395       printf(" %-20s = %s\n", "Stop program", is_str_defined(p->stop->arg[0]));
00396 
00397   for (c= p->checksumlist; c; c= c->next) {
00398     
00399     printf(" %-20s = %s %s\n", "Checksum", c->md5, c->file);
00400     
00401   }
00402 
00403   if (! p->checksumlist) {
00404     
00405     printf(" %-20s = (not defined)\n", "Other checksum");
00406     
00407   }
00408 
00409   if (! p->portlist) {
00410     
00411     printf(" %-20s = (not defined)\n", "Host:Port");
00412     
00413   } else {
00414   
00415     for (n= p->portlist; n; n= n->next) {
00416     
00417       if ( n->family == AF_INET ) {
00418 
00419         printf(" %-20s = %s:%d%s [protocol %s]\n", "Host:Port",
00420                n->hostname, n->port, n->request?n->request:"", n->protocol->name);
00421       } else if ( n->family == AF_UNIX ) {
00422 
00423         printf(" %-20s = %s [protocol %s]\n", "Unix Socket",
00424                n->pathname, n->protocol->name);
00425 
00426       }
00427     
00428     }
00429 
00430   }
00431   
00432   if (p->def_timeout) {
00433     
00434     printf(" %-20s = Do timeout if %d restart within %d cycles\n",
00435        "Timeout", p->to_start, p->to_cycle);
00436     
00437   } else {
00438     
00439     printf(" %-20s = (not defined)\n", "Timeout");
00440     
00441   }
00442 
00443   for (r= p->maillist; r; r= r->next) {
00444     
00445     printf(" %-20s = %s\n", "Alert mail to", is_str_defined(r->to));
00446     printf("   %-18s = %s\n", "alert from", is_str_defined_default(r->from));
00447     printf("   %-18s = %s\n", "alert subject",
00448        is_str_defined_default(r->subject));
00449     printf("   %-18s = %-.20s%s\n", "alert message",
00450        is_str_defined_default(r->message),
00451        r->message?"..":"");
00452     printf("   %-18s = %s\n", "alert on timeout",
00453        r->alert_on_timeout?"yes":"no");
00454     printf("   %-18s = %s\n", "alert on restart",
00455          r->alert_on_restart?"yes":"no");
00456     printf("   %-18s = %s\n", "alert on checksum",
00457        r->alert_on_checksum?"yes":"no");
00458     printf("   %-18s = %s\n", "alert on resource",
00459        r->alert_on_resource?"yes":"no");
00460     printf("   %-18s = %s\n", "alert on stop",
00461        r->alert_on_stop?"yes":"no");
00462 
00463   }
00464 
00465   if ( ! p->resourcelist ) {
00466 
00467     printf(" %-20s = (not defined)\n", "Resource Limits");
00468 
00469   } 
00470     
00471   for (q= p->resourcelist; q; q= q->next) {
00472 
00473     switch (q->resource_id) {
00474 
00475     case RESOURCE_ID_CPU_PERCENT: 
00476 
00477       printf(" %-20s = if %s %.1f%% for %d cycle(s) then %s\n", 
00478          "CPU usage limit", 
00479          operatornames[q->operator], 
00480          q->limit/10.0, q->max_cycle, actionnames[q->action]);
00481       break;
00482 
00483     case RESOURCE_ID_MEM_PERCENT: 
00484 
00485       printf(" %-20s = if %s %.1f%% for %d cycle(s) then %s\n", 
00486          "Memory usage limit", 
00487          operatornames[q->operator], q->limit/10.0, q->max_cycle, 
00488          actionnames[q->action]);
00489       break;
00490 
00491     case RESOURCE_ID_MEM_KBYTE: 
00492 
00493       printf(" %-20s = if %s %ldkB for %d cycle(s) then %s\n", 
00494          "Memory amount limit", 
00495          operatornames[q->operator], q->limit, q->max_cycle, 
00496          actionnames[q->action]);
00497       break;
00498 
00499     case RESOURCE_ID_LOAD1: 
00500 
00501       printf(" %-20s = if %s %.1f for %d cycle(s) then %s\n", 
00502          "Load avg. (1min)", 
00503          operatornames[q->operator], q->limit/10.0, q->max_cycle, 
00504          actionnames[q->action]);
00505       break;
00506 
00507     case RESOURCE_ID_LOAD5: 
00508 
00509       printf(" %-20s = if %s %.1f for %d cycle(s) then %s\n", 
00510          "Load avg. (5min)", 
00511          operatornames[q->operator], q->limit/10.0, q->max_cycle, 
00512          actionnames[q->action]);
00513       break;
00514 
00515     case RESOURCE_ID_LOAD15: 
00516 
00517       printf(" %-20s = if %s %.1f for %d cycle(s) then %s\n", 
00518          "Load avg. (15min)", 
00519          operatornames[q->operator], q->limit/10.0, q->max_cycle, 
00520          actionnames[q->action]);
00521       break;
00522 
00523     }    
00524   }
00525 
00526   if (p->def_every)
00527       
00528     printf(" %-20s = Check process every %d cycles\n", "Every", p->every);
00529   
00530   else {
00531     
00532     printf(" %-20s = (not defined)\n", "Every");
00533     
00534   }
00535   
00536   printf(" %-20s = %s\n", "Autostart", p->do_validate?"yes":"no");
00537   printf("\n");
00538   
00539 }
00540 
00541 
00545 void printprocesslist() {
00546   
00547   char ruler[STRLEN];
00548   Process_T p;
00549   
00550   printf("The process list contains the following entries:\n\n");
00551   
00552   for (p= processlist; p; p= p->next) {
00553     
00554     printprocess(p);
00555     
00556   }
00557 
00558   memset(ruler, '-', STRLEN);
00559   printf("%-.79s\n", ruler);
00560   
00561 }
00562 
00563 
00570 pid_t get_pid(char *pidfile) {
00571   
00572   FILE *file= NULL;
00573   int pid= -1;
00574 
00575   if (! exist_file(pidfile)) {
00576     
00577     return(FALSE);
00578     
00579   }
00580 
00581   if (! isreg_file(pidfile)) {
00582     
00583     log("%s: pidfile '%s' is not a regular file\n",prog, pidfile);
00584     return(FALSE);
00585     
00586   }
00587   
00588   if ((file= fopen(pidfile,"r")) == (FILE *)NULL) {
00589     
00590     log("%s: Error opening the pidfile '%s' -- %s\n",
00591     prog, pidfile, STRERROR);
00592     return(FALSE);
00593     
00594   }
00595 
00596   fscanf(file, "%d", &pid);
00597   fclose(file);
00598 
00599   if (pid == -1) {
00600     
00601     log("%s: pidfile `%s' does not contain a valid pidnumber\n",
00602     prog, pidfile);
00603     
00604     return (FALSE);
00605     
00606   }
00607 
00608   return (pid_t)pid;
00609   
00610 }
00611 
00612 
00617 int is_process_running(Process_T p) {
00618   
00619   pid_t  pid;
00620   
00621   errno= 0;
00622 
00623   if ((pid= get_pid(p->pidfile))) {
00624     
00625     if(kill(pid, 0) == 0 || errno == EPERM)
00626     
00627     return pid;
00628     
00629   }
00630 
00631   return FALSE;
00632   
00633 }
00634 
00635 
00642 char *get_RFC1123date(long *date) {
00643 
00644   struct tm *tm_now;
00645   char D[STRLEN];
00646   time_t now= (date && (*date>0))?*date:time(&now);
00647   long timezone_h;
00648   long timezone_m;
00649   int datelen;
00650 
00651   time(&now);
00652   tzset();
00653   tm_now = localtime(&now);
00654 
00655 #if HAVE_STRUCT_TM_TM_GMTOFF
00656   timezone_h = tm_now->tm_gmtoff/3600;
00657   timezone_m = abs(tm_now->tm_gmtoff/60)%60;
00658 #else
00659   timezone_h = -(timezone/3600)+daylight;
00660   timezone_m = abs(timezone/60)%60;
00661 #endif
00662 
00663   datelen=strftime(D, STRLEN-7, "%a, %d %b %Y %H:%M:%S", tm_now);
00664 
00665   if ( ! datelen ) {
00666 
00667     memset(D, 0, STRLEN);
00668                
00669   } else {
00670    
00671     snprintf(D+datelen, 7, " %+03ld%02ld", timezone_h, timezone_m);
00672 
00673   }
00674 
00675   return xstrdup(D);
00676 }
00677 
00678 
00683 char *get_ctime() {
00684   
00685   time_t now;
00686   char *buf = (char*)xmalloc(STRLEN);
00687   
00688   time(&now);
00689   snprintf(buf, STRLEN, "%s", ctime(&now));
00690 
00691   chomp(buf);
00692   
00693   return buf;
00694     
00695 }
00696 
00703 char *get_process_uptime(char *pidfile) {
00704 
00705   time_t ctime= (pidfile?file_changedtime(pidfile):0);
00706   if(ctime) {
00707     
00708     time_t now= time(&now);
00709     time_t since= now-ctime;
00710 
00711     return get_uptime(since);
00712     
00713   }
00714 
00715   return xstrdup("");
00716   
00717 }
00718 
00719   
00726 char *get_uptime(time_t delta) {
00727 
00728   static int min= 60;
00729   static int hour= 3600;
00730   static int day= 86400;
00731   long rest_d;
00732   long rest_h;
00733   long rest_m;
00734   char buf[STRLEN];
00735   char *p= buf;
00736 
00737   *buf= 0;
00738   
00739   if((rest_d= delta/day)>0) {
00740     p+= sprintf(p, "%ldd ", rest_d);
00741     delta-= rest_d*day;
00742   }
00743   if((rest_h= delta/hour)>0 || ( rest_d > 0 )) {
00744     p+= sprintf(p, "%ldh ", rest_h);
00745     delta-= rest_h*hour;
00746   }
00747   
00748   rest_m= delta/min;
00749   p+= sprintf(p, "%ldm ", rest_m);
00750   delta-= rest_m*min;
00751 
00752   return xstrdup(buf);
00753 
00754 }
00755 
00756 
00765 int set_md5sum(char **dest, char *file) {
00766 
00767   if (! (*dest= get_md5sum(file))) {
00768     
00769     return FALSE;
00770     
00771   }
00772   
00773   return TRUE;
00774 
00775 }
00776     
00777 
00781 char *get_md5sum(char *file) {
00782 
00783   if (isreg_file(file)) {
00784     
00785     FILE *f= fopen(file, "r");
00786     
00787     if (f) {
00788       
00789       int i;
00790       unsigned char md5buf[16];
00791       char result[STRLEN];
00792       char *r= result;
00793       
00794       if (md5_stream(f, md5buf)) {
00795     
00796     fclose(f);
00797     
00798     return NULL;
00799     
00800       }
00801       
00802       fclose(f);
00803       
00804       for (i= 0; i < 16; ++i) {
00805     
00806     r+= sprintf(r, "%02x", md5buf[i]);
00807     
00808       }
00809     
00810       return (xstrdup(result));
00811       
00812     }
00813     
00814   }
00815   
00816   return NULL;
00817 
00818 }
00819 
00820 
00828 int check_md5(char *file, char *sum) {
00829 
00830   char *newSum= get_md5sum(file);
00831   if (newSum) {
00832     
00833     int rv;
00834     
00835     rv= (!strncmp(sum, newSum, 31));
00836     free(newSum);
00837     
00838     return (rv);
00839     
00840   }
00841 
00842   return FALSE;
00843   
00844 }
00845 
00846 
00853 char *url_encode(char *uri) {
00854 
00855   static unsigned char hexchars[]= "0123456789ABCDEF";
00856   register int x, y;
00857   unsigned char *str;
00858 
00859   str= (unsigned char *)xmalloc(3 * strlen(uri) + 1);
00860 
00861   for (x = 0, y = 0; uri[x]; x++, y++) {
00862 
00863     if (is_unsafe(&uri[x])) {
00864       str[y++] = '%';
00865       str[y++] = hexchars[(unsigned char) uri[x] >> 4];
00866       str[y] = hexchars[(unsigned char) uri[x] & 0xf];
00867     } else str[y]= (unsigned char)uri[x];
00868 
00869   }
00870 
00871   str[y] = '\0';
00872 
00873   return ((char *) str);
00874 
00875 }
00876 
00877 
00883 char *get_basic_authentication_header() {
00884 
00885   if (Run.Auth.defined) {
00886     
00887     char *b64;
00888     char buf[STRLEN];
00889     char *auth= xmalloc(STRLEN+1);
00890     
00891     snprintf(buf, STRLEN, "%s:%s", Run.Auth.uname, Run.Auth.passwd);
00892     encode_base64(&b64, strlen(buf), buf);
00893     snprintf(auth, STRLEN, "Authorization: Basic %s\r\n", b64);
00894     free(b64);
00895     
00896     return auth;
00897 
00898   }
00899       
00900   return xstrdup("\r\n");
00901 
00902 }
00903 
00904 
00911 char *format(const char *s, va_list ap) {
00912 
00913   int n;
00914   int size= STRLEN;
00915   char *buf= xmalloc(size);
00916     
00917   while(TRUE) {
00918       
00919     n= vsnprintf(buf, size, s, ap);
00920     
00921     if(n > -1 && n < size)
00922         break;
00923     
00924     if(n > -1)
00925         size= n+1;
00926     else
00927         size*= 2;
00928     
00929     buf= xresize(buf, size);
00930     
00931   }
00932   
00933   return buf;
00934 
00935 }
00936 
00937 
00938 /* ----------------------------------------------------------------- Private */
00939 
00940 
00945 static char *is_str_defined(char *var) {
00946   
00947   return (is_strdefined(var)?var:"(not defined)");
00948   
00949 }
00950 
00951 
00956 static char *is_str_defined_default(char *var) {
00957 
00958   return (is_strdefined(var)?var:"(default)");
00959 
00960 }
00961 
00962 
00968 static int is_unsafe(unsigned char *c) {
00969 
00970   int i;
00971   static unsigned char unsafe[]= "<>\"#{}|\\^~[]`";
00972   
00973   if(33>*c || *c>176)
00974       return TRUE;
00975   
00976   if(*c=='%') {
00977     if( isxdigit(*(c + 1)) && isxdigit(*(c + 2)) ) return FALSE;
00978     return TRUE;
00979   }
00980 
00981   for(i=0; unsafe[i]; i++)
00982     if(*c==unsafe[i]) return TRUE;
00983 
00984   return FALSE;
00985 
00986 }
00987