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 #include <fcntl.h>
00031
00032 #ifdef HAVE_UNISTD_H
00033 #include <unistd.h>
00034 #endif
00035
00036 #ifdef HAVE_STRING_H
00037 #include <string.h>
00038 #endif
00039
00040 #ifdef HAVE_STRINGS_H
00041 #include <strings.h>
00042 #endif
00043
00044 #ifdef HAVE_SYS_TYPES_H
00045 #include <sys/types.h>
00046 #endif
00047
00048 #ifdef HAVE_SYS_STAT_H
00049 #include <sys/stat.h>
00050 #endif
00051
00052 #include "monitor.h"
00053 #include "engine.h"
00054 #include "md5.h"
00055 #include "base64.h"
00056 #include "alert.h"
00057 #include "monit_process.h"
00058
00059
00060 static int is_unsafe(unsigned char *c);
00061 static char *is_str_defined(char *);
00062 static char *is_str_defined_default(char *);
00063
00078
00079
00080
00086 void error(const char *format, ...) {
00087
00088 char msg[1024];
00089 va_list ap;
00090
00091 ASSERT(format);
00092
00093 va_start(ap,format);
00094 vsnprintf(msg, 1024, format, ap);
00095 va_end(ap);
00096
00097 if(Run.have_tty) {
00098
00099 fprintf(stderr,"%s", msg);
00100 fflush(stderr);
00101
00102 } else {
00103
00104 log("%s", msg);
00105
00106 }
00107
00108 }
00109
00110
00114 int is_strdefined(char *p) {
00115
00116 return(p && *p);
00117
00118 }
00119
00120
00126 char *stripfilename(char* path) {
00127
00128 char *fname;
00129
00130 ASSERT(path);
00131
00132 fname= strrchr(path, '/');
00133
00134 return(fname ? ++fname : path);
00135
00136 }
00137
00138
00143 void chomp(char *string) {
00144
00145 char *p;
00146
00147 ASSERT(string);
00148
00149 if((p= strchr(string, '\r')) || (p= strchr(string, '\n'))) *p= 0;
00150
00151 }
00152
00153
00159 char *trim(char *s) {
00160
00161 ASSERT(s);
00162
00163 ltrim(s);
00164 rtrim(s);
00165
00166 return s;
00167
00168 }
00169
00170
00176 char *ltrim(char *s) {
00177
00178 char *t= s;
00179
00180 ASSERT(s);
00181
00182 while(*t==' ' || *t=='\t' || *t=='\r' || *t=='\n') t++;
00183
00184 return strcpy(s, t);
00185
00186 }
00187
00188
00194 char *rtrim(char *s) {
00195
00196 char *t= s;
00197
00198 ASSERT(s);
00199
00200 while(*s) s++;
00201 while(*--s==' ' || *s=='\t' || *s=='\r' || *s=='\n') *s= '\0';
00202
00203 return t;
00204
00205 }
00206
00207
00214 char *trim_quotes(char *s) {
00215
00216 char *t= s;
00217 char tmp=0;
00218
00219 ASSERT(s);
00220
00221 while(*t==39 || *t==34) {
00222
00223 tmp=*t;
00224 t++;
00225 break;
00226
00227 }
00228
00229 if(t[strlen(t)-1]==tmp) t[strlen(t)-1]= '\0';
00230
00231 return strcpy(s, t);
00232
00233 }
00234
00235
00242 int starts_with(char *a, char *b) {
00243
00244 if((!a || !b) || *a!=*b) return FALSE;
00245
00246 while(*a && *b) {
00247
00248 if(*a++ != *b++) return FALSE;
00249
00250 }
00251
00252 return TRUE;
00253
00254 }
00255
00256
00262 void handle_string_escapes(char *buf) {
00263
00264 int editpos;
00265 int insertpos;
00266
00267 ASSERT(buf);
00268
00269 for(editpos=insertpos=0; *(buf+editpos)!='\0'; editpos++, insertpos++) {
00270
00271 if(*(buf+editpos) == '\\' ) {
00272
00273 switch(*(buf+editpos+1)) {
00274
00275 case 'n':
00276 *(buf+insertpos)='\n';
00277 editpos++;
00278 break;
00279
00280 case 't':
00281 *(buf+insertpos)='\t';
00282 editpos++;
00283 break;
00284
00285 case 'r':
00286 *(buf+insertpos)='\r';
00287 editpos++;
00288 break;
00289
00290 case ' ':
00291 *(buf+insertpos)=' ';
00292 editpos++;
00293 break;
00294
00295 case '\\':
00296 *(buf+insertpos)='\\';
00297 editpos++;
00298 break;
00299
00300 default:
00301 *(buf+insertpos)=*(buf+editpos);
00302
00303 }
00304
00305 } else {
00306
00307 *(buf+insertpos)=*(buf+editpos);
00308
00309 }
00310
00311 }
00312 *(buf+insertpos)='\0';
00313
00314 }
00315
00316
00321 Process_T get_process(char *name) {
00322
00323 Process_T p;
00324
00325 ASSERT(name);
00326
00327 for(p= processlist; p; p= p->next) {
00328 if(is(p->name, name)) {
00329 return p;
00330 }
00331 }
00332
00333 return NULL;
00334
00335 }
00336
00337
00343 int exist_process(char *name) {
00344
00345 Process_T p;
00346
00347 ASSERT(name);
00348
00349 for(p= processlist; p; p= p->next)
00350 if(is(p->name, name))
00351 return TRUE;
00352
00353 return FALSE;
00354
00355 }
00356
00357
00361 void printrunlist() {
00362
00363 printf("Runtime constants:\n");
00364 printf(" %-18s = %s\n", "Control file", is_str_defined(Run.controlfile));
00365 printf(" %-18s = %s\n", "Log file", is_str_defined(Run.logfile));
00366 printf(" %-18s = %s\n", "Pid file", is_str_defined(Run.pidfile));
00367 printf(" %-18s = %s\n", "Debug", Run.debug?"True":"False");
00368 printf(" %-18s = %s\n", "Log", Run.dolog?"True":"False");
00369 printf(" %-18s = %s\n", "Use syslog", Run.use_syslog?"True":"False");
00370 printf(" %-18s = %s\n", "Is Daemon", Run.isdaemon?"True":"False");
00371 printf(" %-18s = %s\n", "Use process engine", Run.doprocess?"True":"False");
00372 printf(" %-18s = %d seconds\n", "Poll time", Run.polltime);
00373 printf(" %-18s = %s\n", "Mail server", is_str_defined(Run.mailserver));
00374 printf(" %-18s = %s\n", "Mail from", is_str_defined(Run.MailFormat.from));
00375 printf(" %-18s = %s\n", "Mail subject",
00376 is_str_defined(Run.MailFormat.subject));
00377 printf(" %-18s = %-.20s%s\n", "Mail message",
00378 Run.MailFormat.message?
00379 Run.MailFormat.message:"(not defined)",
00380 Run.MailFormat.message?"..(truncated)":"");
00381
00382 printf(" %-18s = %s\n", "Start monit httpd", Run.dohttpd?"True":"False");
00383
00384
00385
00386 if(Run.dohttpd) {
00387
00388 printf(" %-18s = %s\n", "httpd bind address",
00389 Run.bind_addr?Run.bind_addr:"Any/All");
00390 printf(" %-18s = %d\n", "httpd portnumber", Run.httpdport);
00391 printf(" %-18s = %s\n", "Use ssl encryption", Run.httpdssl?"True":"False");
00392
00393 if(Run.httpdssl) {
00394
00395 printf(" %-18s = %s\n", "PEM key/cert file", Run.httpsslpem);
00396
00397 if(Run.httpsslclientpem!=NULL) {
00398 printf(" %-18s = %s\n", "Client cert file", Run.httpsslclientpem);
00399 } else {
00400 printf(" %-18s = %s\n", "Client cert file", "None");
00401 }
00402
00403 printf(" %-18s = %s\n", "Allow self certs",
00404 Run.allowselfcert?"True":"False");
00405
00406 }
00407
00408 printf(" %-18s = %s\n", "httpd auth. style",
00409 Run.Auth.defined&&has_hosts_allow()?
00410 "Basic Authentication and Host allow list":
00411 Run.Auth.defined?"Basic Authentication":
00412 has_hosts_allow()?"Host allow list":
00413 "No authentication!");
00414
00415 }
00416
00417 printf("\n");
00418
00419 }
00420
00421
00426 void printprocess(Process_T p) {
00427
00428 Port_T n;
00429 Mail_T r;
00430 Resource_T q;
00431 Checksum_T c;
00432 Timestamp_T t;
00433 Dependant_T d;
00434
00435 ASSERT(p);
00436
00437 printf("%-21s = %s\n", "Process Name", p->name);
00438 printf(" %-20s = %s\n", "Group", is_str_defined(p->group));
00439 printf(" %-20s = %s\n", "Pid file", p->pidfile);
00440 printf(" %-20s = %s\n", "Monitoring mode", modenames[p->mode]);
00441 if(p->start)
00442 printf(" %-20s = %s\n", "Start program", is_str_defined(p->start->arg[0]));
00443 if(p->stop)
00444 printf(" %-20s = %s\n", "Stop program", is_str_defined(p->stop->arg[0]));
00445
00446 for(c= p->checksumlist; c; c= c->next) {
00447
00448 printf(" %-20s = %s %s\n", "Checksum", c->md5, c->file);
00449
00450 }
00451
00452 for(d= p->dependantlist; d; d= d->next)
00453 if(d->dependant != NULL)
00454 printf(" %-20s = %s\n", "Depends on Process", d->dependant);
00455
00456 if(! p->portlist) {
00457
00458 printf(" %-20s = (not defined)\n", "Host:Port");
00459
00460 } else {
00461
00462 for(n= p->portlist; n; n= n->next) {
00463
00464 if(n->family == AF_INET) {
00465
00466 if(n->ssl != NULL) {
00467
00468 printf(" %-20s = %s:%d%s [protocol %s via SSL]\n", "Host:Port",
00469 n->hostname, n->port, n->request?n->request:"",
00470 n->protocol->name);
00471
00472 if(n->certmd5 != NULL) {
00473
00474 printf(" %-20s = %s\n",
00475 "Server cert md5 sum",
00476 n->certmd5);
00477
00478 }
00479
00480 } else {
00481
00482 printf(" %-20s = %s:%d%s [protocol %s]\n", "Host:Port",
00483 n->hostname, n->port, n->request?n->request:"",
00484 n->protocol->name);
00485
00486 }
00487
00488 } else if(n->family == AF_UNIX) {
00489
00490 printf(" %-20s = %s [protocol %s]\n", "Unix Socket",
00491 n->pathname, n->protocol->name);
00492
00493 }
00494
00495 }
00496
00497 }
00498
00499 for(t= p->timestamplist; t; t= t->next) {
00500
00501 printf(" %-20s = if %s %s %d second(s) then %s\n",
00502 "Timestamp",
00503 t->pathname,
00504 operatornames[t->operator],
00505 t->time,
00506 actionnames[t->action]);
00507
00508 }
00509
00510 if(! p->resourcelist) {
00511
00512 printf(" %-20s = (not defined)\n", "Resource Limits");
00513
00514 }
00515
00516 for(q= p->resourcelist; q; q= q->next) {
00517
00518 switch(q->resource_id) {
00519
00520 case RESOURCE_ID_CPU_PERCENT:
00521
00522 printf(" %-20s = if %s %.1f%% for %d cycle(s) then %s\n",
00523 "CPU usage limit",
00524 operatornames[q->operator],
00525 q->limit/10.0, q->max_cycle, actionnames[q->action]);
00526 break;
00527
00528 case RESOURCE_ID_MEM_PERCENT:
00529
00530 printf(" %-20s = if %s %.1f%% for %d cycle(s) then %s\n",
00531 "Memory usage limit",
00532 operatornames[q->operator], q->limit/10.0, q->max_cycle,
00533 actionnames[q->action]);
00534 break;
00535
00536 case RESOURCE_ID_MEM_KBYTE:
00537
00538 printf(" %-20s = if %s %ldkB for %d cycle(s) then %s\n",
00539 "Memory amount limit",
00540 operatornames[q->operator], q->limit, q->max_cycle,
00541 actionnames[q->action]);
00542 break;
00543
00544 case RESOURCE_ID_LOAD1:
00545
00546 printf(" %-20s = if %s %.1f for %d cycle(s) then %s\n",
00547 "Load avg. (1min)",
00548 operatornames[q->operator], q->limit/10.0, q->max_cycle,
00549 actionnames[q->action]);
00550 break;
00551
00552 case RESOURCE_ID_LOAD5:
00553
00554 printf(" %-20s = if %s %.1f for %d cycle(s) then %s\n",
00555 "Load avg. (5min)",
00556 operatornames[q->operator], q->limit/10.0, q->max_cycle,
00557 actionnames[q->action]);
00558 break;
00559
00560 case RESOURCE_ID_LOAD15:
00561
00562 printf(" %-20s = if %s %.1f for %d cycle(s) then %s\n",
00563 "Load avg. (15min)",
00564 operatornames[q->operator], q->limit/10.0, q->max_cycle,
00565 actionnames[q->action]);
00566 break;
00567
00568 }
00569 }
00570
00571 if(p->def_every)
00572
00573 printf(" %-20s = Check process every %d cycles\n", "Every", p->every);
00574
00575 else {
00576
00577 printf(" %-20s = (not defined)\n", "Every");
00578
00579 }
00580
00581 if(p->def_timeout) {
00582
00583 printf(" %-20s = Do timeout if %d restart within %d cycles\n",
00584 "Timeout", p->to_start, p->to_cycle);
00585
00586 } else {
00587
00588 printf(" %-20s = (not defined)\n", "Timeout");
00589
00590 }
00591
00592 for(r= p->maillist; r; r= r->next) {
00593
00594 printf(" %-20s = %s\n", "Alert mail to", is_str_defined(r->to));
00595 printf(" %-18s = %s\n", "alert from", is_str_defined_default(r->from));
00596 printf(" %-18s = %s\n", "alert subject",
00597 is_str_defined_default(r->subject));
00598 printf(" %-18s = %-.20s%s\n", "alert message",
00599 is_str_defined_default(r->message),
00600 r->message?"..":"");
00601 printf(" %-18s = %s\n", "alert on timeout",
00602 r->alert_on_timeout?"yes":"no");
00603 printf(" %-18s = %s\n", "alert on restart",
00604 r->alert_on_restart?"yes":"no");
00605 printf(" %-18s = %s\n", "alert on checksum",
00606 r->alert_on_checksum?"yes":"no");
00607 printf(" %-18s = %s\n", "alert on resource",
00608 r->alert_on_resource?"yes":"no");
00609 printf(" %-18s = %s\n", "alert on stop",
00610 r->alert_on_stop?"yes":"no");
00611 printf(" %-18s = %s\n", "alert on timestamp",
00612 r->alert_on_timestamp?"yes":"no");
00613
00614 }
00615
00616 printf("\n");
00617
00618 }
00619
00620
00624 void printprocesslist() {
00625
00626 Process_T p;
00627 char ruler[STRLEN];
00628
00629 printf("The process list contains the following entries:\n\n");
00630
00631 for(p= processlist; p; p= p->next) {
00632
00633 printprocess(p);
00634
00635 }
00636
00637 memset(ruler, '-', STRLEN);
00638 printf("%-.79s\n", ruler);
00639
00640 }
00641
00642
00649 pid_t get_pid(char *pidfile) {
00650
00651 FILE *file= NULL;
00652 int pid= -1;
00653
00654 ASSERT(pidfile);
00655
00656 if(! exist_file(pidfile)) {
00657
00658 return(FALSE);
00659
00660 }
00661
00662 if(! isreg_file(pidfile)) {
00663
00664 log("%s: pidfile '%s' is not a regular file\n",prog, pidfile);
00665 return(FALSE);
00666
00667 }
00668
00669 if((file= fopen(pidfile,"r")) == (FILE *)NULL) {
00670
00671 log("%s: Error opening the pidfile '%s' -- %s\n",
00672 prog, pidfile, STRERROR);
00673 return(FALSE);
00674
00675 }
00676
00677 fscanf(file, "%d", &pid);
00678 fclose(file);
00679
00680 if(pid == -1) {
00681
00682 log("%s: pidfile `%s' does not contain a valid pidnumber\n",
00683 prog, pidfile);
00684
00685 return (FALSE);
00686
00687 }
00688
00689 return (pid_t)pid;
00690
00691 }
00692
00693
00698 int is_process_running(Process_T p) {
00699
00700 pid_t pid;
00701 int kill_return= 0;
00702
00703 ASSERT(p);
00704
00705 errno= 0;
00706
00707 if((pid= get_pid(p->pidfile))) {
00708
00709 if((kill_return= getpgid(pid)) > 0 || errno == EPERM)
00710
00711 return pid;
00712
00713 }
00714
00715 return FALSE;
00716
00717 }
00718
00719
00726 char *get_RFC1123date(long *date) {
00727
00728 struct tm *tm_now;
00729 char D[STRLEN];
00730 time_t now= (date && (*date>0))?*date:time(&now);
00731 long timezone_h;
00732 long timezone_m;
00733 int datelen;
00734
00735 time(&now);
00736 tzset();
00737 tm_now = localtime(&now);
00738
00739 #if HAVE_STRUCT_TM_TM_GMTOFF
00740 timezone_h = tm_now->tm_gmtoff/3600;
00741 timezone_m = abs(tm_now->tm_gmtoff/60)%60;
00742 #else
00743 timezone_h = -(timezone/3600)+daylight;
00744 timezone_m = abs(timezone/60)%60;
00745 #endif
00746
00747 datelen=strftime(D, STRLEN-7, "%a, %d %b %Y %H:%M:%S", tm_now);
00748
00749 if(! datelen) {
00750
00751 memset(D, 0, STRLEN);
00752
00753 } else {
00754
00755 snprintf(D+datelen, 7, " %+03ld%02ld", timezone_h, timezone_m);
00756
00757 }
00758
00759 return xstrdup(D);
00760
00761 }
00762
00763
00768 char *get_ctime() {
00769
00770 time_t now;
00771 char *buf = (char*)xmalloc(STRLEN);
00772
00773 time(&now);
00774 snprintf(buf, STRLEN, "%s", ctime(&now));
00775
00776 chomp(buf);
00777
00778 return buf;
00779
00780 }
00781
00788 char *get_process_uptime(char *pidfile) {
00789
00790 time_t ctime;
00791
00792 ASSERT(pidfile);
00793
00794 if( (ctime= get_timestamp(pidfile, S_IFREG)) ) {
00795
00796 time_t now= time(&now);
00797 time_t since= now-ctime;
00798
00799 return get_uptime(since);
00800
00801 }
00802
00803 return xstrdup("");
00804
00805 }
00806
00807
00814 char *get_uptime(time_t delta) {
00815
00816 static int min= 60;
00817 static int hour= 3600;
00818 static int day= 86400;
00819 long rest_d;
00820 long rest_h;
00821 long rest_m;
00822 char buf[STRLEN];
00823 char *p= buf;
00824
00825 *buf= 0;
00826
00827 if((rest_d= delta/day)>0) {
00828 p+= sprintf(p, "%ldd ", rest_d);
00829 delta-= rest_d*day;
00830 }
00831 if((rest_h= delta/hour)>0 || (rest_d > 0)) {
00832 p+= sprintf(p, "%ldh ", rest_h);
00833 delta-= rest_h*hour;
00834 }
00835
00836 rest_m= delta/min;
00837 p+= sprintf(p, "%ldm ", rest_m);
00838 delta-= rest_m*min;
00839
00840 return xstrdup(buf);
00841
00842 }
00843
00844
00853 int set_md5sum(char **dest, char *file) {
00854
00855 ASSERT(dest);
00856 ASSERT(file);
00857
00858 if(! (*dest= get_md5sum(file)))
00859 return FALSE;
00860
00861 return TRUE;
00862
00863 }
00864
00865
00869 char *get_md5sum(char *file) {
00870
00871 ASSERT(file);
00872
00873 if(isreg_file(file)) {
00874
00875 FILE *f= fopen(file, "r");
00876
00877 if(f) {
00878
00879 int i;
00880 unsigned char md5buf[16];
00881 char result[STRLEN];
00882 char *r= result;
00883
00884 if(md5_stream(f, md5buf)) {
00885
00886 fclose(f);
00887
00888 return NULL;
00889
00890 }
00891
00892 fclose(f);
00893
00894 for(i= 0; i < 16; ++i) {
00895
00896 r+= sprintf(r, "%02x", md5buf[i]);
00897
00898 }
00899
00900 return (xstrdup(result));
00901
00902 }
00903
00904 }
00905
00906 return NULL;
00907
00908 }
00909
00910
00918 int check_md5(char *file, char *sum) {
00919
00920 char *newSum;
00921
00922 ASSERT(file);
00923 ASSERT(sum);
00924
00925 newSum= get_md5sum(file);
00926
00927 if(newSum) {
00928
00929 int rv;
00930
00931 rv= (!strncmp(sum, newSum, 31));
00932 free(newSum);
00933
00934 return (rv);
00935
00936 }
00937
00938 return FALSE;
00939
00940 }
00941
00942
00949 char *url_encode(char *uri) {
00950
00951 static unsigned char hexchars[]= "0123456789ABCDEF";
00952 register int x, y;
00953 unsigned char *str;
00954
00955 ASSERT(uri);
00956
00957 str= (unsigned char *)xmalloc(3 * strlen(uri) + 1);
00958
00959 for(x = 0, y = 0; uri[x]; x++, y++) {
00960
00961 if(is_unsafe(&uri[x])) {
00962 str[y++] = '%';
00963 str[y++] = hexchars[(unsigned char) uri[x] >> 4];
00964 str[y] = hexchars[(unsigned char) uri[x] & 0xf];
00965 } else str[y]= (unsigned char)uri[x];
00966
00967 }
00968
00969 str[y] = '\0';
00970
00971 return ((char *) str);
00972
00973 }
00974
00975
00981 char *get_basic_authentication_header() {
00982
00983 if(Run.Auth.defined) {
00984
00985 char *b64;
00986 char buf[STRLEN];
00987 char *auth= xmalloc(STRLEN+1);
00988
00989 snprintf(buf, STRLEN, "%s:%s", Run.Auth.uname, Run.Auth.passwd);
00990 encode_base64(&b64, strlen(buf), buf);
00991 snprintf(auth, STRLEN, "Authorization: Basic %s\r\n", b64);
00992 free(b64);
00993
00994 return auth;
00995
00996 }
00997
00998 return xstrdup("\r\n");
00999
01000 }
01001
01002
01009 char *format(const char *s, va_list ap) {
01010
01011 int n;
01012 int size= STRLEN;
01013 char *buf= xmalloc(size);
01014
01015 ASSERT(s);
01016
01017 while(TRUE) {
01018
01019 n= vsnprintf(buf, size, s, ap);
01020
01021 if(n > -1 && n < size)
01022 break;
01023
01024 if(n > -1)
01025 size= n+1;
01026 else
01027 size*= 2;
01028
01029 buf= xresize(buf, size);
01030
01031 }
01032
01033 return buf;
01034
01035 }
01036
01037
01042 void redirect_stdfd() {
01043
01044 int i;
01045
01046 Run.have_tty= FALSE;
01047 for(i= 0; i < 3; i++)
01048 if(close(i) == -1 || open("/dev/null", O_RDWR) != i)
01049 error("Cannot reopen standard file descriptor (%d) -- %s\n", i, STRERROR);
01050
01051 }
01052
01053
01054
01055
01056
01061 static char *is_str_defined(char *var) {
01062
01063 return (is_strdefined(var)?var:"(not defined)");
01064
01065 }
01066
01067
01072 static char *is_str_defined_default(char *var) {
01073
01074 return (is_strdefined(var)?var:"(default)");
01075
01076 }
01077
01078
01084 static int is_unsafe(unsigned char *c) {
01085
01086 int i;
01087 static unsigned char unsafe[]= "<>\"#{}|\\^~[]`";
01088
01089 ASSERT(c);
01090
01091 if(33>*c || *c>176)
01092 return TRUE;
01093
01094 if(*c=='%') {
01095 if( isxdigit(*(c + 1)) && isxdigit(*(c + 2)) ) return FALSE;
01096 return TRUE;
01097 }
01098
01099 for(i=0; unsafe[i]; i++)
01100 if(*c==unsafe[i]) return TRUE;
01101
01102 return FALSE;
01103
01104 }
01105