00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
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
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
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
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