| /* |
| * Copyright (C) Tildeslash Ltd. All rights reserved. |
| * |
| * This program is free software: you can redistribute it and/or modify |
| * it under the terms of the GNU Affero General Public License version 3. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| * |
| * You should have received a copy of the GNU Affero General Public License |
| * along with this program. If not, see <http://www.gnu.org/licenses/>. |
| * |
| * In addition, as a special exception, the copyright holders give |
| * permission to link the code of portions of this program with the |
| * OpenSSL library under certain conditions as described in each |
| * individual source file, and distribute linked combinations |
| * including the two. |
| * |
| * You must obey the GNU Affero General Public License in all respects |
| * for all of the code used other than OpenSSL. |
| */ |
| |
| |
| %{ |
| |
| /* |
| * DESCRIPTION |
| * Simple context-free grammar for parsing the control file. |
| * |
| */ |
| |
| #include "config.h" |
| |
| #ifdef HAVE_STDIO_H |
| #include <stdio.h> |
| #endif |
| |
| #ifdef HAVE_STDLIB_H |
| #include <stdlib.h> |
| #endif |
| |
| #ifdef HAVE_ERRNO_H |
| #include <errno.h> |
| #endif |
| |
| #ifdef HAVE_CTYPE_H |
| #include <ctype.h> |
| #endif |
| |
| #ifdef HAVE_PWD_H |
| #include <pwd.h> |
| #endif |
| |
| #ifdef HAVE_GRP_H |
| #include <grp.h> |
| #endif |
| |
| #ifdef HAVE_SYS_TYPES_H |
| #include <sys/types.h> |
| #endif |
| |
| #ifdef HAVE_SYS_TIME_H |
| #include <sys/time.h> |
| #endif |
| |
| #ifdef HAVE_TIME_H |
| #include <time.h> |
| #endif |
| |
| #ifdef HAVE_SYS_SOCKET_H |
| #include <sys/socket.h> |
| #endif |
| |
| #ifdef HAVE_ASM_PARAM_H |
| #include <asm/param.h> |
| #endif |
| |
| #ifdef HAVE_STRING_H |
| #include <string.h> |
| #endif |
| |
| #ifdef HAVE_STRINGS_H |
| #include <strings.h> |
| #endif |
| |
| #ifdef HAVE_NETDB_H |
| #include <netdb.h> |
| #endif |
| |
| #ifdef HAVE_SYSLOG_H |
| #include <syslog.h> |
| #endif |
| |
| #ifndef HAVE_SOL_IP |
| #include <netinet/in_systm.h> |
| #include <netinet/in.h> |
| #include <netinet/ip.h> |
| #endif |
| |
| #ifdef HAVE_NETINET_IP_ICMP_H |
| #include <netinet/ip_icmp.h> |
| #endif |
| |
| #ifdef HAVE_REGEX_H |
| #include <regex.h> |
| #endif |
| |
| #include "net.h" |
| #include "monit.h" |
| #include "protocol.h" |
| #include "engine.h" |
| #include "alert.h" |
| #include "process.h" |
| #include "ssl.h" |
| #include "device.h" |
| |
| // libmonit |
| #include "io/File.h" |
| |
| |
| /* ------------------------------------------------------------- Definitions */ |
| |
| struct IHavePrecedence { |
| int daemon; |
| int logfile; |
| int pidfile; |
| }; |
| |
| struct myrate { |
| unsigned count; |
| unsigned cycles; |
| }; |
| |
| /* yacc interface */ |
| void yyerror(const char *,...); |
| void yyerror2(const char *,...); |
| void yywarning(const char *,...); |
| void yywarning2(const char *,...); |
| |
| /* lexer interface */ |
| int yylex(void); |
| extern FILE *yyin; |
| extern int lineno; |
| extern int arglineno; |
| extern char *yytext; |
| extern char *argyytext; |
| extern char *currentfile; |
| extern char *argcurrentfile; |
| extern int buffer_stack_ptr; |
| |
| /* Local variables */ |
| static int cfg_errflag = FALSE; |
| static Service_T tail = NULL; |
| static Service_T current = NULL; |
| static Request_T urlrequest = NULL; |
| static command_t command = NULL; |
| static command_t command1 = NULL; |
| static command_t command2 = NULL; |
| static Service_T depend_list = NULL; |
| static struct mygid gidset; |
| static struct myuid uidset; |
| static struct myprogram programset; |
| static struct myperm permset; |
| static struct mysize sizeset; |
| static struct myuptime uptimeset; |
| static struct mymatch matchset; |
| static struct myicmp icmpset; |
| static struct mymail mailset; |
| static struct myport portset; |
| static struct mymailserver mailserverset; |
| static struct myfilesystem filesystemset; |
| static struct myresource resourceset; |
| static struct mychecksum checksumset; |
| static struct mytimestamp timestampset; |
| static struct myactionrate actionrateset; |
| static struct IHavePrecedence ihp = {FALSE, FALSE, FALSE}; |
| static struct myrate rate1 = {1, 1}; |
| static struct myrate rate2 = {1, 1}; |
| static char * htpasswd_file = NULL; |
| static int digesttype = DIGEST_CLEARTEXT; |
| static int hassystem = FALSE; |
| |
| #define BITMAP_MAX (sizeof(long long) * 8) |
| |
| |
| /* -------------------------------------------------------------- Prototypes */ |
| |
| static void preparse(); |
| static void postparse(); |
| static void addservice(Service_T); |
| static void addmail(char *, Mail_T, Mail_T *); |
| static void createservice(int, char *, char *, int (*)(Service_T)); |
| static void adddependant(char *); |
| static void addservicegroup(char *); |
| static void addport(Port_T); |
| static void addresource(Resource_T); |
| static void addtimestamp(Timestamp_T, int); |
| static void addactionrate(ActionRate_T); |
| static void addsize(Size_T); |
| static void adduptime(Uptime_T); |
| static void addfilesystem(Filesystem_T); |
| static void addicmp(Icmp_T); |
| static void addgeneric(Port_T, char*, char*); |
| static void addcommand(int, unsigned); |
| static void addargument(char *); |
| static void addmmonit(URL_T, int, int, char *); |
| static void addmailserver(MailServer_T); |
| static int addcredentials(char *, char *, int, int); |
| #ifdef HAVE_LIBPAM |
| static void addpamauth(char *, int); |
| #endif |
| static void addhtpasswdentry(char *, char *, int); |
| static uid_t get_uid(char *, uid_t); |
| static gid_t get_gid(char *, gid_t); |
| static void addchecksum(Checksum_T); |
| static void addperm(Perm_T); |
| static void addmatch(Match_T, int, int); |
| static void addmatchpath(Match_T, int); |
| static void addprogram(Program_T); |
| static void adduid(Uid_T); |
| static void addgid(Gid_T); |
| static void addeuid(uid_t); |
| static void addegid(gid_t); |
| static void addeventaction(EventAction_T *, int, int); |
| static void seteventaction(EventAction_T *, int, int); |
| static void prepare_urlrequest(URL_T U); |
| static void seturlrequest(int, char *); |
| static void setlogfile(char *); |
| static void setpidfile(char *); |
| static void reset_mailset(); |
| static void reset_mailserverset(); |
| static void reset_portset(); |
| static void reset_resourceset(); |
| static void reset_timestampset(); |
| static void reset_actionrateset(); |
| static void reset_sizeset(); |
| static void reset_uptimeset(); |
| static void reset_checksumset(); |
| static void reset_permset(); |
| static void reset_uidset(); |
| static void reset_programset(); |
| static void reset_gidset(); |
| static void reset_filesystemset(); |
| static void reset_icmpset(); |
| static void reset_rateset(); |
| static void check_name(char *); |
| static int check_perm(int); |
| static void check_hostname (char *); |
| static void check_exec(char *); |
| static int cleanup_hash_string(char *); |
| static void check_depend(); |
| static void setsyslog(char *); |
| static command_t copycommand(command_t); |
| static int verifyMaxForward(int); |
| |
| %} |
| |
| %union { |
| URL_T url; |
| float real; |
| int number; |
| char *string; |
| } |
| |
| %token IF ELSE THEN OR FAILED |
| %token SET LOGFILE FACILITY DAEMON SYSLOG MAILSERVER HTTPD ALLOW ADDRESS INIT |
| %token READONLY CLEARTEXT MD5HASH SHA1HASH CRYPT DELAY |
| %token PEMFILE ENABLE DISABLE HTTPDSSL CLIENTPEMFILE ALLOWSELFCERTIFICATION |
| %token IDFILE STATEFILE SEND EXPECT EXPECTBUFFER CYCLE COUNT REMINDER |
| %token PIDFILE START STOP PATHTOK |
| %token HOST HOSTNAME PORT TYPE UDP TCP TCPSSL PROTOCOL CONNECTION |
| %token ALERT NOALERT MAILFORMAT UNIXSOCKET SIGNATURE |
| %token TIMEOUT RETRY RESTART CHECKSUM EVERY NOTEVERY |
| %token DEFAULT HTTP APACHESTATUS FTP SMTP POP IMAP CLAMAV NNTP NTP3 MYSQL DNS |
| %token SSH DWP LDAP2 LDAP3 RDATE RSYNC TNS PGSQL POSTFIXPOLICY SIP LMTP GPS RADIUS MEMCACHE |
| %token <string> STRING PATH MAILADDR MAILFROM MAILREPLYTO MAILSUBJECT |
| %token <string> MAILBODY SERVICENAME STRINGNAME |
| %token <number> NUMBER PERCENT LOGLIMIT CLOSELIMIT DNSLIMIT KEEPALIVELIMIT |
| %token <number> REPLYLIMIT REQUESTLIMIT STARTLIMIT WAITLIMIT GRACEFULLIMIT |
| %token <number> CLEANUPLIMIT |
| %token <real> REAL |
| %token CHECKPROC CHECKFILESYS CHECKFILE CHECKDIR CHECKHOST CHECKSYSTEM CHECKFIFO CHECKPROGRAM |
| %token CHILDREN SYSTEM STATUS |
| %token RESOURCE MEMORY TOTALMEMORY LOADAVG1 LOADAVG5 LOADAVG15 SWAP |
| %token MODE ACTIVE PASSIVE MANUAL CPU TOTALCPU CPUUSER CPUSYSTEM CPUWAIT |
| %token GROUP REQUEST DEPENDS BASEDIR SLOT EVENTQUEUE SECRET HOSTHEADER |
| %token UID GID MMONIT INSTANCE USERNAME PASSWORD |
| %token TIMESTAMP CHANGED SECOND MINUTE HOUR DAY |
| %token SSLAUTO SSLV2 SSLV3 TLSV1 CERTMD5 |
| %token BYTE KILOBYTE MEGABYTE GIGABYTE |
| %token INODE SPACE PERMISSION SIZE MATCH NOT IGNORE ACTION UPTIME |
| %token EXEC UNMONITOR ICMP ICMPECHO NONEXIST EXIST INVALID DATA RECOVERED PASSED SUCCEEDED |
| %token URL CONTENT PID PPID FSFLAG |
| %token REGISTER CREDENTIALS |
| %token <url> URLOBJECT |
| %token <string> TARGET TIMESPEC |
| %token <number> MAXFORWARD |
| %token FIPS |
| |
| %left GREATER LESS EQUAL NOTEQUAL |
| |
| |
| %% |
| cfgfile : /* EMPTY */ |
| | statement_list |
| ; |
| |
| statement_list : statement |
| | statement_list statement |
| ; |
| |
| statement : setalert |
| | setdaemon |
| | setlog |
| | seteventqueue |
| | setmmonits |
| | setmailservers |
| | setmailformat |
| | sethttpd |
| | setpid |
| | setidfile |
| | setstatefile |
| | setexpectbuffer |
| | setinit |
| | setfips |
| | checkproc optproclist |
| | checkfile optfilelist |
| | checkfilesys optfilesyslist |
| | checkdir optdirlist |
| | checkhost opthostlist |
| | checksystem optsystemlist |
| | checkfifo optfifolist |
| | checkprogram optstatuslist |
| ; |
| |
| optproclist : /* EMPTY */ |
| | optproclist optproc |
| ; |
| |
| optproc : start |
| | stop |
| | restart |
| | exist |
| | pid |
| | ppid |
| | uptime |
| | connection |
| | connectionunix |
| | actionrate |
| | alert |
| | every |
| | mode |
| | group |
| | depend |
| | resourceprocess |
| ; |
| |
| optfilelist : /* EMPTY */ |
| | optfilelist optfile |
| ; |
| |
| optfile : start |
| | stop |
| | restart |
| | exist |
| | timestamp |
| | actionrate |
| | every |
| | alert |
| | permission |
| | uid |
| | gid |
| | checksum |
| | size |
| | match |
| | mode |
| | group |
| | depend |
| ; |
| |
| optfilesyslist : /* EMPTY */ |
| | optfilesyslist optfilesys |
| ; |
| |
| optfilesys : start |
| | stop |
| | restart |
| | exist |
| | actionrate |
| | every |
| | alert |
| | permission |
| | uid |
| | gid |
| | mode |
| | group |
| | depend |
| | inode |
| | space |
| | fsflag |
| ; |
| |
| optdirlist : /* EMPTY */ |
| | optdirlist optdir |
| ; |
| |
| optdir : start |
| | stop |
| | restart |
| | exist |
| | timestamp |
| | actionrate |
| | every |
| | alert |
| | permission |
| | uid |
| | gid |
| | mode |
| | group |
| | depend |
| ; |
| |
| opthostlist : opthost |
| | opthostlist opthost |
| ; |
| |
| opthost : start |
| | stop |
| | restart |
| | exist |
| | connection |
| | icmp |
| | actionrate |
| | alert |
| | every |
| | mode |
| | group |
| | depend |
| ; |
| |
| optsystemlist : /* EMPTY */ |
| | optsystemlist optsystem |
| ; |
| |
| optsystem : start |
| | stop |
| | restart |
| | actionrate |
| | alert |
| | every |
| | group |
| | depend |
| | resourcesystem |
| ; |
| |
| optfifolist : /* EMPTY */ |
| | optfifolist optfifo |
| ; |
| |
| optfifo : start |
| | stop |
| | restart |
| | exist |
| | timestamp |
| | actionrate |
| | every |
| | alert |
| | permission |
| | uid |
| | gid |
| | mode |
| | group |
| | depend |
| ; |
| |
| optstatuslist : /* EMPTY */ |
| | optstatuslist optstatus |
| ; |
| |
| optstatus : start |
| | stop |
| | restart |
| | actionrate |
| | exist |
| | alert |
| | every |
| | group |
| | depend |
| | exitvalue |
| ; |
| |
| setalert : SET alertmail formatlist reminder { |
| mailset.events = Event_All; |
| addmail($<string>2, &mailset, &Run.maillist); |
| } |
| | SET alertmail '{' eventoptionlist '}' formatlist reminder { |
| addmail($<string>2, &mailset, &Run.maillist); |
| } |
| | SET alertmail NOT '{' eventoptionlist '}' formatlist reminder { |
| mailset.events = ~mailset.events; |
| addmail($<string>2, &mailset, &Run.maillist); |
| } |
| ; |
| |
| setdaemon : SET DAEMON NUMBER startdelay { |
| if (!Run.isdaemon || ihp.daemon) { |
| ihp.daemon = TRUE; |
| Run.isdaemon = TRUE; |
| Run.polltime = $3; |
| Run.startdelay = $<number>4; |
| } |
| } |
| ; |
| |
| startdelay : /* EMPTY */ { $<number>$ = START_DELAY; } |
| | START DELAY NUMBER { $<number>$ = $3; } |
| ; |
| |
| setexpectbuffer : SET EXPECTBUFFER NUMBER unit { |
| Run.expectbuffer = $3 * $<number>4; |
| } |
| ; |
| |
| setinit : SET INIT { |
| Run.init = TRUE; |
| } |
| ; |
| |
| setfips : SET FIPS { |
| #ifdef OPENSSL_FIPS |
| Run.fipsEnabled = TRUE; |
| #endif |
| } |
| ; |
| |
| setlog : SET LOGFILE PATH { |
| if (!Run.logfile || ihp.logfile) { |
| ihp.logfile = TRUE; |
| setlogfile($3); |
| Run.use_syslog = FALSE; |
| Run.dolog =TRUE; |
| } |
| } |
| | SET LOGFILE SYSLOG { |
| setsyslog(NULL); |
| } |
| | SET LOGFILE SYSLOG FACILITY STRING { |
| setsyslog($5); FREE($5); |
| } |
| ; |
| |
| seteventqueue : SET EVENTQUEUE BASEDIR PATH { |
| Run.eventlist_dir = $4; |
| } |
| | SET EVENTQUEUE BASEDIR PATH SLOT NUMBER { |
| Run.eventlist_dir = $4; |
| Run.eventlist_slots = $6; |
| } |
| | SET EVENTQUEUE SLOT NUMBER { |
| Run.eventlist_dir = Str_dup(MYEVENTLISTBASE); |
| Run.eventlist_slots = $4; |
| } |
| ; |
| |
| setidfile : SET IDFILE PATH { |
| Run.idfile = $3; |
| } |
| ; |
| |
| setstatefile : SET STATEFILE PATH { |
| Run.statefile = $3; |
| } |
| ; |
| |
| setpid : SET PIDFILE PATH { |
| if (!Run.pidfile || ihp.pidfile) { |
| ihp.pidfile = TRUE; |
| setpidfile($3); |
| } |
| } |
| ; |
| |
| setmmonits : SET MMONIT mmonitlist |
| ; |
| |
| mmonitlist : mmonit credentials |
| | mmonitlist mmonit credentials |
| ; |
| |
| mmonit : URLOBJECT nettimeout sslversion certmd5 { |
| check_hostname(($<url>1)->hostname); |
| addmmonit($<url>1, $<number>2, $<number>3, $<string>4); |
| } |
| ; |
| |
| credentials : /* EMPTY */ |
| | REGISTER CREDENTIALS { |
| Run.dommonitcredentials = FALSE; |
| } |
| ; |
| |
| setmailservers : SET MAILSERVER mailserverlist nettimeout hostname { |
| Run.mailserver_timeout = $<number>4; |
| Run.mail_hostname = $<string>5; |
| } |
| ; |
| |
| setmailformat : SET MAILFORMAT '{' formatoptionlist '}' { |
| Run.MailFormat.from = mailset.from ? mailset.from : Str_dup(ALERT_FROM); |
| Run.MailFormat.replyto = mailset.replyto ? mailset.replyto : NULL; |
| Run.MailFormat.subject = mailset.subject ? mailset.subject : Str_dup(ALERT_SUBJECT); |
| Run.MailFormat.message = mailset.message ? mailset.message : Str_dup(ALERT_MESSAGE); |
| reset_mailset(); |
| } |
| ; |
| |
| sethttpd : SET HTTPD PORT NUMBER httpdlist { |
| Run.dohttpd = TRUE; |
| Run.httpdport = $4; |
| } |
| ; |
| |
| mailserverlist : mailserver |
| | mailserverlist mailserver |
| ; |
| |
| mailserver : STRING username password sslversion certmd5 { |
| /* Restore the current text overriden by lookahead */ |
| FREE(argyytext); |
| argyytext = Str_dup($1); |
| |
| check_hostname($1); |
| mailserverset.host = $1; |
| mailserverset.username = $<string>2; |
| mailserverset.password = $<string>3; |
| mailserverset.ssl.version = $<number>4; |
| if (mailserverset.ssl.version != SSL_VERSION_NONE) { |
| mailserverset.ssl.use_ssl = TRUE; |
| if (mailserverset.ssl.version == SSL_VERSION_SSLV2 || |
| mailserverset.ssl.version == SSL_VERSION_SSLV3) |
| mailserverset.port = PORT_SMTPS; |
| mailserverset.ssl.certmd5 = $<string>5; |
| } |
| addmailserver(&mailserverset); |
| } |
| | STRING PORT NUMBER username password sslversion certmd5 { |
| /* Restore the current text overriden by lookahead */ |
| FREE(argyytext); |
| argyytext = Str_dup($1); |
| |
| check_hostname($1); |
| mailserverset.host = $1; |
| mailserverset.port = $<number>3; |
| mailserverset.username = $<string>4; |
| mailserverset.password = $<string>5; |
| mailserverset.ssl.version = $<number>6; |
| if (mailserverset.ssl.version != SSL_VERSION_NONE) { |
| mailserverset.ssl.use_ssl = TRUE; |
| mailserverset.ssl.certmd5 = $<string>7; |
| } |
| addmailserver(&mailserverset); |
| } |
| ; |
| |
| httpdlist : /* EMPTY */ |
| | httpdlist httpdoption |
| ; |
| |
| httpdoption : ssl |
| | signature |
| | bindaddress |
| | allow |
| ; |
| |
| ssl : ssldisable { Run.httpdssl = FALSE; } |
| | sslenable optssllist { |
| Run.httpdssl = TRUE; |
| if (! have_ssl()) |
| yyerror("SSL is not supported"); |
| else if (! Run.httpsslpem) |
| yyerror("SSL server PEM file is required (pemfile option)"); |
| else if (! file_checkStat(Run.httpsslpem, "SSL server PEM file", S_IRWXU)) |
| yyerror("SSL server PEM file permissions check failed"); |
| } |
| ; |
| |
| optssllist : /* EMPTY */ |
| | optssllist optssl |
| ; |
| |
| optssl : pemfile |
| | clientpemfile |
| | allowselfcert |
| ; |
| |
| sslenable : HTTPDSSL |
| | HTTPDSSL ENABLE |
| | ENABLE HTTPDSSL |
| ; |
| |
| ssldisable : HTTPDSSL DISABLE |
| | DISABLE HTTPDSSL |
| | ssldisable PEMFILE PATH { FREE($3); } |
| | ssldisable CLIENTPEMFILE PATH { FREE($3); } |
| | ssldisable ALLOWSELFCERTIFICATION |
| ; |
| |
| signature : sigenable { Run.httpdsig = TRUE; } |
| | sigdisable { Run.httpdsig = FALSE; } |
| ; |
| |
| sigenable : SIGNATURE ENABLE |
| | ENABLE SIGNATURE |
| ; |
| |
| sigdisable : SIGNATURE DISABLE |
| | DISABLE SIGNATURE |
| ; |
| |
| bindaddress : ADDRESS STRING { Run.bind_addr = $2; } |
| ; |
| |
| pemfile : PEMFILE PATH { |
| Run.httpsslpem = $2; |
| } |
| ; |
| |
| clientpemfile : CLIENTPEMFILE PATH { |
| Run.httpsslclientpem = $2; |
| Run.clientssl = TRUE; |
| if (!file_checkStat(Run.httpsslclientpem, "SSL client PEM file", S_IRWXU | S_IRGRP | S_IROTH)) |
| yyerror2("SSL client PEM file has too loose permissions"); |
| } |
| ; |
| |
| allowselfcert : ALLOWSELFCERTIFICATION { |
| Run.allowselfcert = TRUE; |
| } |
| ; |
| |
| allow : ALLOW STRING':'STRING readonly { |
| addcredentials($2,$4, DIGEST_CLEARTEXT, $<number>5); |
| } |
| | ALLOW '@'STRING readonly { |
| #ifdef HAVE_LIBPAM |
| addpamauth($3, $<number>4); |
| #else |
| yyerror("PAM is not supported"); |
| FREE($3); |
| #endif |
| } |
| | ALLOW PATH { |
| addhtpasswdentry($2, NULL, DIGEST_CLEARTEXT); |
| FREE($2); |
| } |
| | ALLOW CLEARTEXT PATH { |
| addhtpasswdentry($3, NULL, DIGEST_CLEARTEXT); |
| FREE($3); |
| } |
| | ALLOW MD5HASH PATH { |
| addhtpasswdentry($3, NULL, DIGEST_MD5); |
| FREE($3); |
| } |
| | ALLOW CRYPT PATH { |
| addhtpasswdentry($3, NULL, DIGEST_CRYPT); |
| FREE($3); |
| } |
| | ALLOW PATH { |
| htpasswd_file = $2; |
| digesttype = CLEARTEXT; |
| } |
| allowuserlist { |
| FREE(htpasswd_file); |
| } |
| | ALLOW CLEARTEXT PATH { |
| htpasswd_file = $3; |
| digesttype = DIGEST_CLEARTEXT; |
| } |
| allowuserlist { |
| FREE(htpasswd_file); |
| } |
| | ALLOW MD5HASH PATH { |
| htpasswd_file = $3; |
| digesttype = DIGEST_MD5; |
| } |
| allowuserlist { |
| FREE(htpasswd_file); |
| } |
| | ALLOW CRYPT PATH { |
| htpasswd_file = $3; |
| digesttype = DIGEST_CRYPT; |
| } |
| allowuserlist { |
| FREE(htpasswd_file); |
| } |
| | ALLOW STRING { |
| if (! (add_net_allow($2) || add_host_allow($2))) { |
| yyerror2("erroneous network or host identifier %s", $2); |
| } |
| FREE($2); |
| } |
| ; |
| |
| allowuserlist : allowuser |
| | allowuserlist allowuser |
| ; |
| |
| allowuser : STRING { addhtpasswdentry(htpasswd_file, $1, digesttype); |
| FREE($1); } |
| ; |
| |
| readonly : /* EMPTY */ { $<number>$ = FALSE; } |
| | READONLY { $<number>$ = TRUE; } |
| ; |
| |
| checkproc : CHECKPROC SERVICENAME PIDFILE PATH { |
| createservice(TYPE_PROCESS, $<string>2, $4, check_process); |
| } |
| | CHECKPROC SERVICENAME PATHTOK PATH { |
| createservice(TYPE_PROCESS, $<string>2, $4, check_process); |
| } |
| | CHECKPROC SERVICENAME MATCH STRING { |
| createservice(TYPE_PROCESS, $<string>2, $4, check_process); |
| matchset.ignore = FALSE; |
| matchset.match_path = NULL; |
| matchset.match_string = Str_dup($4); |
| addmatch(&matchset, ACTION_IGNORE, 0); |
| } |
| | CHECKPROC SERVICENAME MATCH PATH { |
| createservice(TYPE_PROCESS, $<string>2, $4, check_process); |
| matchset.ignore = FALSE; |
| matchset.match_path = NULL; |
| matchset.match_string = Str_dup($4); |
| addmatch(&matchset, ACTION_IGNORE, 0); |
| } |
| ; |
| |
| checkfile : CHECKFILE SERVICENAME PATHTOK PATH { |
| createservice(TYPE_FILE, $<string>2, $4, check_file); |
| } |
| ; |
| |
| checkfilesys : CHECKFILESYS SERVICENAME PATHTOK PATH { |
| createservice(TYPE_FILESYSTEM, $<string>2, $4, check_filesystem); |
| } |
| ; |
| |
| checkdir : CHECKDIR SERVICENAME PATHTOK PATH { |
| createservice(TYPE_DIRECTORY, $<string>2, $4, check_directory); |
| } |
| ; |
| |
| checkhost : CHECKHOST SERVICENAME ADDRESS STRING { |
| check_hostname($4); |
| createservice(TYPE_HOST, $<string>2, $4, check_remote_host); |
| } |
| ; |
| |
| checksystem : CHECKSYSTEM SERVICENAME { |
| createservice(TYPE_SYSTEM, $<string>2, Str_dup(""), check_system); |
| hassystem = TRUE; |
| } |
| ; |
| |
| checkfifo : CHECKFIFO SERVICENAME PATHTOK PATH { |
| createservice(TYPE_FIFO, $<string>2, $4, check_fifo); |
| } |
| ; |
| |
| checkprogram : CHECKPROGRAM SERVICENAME PATHTOK PATH { |
| check_exec($4); |
| createservice(TYPE_PROGRAM, $<string>2, $4, check_program); |
| } |
| ; |
| |
| start : START argumentlist exectimeout { |
| addcommand(START, $<number>3); |
| } |
| | START argumentlist useroptionlist exectimeout { |
| addcommand(START, $<number>4); |
| } |
| ; |
| |
| stop : STOP argumentlist exectimeout { |
| addcommand(STOP, $<number>3); |
| } |
| | STOP argumentlist useroptionlist exectimeout { |
| addcommand(STOP, $<number>4); |
| } |
| ; |
| |
| |
| restart : RESTART argumentlist exectimeout { |
| addcommand(RESTART, $<number>3); |
| } |
| | RESTART argumentlist useroptionlist exectimeout { |
| addcommand(RESTART, $<number>4); |
| } |
| ; |
| |
| argumentlist : argument |
| | argumentlist argument |
| ; |
| |
| useroptionlist : useroption |
| | useroptionlist useroption |
| ; |
| |
| argument : STRING { addargument($1); } |
| | PATH { addargument($1); } |
| ; |
| |
| useroption : UID STRING { addeuid( get_uid($2, 0) ); FREE($2); } |
| | GID STRING { addegid( get_gid($2, 0) ); FREE($2); } |
| | UID NUMBER { addeuid( get_uid(NULL, $2) ); } |
| | GID NUMBER { addegid( get_gid(NULL, $2) ); } |
| ; |
| |
| username : /* EMPTY */ { $<string>$ = NULL; } |
| | USERNAME MAILADDR { $<string>$ = $2; } |
| | USERNAME STRING { $<string>$ = $2; } |
| ; |
| |
| password : /* EMPTY */ { $<string>$ = NULL; } |
| | PASSWORD STRING { $<string>$ = $2; } |
| ; |
| |
| hostname : /* EMPTY */ { $<string>$ = NULL; } |
| | HOSTNAME STRING { $<string>$ = $2; } |
| ; |
| |
| connection : IF FAILED host port type protocol nettimeout retry rate1 |
| THEN action1 recovery { |
| portset.timeout = $<number>7; |
| portset.retry = $<number>8; |
| addeventaction(&(portset).action, $<number>11, $<number>12); |
| addport(&portset); |
| } |
| | IF FAILED URL URLOBJECT urloption nettimeout retry rate1 |
| THEN action1 recovery { |
| prepare_urlrequest($<url>4); |
| portset.timeout = $<number>6; |
| portset.retry = $<number>7; |
| addeventaction(&(portset).action, $<number>10, $<number>11); |
| addport(&portset); |
| } |
| ; |
| |
| connectionunix : IF FAILED unixsocket type protocol nettimeout retry rate1 |
| THEN action1 recovery { |
| portset.timeout = $<number>6; |
| portset.retry = $<number>7; |
| addeventaction(&(portset).action, $<number>10, $<number>11); |
| addport(&portset); |
| } |
| ; |
| |
| icmp : IF FAILED ICMP icmptype icmpcount nettimeout rate1 |
| THEN action1 recovery { |
| icmpset.type = $<number>4; |
| icmpset.count = $<number>5; |
| icmpset.timeout = $<number>6; |
| addeventaction(&(icmpset).action, $<number>9, $<number>10); |
| addicmp(&icmpset); |
| } |
| ; |
| |
| host : /* EMPTY */ { |
| if (current->type == TYPE_HOST) |
| portset.hostname = Str_dup(current->path); |
| else |
| portset.hostname = Str_dup(LOCALHOST); |
| } |
| | HOST STRING { check_hostname($2); portset.hostname = $2; } |
| ; |
| |
| port : PORT NUMBER { portset.port = $2; portset.family = AF_INET; } |
| ; |
| |
| unixsocket : UNIXSOCKET PATH { |
| portset.pathname = $2; portset.family = AF_UNIX; |
| } |
| ; |
| |
| type : /* EMPTY */ { |
| portset.type = SOCK_STREAM; |
| } |
| | TYPE TCP { |
| portset.type = SOCK_STREAM; |
| } |
| | TYPE TCPSSL sslversion certmd5 { |
| portset.type = SOCK_STREAM; |
| portset.SSL.use_ssl = TRUE; |
| portset.SSL.version = $<number>3; |
| if (portset.SSL.version == SSL_VERSION_NONE) |
| portset.SSL.version = SSL_VERSION_AUTO; |
| portset.SSL.certmd5 = $<string>4; |
| } |
| | TYPE UDP { |
| portset.type = SOCK_DGRAM; |
| } |
| ; |
| |
| certmd5 : /* EMPTY */ { $<string>$ = NULL; } |
| | CERTMD5 STRING { $<string>$ = $2; } |
| ; |
| |
| sslversion : /* EMPTY */ { $<number>$ = SSL_VERSION_NONE; } |
| | SSLV2 { $<number>$ = SSL_VERSION_SSLV2; } |
| | SSLV3 { $<number>$ = SSL_VERSION_SSLV3; } |
| | TLSV1 { $<number>$ = SSL_VERSION_TLS; } |
| | SSLAUTO { $<number>$ = SSL_VERSION_AUTO; } |
| ; |
| |
| protocol : /* EMPTY */ { |
| portset.protocol = Protocol_get(Protocol_DEFAULT); |
| } |
| | PROTOCOL APACHESTATUS apache_stat_list { |
| portset.protocol = Protocol_get(Protocol_APACHESTATUS); |
| } |
| | PROTOCOL DEFAULT { |
| portset.protocol = Protocol_get(Protocol_DEFAULT); |
| } |
| | PROTOCOL DNS { |
| portset.protocol = Protocol_get(Protocol_DNS); |
| } |
| | PROTOCOL DWP { |
| portset.protocol = Protocol_get(Protocol_DWP); |
| } |
| | PROTOCOL FTP { |
| portset.protocol = Protocol_get(Protocol_FTP); |
| } |
| | PROTOCOL HTTP request { |
| portset.protocol = Protocol_get(Protocol_HTTP); |
| } |
| | PROTOCOL IMAP { |
| portset.protocol = Protocol_get(Protocol_IMAP); |
| } |
| | PROTOCOL CLAMAV { |
| portset.protocol = Protocol_get(Protocol_CLAMAV); |
| } |
| | PROTOCOL LDAP2 { |
| portset.protocol = Protocol_get(Protocol_LDAP2); |
| } |
| | PROTOCOL LDAP3 { |
| portset.protocol = Protocol_get(Protocol_LDAP3); |
| } |
| | PROTOCOL MYSQL { |
| portset.protocol = Protocol_get(Protocol_MYSQL); |
| } |
| | PROTOCOL SIP target maxforward { |
| portset.protocol = Protocol_get(Protocol_SIP); |
| } |
| | PROTOCOL NNTP { |
| portset.protocol = Protocol_get(Protocol_NNTP); |
| } |
| | PROTOCOL NTP3 { |
| portset.protocol = Protocol_get(Protocol_NTP3); |
| portset.type = SOCK_DGRAM; |
| } |
| | PROTOCOL POSTFIXPOLICY { |
| portset.protocol = Protocol_get(Protocol_POSTFIXPOLICY); |
| } |
| | PROTOCOL POP { |
| portset.protocol = Protocol_get(Protocol_POP); |
| } |
| | PROTOCOL SMTP { |
| portset.protocol = Protocol_get(Protocol_SMTP); |
| } |
| | PROTOCOL SSH { |
| portset.protocol = Protocol_get(Protocol_SSH); |
| } |
| | PROTOCOL RDATE { |
| portset.protocol = Protocol_get(Protocol_RDATE); |
| } |
| | PROTOCOL RSYNC { |
| portset.protocol = Protocol_get(Protocol_RSYNC); |
| } |
| | PROTOCOL TNS { |
| portset.protocol = Protocol_get(Protocol_TNS); |
| } |
| | PROTOCOL PGSQL { |
| portset.protocol = Protocol_get(Protocol_PGSQL); |
| } |
| | PROTOCOL LMTP { |
| portset.protocol = Protocol_get(Protocol_LMTP); |
| } |
| | PROTOCOL GPS { |
| portset.protocol = Protocol_get(Protocol_GPS); |
| } |
| | PROTOCOL RADIUS secret { |
| portset.protocol = Protocol_get(Protocol_RADIUS); |
| } |
| | PROTOCOL MEMCACHE { |
| portset.protocol = Protocol_get(Protocol_MEMCACHE); |
| } |
| | sendexpectlist { |
| portset.protocol = Protocol_get(Protocol_GENERIC); |
| } |
| ; |
| |
| sendexpectlist : sendexpect |
| | sendexpectlist sendexpect |
| ; |
| |
| sendexpect : SEND STRING { addgeneric(&portset, $2, NULL); FREE($2);} |
| | EXPECT STRING { addgeneric(&portset, NULL, $2); FREE($2);} |
| ; |
| |
| target : /* EMPTY */ |
| | TARGET MAILADDR { |
| portset.request = $2; |
| } |
| | TARGET STRING { |
| portset.request = $2; |
| } |
| ; |
| |
| maxforward : /* EMPTY */ |
| | MAXFORWARD NUMBER { |
| portset.maxforward = verifyMaxForward($2); |
| } |
| ; |
| |
| request : /* EMPTY */ |
| | REQUEST PATH hostheader { |
| portset.request = Util_urlEncode($2); |
| FREE($2); |
| } |
| | REQUEST PATH CHECKSUM STRING hostheader { |
| portset.request = Util_urlEncode($2); |
| FREE($2); |
| portset.request_checksum = $4; |
| } |
| ; |
| |
| hostheader : /* EMPTY */ |
| | HOSTHEADER STRING { |
| portset.request_hostheader = $2; |
| } |
| ; |
| |
| secret : SECRET STRING { |
| portset.request = $2; |
| } |
| ; |
| |
| apache_stat_list: apache_stat |
| | apache_stat_list OR apache_stat |
| ; |
| |
| apache_stat : LOGLIMIT operator NUMBER PERCENT { |
| portset.ApacheStatus.loglimitOP = $<number>2; |
| portset.ApacheStatus.loglimit = (int)$3; |
| } |
| | CLOSELIMIT operator NUMBER PERCENT { |
| portset.ApacheStatus.closelimitOP = $<number>2; |
| portset.ApacheStatus.closelimit = (int)($3); |
| } |
| | DNSLIMIT operator NUMBER PERCENT { |
| portset.ApacheStatus.dnslimitOP = $<number>2; |
| portset.ApacheStatus.dnslimit = (int)($3); |
| } |
| | KEEPALIVELIMIT operator NUMBER PERCENT { |
| portset.ApacheStatus.keepalivelimitOP = $<number>2; |
| portset.ApacheStatus.keepalivelimit = (int)($3); |
| } |
| | REPLYLIMIT operator NUMBER PERCENT { |
| portset.ApacheStatus.replylimitOP = $<number>2; |
| portset.ApacheStatus.replylimit = (int)($3); |
| } |
| | REQUESTLIMIT operator NUMBER PERCENT { |
| portset.ApacheStatus.requestlimitOP = $<number>2; |
| portset.ApacheStatus.requestlimit = (int)($3); |
| } |
| | STARTLIMIT operator NUMBER PERCENT { |
| portset.ApacheStatus.startlimitOP = $<number>2; |
| portset.ApacheStatus.startlimit = (int)($3); |
| } |
| | WAITLIMIT operator NUMBER PERCENT { |
| portset.ApacheStatus.waitlimitOP = $<number>2; |
| portset.ApacheStatus.waitlimit = (int)($3); |
| } |
| | GRACEFULLIMIT operator NUMBER PERCENT { |
| portset.ApacheStatus.gracefullimitOP = $<number>2; |
| portset.ApacheStatus.gracefullimit = (int)($3); |
| } |
| | CLEANUPLIMIT operator NUMBER PERCENT { |
| portset.ApacheStatus.cleanuplimitOP = $<number>2; |
| portset.ApacheStatus.cleanuplimit = (int)($3); |
| } |
| ; |
| |
| exist : IF NOT EXIST rate1 THEN action1 recovery { |
| seteventaction(&(current)->action_NONEXIST, $<number>6, $<number>7); |
| } |
| ; |
| |
| |
| pid : IF CHANGED PID rate1 THEN action1 { |
| seteventaction(&(current)->action_PID, $<number>6, ACTION_IGNORE); |
| } |
| ; |
| |
| ppid : IF CHANGED PPID rate1 THEN action1 { |
| seteventaction(&(current)->action_PPID, $<number>6, ACTION_IGNORE); |
| } |
| ; |
| |
| uptime : IF UPTIME operator NUMBER time rate1 THEN action1 recovery { |
| uptimeset.operator = $<number>3; |
| uptimeset.uptime = ((unsigned long long)$4 * $<number>5); |
| addeventaction(&(uptimeset).action, $<number>8, $<number>9); |
| adduptime(&uptimeset); |
| } |
| |
| icmpcount : /* EMPTY */ { |
| $<number>$ = ICMP_ATTEMPT_COUNT; |
| } |
| | COUNT NUMBER { |
| $<number>$ = $2; |
| } |
| ; |
| |
| exectimeout : /* EMPTY */ { |
| $<number>$ = EXEC_TIMEOUT; |
| } |
| | TIMEOUT NUMBER SECOND { |
| $<number>$ = $2; |
| } |
| ; |
| |
| programtimeout : /* EMPTY */ { |
| $<number>$ = 600; // Default program status check timeout is 5 min |
| } |
| | TIMEOUT NUMBER SECOND { |
| $<number>$ = $2; |
| } |
| ; |
| |
| nettimeout : /* EMPTY */ { |
| $<number>$ = NET_TIMEOUT; |
| } |
| | TIMEOUT NUMBER SECOND { |
| $<number>$ = $2; |
| } |
| ; |
| |
| retry : /* EMPTY */ { |
| $<number>$ = 1; |
| } |
| | RETRY NUMBER { |
| $<number>$ = $2; |
| } |
| ; |
| |
| actionrate : IF NUMBER RESTART NUMBER CYCLE THEN action1 { |
| actionrateset.count = $2; |
| actionrateset.cycle = $4; |
| addeventaction(&(actionrateset).action, $<number>7, ACTION_IGNORE); |
| addactionrate(&actionrateset); |
| } |
| | IF NUMBER RESTART NUMBER CYCLE THEN TIMEOUT { |
| actionrateset.count = $2; |
| actionrateset.cycle = $4; |
| addeventaction(&(actionrateset).action, ACTION_UNMONITOR, ACTION_IGNORE); |
| addactionrate(&actionrateset); |
| } |
| ; |
| |
| urloption : /* EMPTY */ |
| | CONTENT urloperator STRING { |
| seturlrequest($<number>2, $<string>3); |
| FREE($3); |
| } |
| ; |
| |
| urloperator : EQUAL { $<number>$ = OPERATOR_EQUAL; } |
| | NOTEQUAL { $<number>$ = OPERATOR_NOTEQUAL; } |
| ; |
| |
| alert : alertmail formatlist reminder { |
| mailset.events = Event_All; |
| addmail($<string>1, &mailset, ¤t->maillist); |
| } |
| | alertmail '{' eventoptionlist '}' formatlist reminder { |
| addmail($<string>1, &mailset, ¤t->maillist); |
| } |
| | alertmail NOT '{' eventoptionlist '}' formatlist reminder { |
| mailset.events = ~mailset.events; |
| addmail($<string>1, &mailset, ¤t->maillist); |
| } |
| | noalertmail { |
| addmail($<string>1, &mailset, ¤t->maillist); |
| } |
| ; |
| |
| alertmail : ALERT MAILADDR { $<string>$ = $2; } |
| ; |
| |
| noalertmail : NOALERT MAILADDR { $<string>$ = $2; } |
| ; |
| |
| eventoptionlist : eventoption |
| | eventoptionlist eventoption |
| ; |
| |
| eventoption : ACTION { mailset.events |= Event_Action; } |
| | CHECKSUM { mailset.events |= Event_Checksum; } |
| | CONNECTION { mailset.events |= Event_Connection; } |
| | CONTENT { mailset.events |= Event_Content; } |
| | DATA { mailset.events |= Event_Data; } |
| | EXEC { mailset.events |= Event_Exec; } |
| | FSFLAG { mailset.events |= Event_Fsflag; } |
| | GID { mailset.events |= Event_Gid; } |
| | ICMP { mailset.events |= Event_Icmp; } |
| | INSTANCE { mailset.events |= Event_Instance; } |
| | INVALID { mailset.events |= Event_Invalid; } |
| | NONEXIST { mailset.events |= Event_Nonexist; } |
| | PERMISSION { mailset.events |= Event_Permission; } |
| | PID { mailset.events |= Event_Pid; } |
| | PPID { mailset.events |= Event_PPid; } |
| | RESOURCE { mailset.events |= Event_Resource; } |
| | SIZE { mailset.events |= Event_Size; } |
| | STATUS { mailset.events |= Event_Status; } |
| | TIMEOUT { mailset.events |= Event_Timeout; } |
| | TIMESTAMP { mailset.events |= Event_Timestamp; } |
| | UID { mailset.events |= Event_Uid; } |
| | UPTIME { mailset.events |= Event_Uptime; } |
| ; |
| |
| formatlist : /* EMPTY */ |
| | MAILFORMAT '{' formatoptionlist '}' |
| ; |
| |
| formatoptionlist: formatoption |
| | formatoptionlist formatoption |
| ; |
| |
| formatoption : MAILFROM { mailset.from = $1; } |
| | MAILREPLYTO { mailset.replyto = $1; } |
| | MAILSUBJECT { mailset.subject = $1; } |
| | MAILBODY { mailset.message = $1; } |
| ; |
| |
| every : EVERY NUMBER CYCLE { |
| current->every.type = EVERY_SKIPCYCLES; |
| current->every.spec.cycle.number = $2; |
| } |
| | EVERY TIMESPEC { |
| current->every.type = EVERY_CRON; |
| current->every.spec.cron = $2; |
| } |
| | NOTEVERY TIMESPEC { |
| current->every.type = EVERY_NOTINCRON; |
| current->every.spec.cron = $2; |
| } |
| ; |
| |
| mode : MODE ACTIVE { |
| current->mode = MODE_ACTIVE; |
| } |
| | MODE PASSIVE { |
| current->mode = MODE_PASSIVE; |
| } |
| | MODE MANUAL { |
| current->mode = MODE_MANUAL; |
| current->monitor = MONITOR_NOT; |
| } |
| ; |
| |
| group : GROUP STRINGNAME { addservicegroup($2); FREE($2);} |
| ; |
| |
| |
| depend : DEPENDS dependlist |
| ; |
| |
| dependlist : dependant |
| | dependlist dependant |
| ; |
| |
| dependant : SERVICENAME { adddependant($<string>1); } |
| ; |
| |
| exitvalue : IF STATUS operator NUMBER programtimeout rate1 THEN action1 recovery { |
| programset.operator = $<number>3; |
| programset.return_value = $<number>4; |
| programset.timeout = $<number>5; |
| addeventaction(&(programset).action, $<number>8, $<number>9); |
| addprogram(&programset); |
| } |
| ; |
| |
| resourceprocess : IF resourceprocesslist rate1 THEN action1 recovery { |
| addeventaction(&(resourceset).action, $<number>5, $<number>6); |
| addresource(&resourceset); |
| } |
| ; |
| |
| resourceprocesslist : resourceprocessopt |
| | resourceprocesslist resourceprocessopt |
| ; |
| |
| resourceprocessopt : resourcecpuproc |
| | resourcemem |
| | resourcechild |
| | resourceload |
| ; |
| |
| resourcesystem : IF resourcesystemlist rate1 THEN action1 recovery { |
| addeventaction(&(resourceset).action, $<number>5, $<number>6); |
| addresource(&resourceset); |
| } |
| ; |
| |
| resourcesystemlist : resourcesystemopt |
| | resourcesystemlist resourcesystemopt |
| ; |
| |
| resourcesystemopt : resourceload |
| | resourcemem |
| | resourceswap |
| | resourcecpu |
| ; |
| |
| resourcecpuproc : CPU operator NUMBER PERCENT { |
| resourceset.resource_id = RESOURCE_ID_CPU_PERCENT; |
| resourceset.operator = $<number>2; |
| resourceset.limit = ($3 * 10); |
| } |
| | TOTALCPU operator NUMBER PERCENT { |
| resourceset.resource_id = RESOURCE_ID_TOTAL_CPU_PERCENT; |
| resourceset.operator = $<number>2; |
| resourceset.limit = ($3 * 10); |
| } |
| ; |
| |
| resourcecpu : resourcecpuid operator NUMBER PERCENT { |
| resourceset.resource_id = $<number>1; |
| resourceset.operator = $<number>2; |
| resourceset.limit = ($3 * 10); |
| } |
| ; |
| |
| resourcecpuid : CPUUSER { $<number>$ = RESOURCE_ID_CPUUSER; } |
| | CPUSYSTEM { $<number>$ = RESOURCE_ID_CPUSYSTEM; } |
| | CPUWAIT { $<number>$ = RESOURCE_ID_CPUWAIT; } |
| ; |
| |
| resourcemem : MEMORY operator value unit { |
| resourceset.resource_id = RESOURCE_ID_MEM_KBYTE; |
| resourceset.operator = $<number>2; |
| resourceset.limit = (int) ($<real>3 * ($<number>4 / 1024.0)); |
| } |
| | MEMORY operator NUMBER PERCENT { |
| resourceset.resource_id = RESOURCE_ID_MEM_PERCENT; |
| resourceset.operator = $<number>2; |
| resourceset.limit = ($3 * 10); |
| } |
| | TOTALMEMORY operator value unit { |
| resourceset.resource_id = RESOURCE_ID_TOTAL_MEM_KBYTE; |
| resourceset.operator = $<number>2; |
| resourceset.limit = (int) ($<real>3 * ($<number>4 / 1024.0)); |
| } |
| | TOTALMEMORY operator NUMBER PERCENT { |
| resourceset.resource_id = RESOURCE_ID_TOTAL_MEM_PERCENT; |
| resourceset.operator = $<number>2; |
| resourceset.limit = ($3 * 10); |
| } |
| ; |
| |
| resourceswap : SWAP operator value unit { |
| resourceset.resource_id = RESOURCE_ID_SWAP_KBYTE; |
| resourceset.operator = $<number>2; |
| resourceset.limit = (int) ($<real>3 * ($<number>4 / 1024.0)); |
| } |
| | SWAP operator NUMBER PERCENT { |
| resourceset.resource_id = RESOURCE_ID_SWAP_PERCENT; |
| resourceset.operator = $<number>2; |
| resourceset.limit = ($3 * 10); |
| } |
| ; |
| |
| resourcechild : CHILDREN operator NUMBER { |
| resourceset.resource_id = RESOURCE_ID_CHILDREN; |
| resourceset.operator = $<number>2; |
| resourceset.limit = (int) $3; |
| } |
| ; |
| |
| resourceload : resourceloadavg operator value { |
| resourceset.resource_id = $<number>1; |
| resourceset.operator = $<number>2; |
| resourceset.limit = (int) ($<real>3 * 10.0); |
| } |
| ; |
| |
| resourceloadavg : LOADAVG1 { $<number>$ = RESOURCE_ID_LOAD1; } |
| | LOADAVG5 { $<number>$ = RESOURCE_ID_LOAD5; } |
| | LOADAVG15 { $<number>$ = RESOURCE_ID_LOAD15; } |
| ; |
| |
| value : REAL { $<real>$ = $1; } |
| | NUMBER { $<real>$ = (float) $1; } |
| ; |
| |
| timestamp : IF TIMESTAMP operator NUMBER time rate1 THEN action1 recovery { |
| timestampset.operator = $<number>3; |
| timestampset.time = ($4 * $<number>5); |
| addeventaction(&(timestampset).action, $<number>8, $<number>9); |
| addtimestamp(×tampset, FALSE); |
| } |
| | IF CHANGED TIMESTAMP rate1 THEN action1 { |
| timestampset.test_changes = TRUE; |
| addeventaction(&(timestampset).action, $<number>6, ACTION_IGNORE); |
| addtimestamp(×tampset, TRUE); |
| } |
| ; |
| |
| operator : /* EMPTY */ { $<number>$ = OPERATOR_EQUAL; } |
| | GREATER { $<number>$ = OPERATOR_GREATER; } |
| | LESS { $<number>$ = OPERATOR_LESS; } |
| | EQUAL { $<number>$ = OPERATOR_EQUAL; } |
| | NOTEQUAL { $<number>$ = OPERATOR_NOTEQUAL; } |
| | CHANGED { $<number>$ = OPERATOR_NOTEQUAL; } |
| ; |
| |
| time : /* EMPTY */ { $<number>$ = TIME_SECOND; } |
| | SECOND { $<number>$ = TIME_SECOND; } |
| | MINUTE { $<number>$ = TIME_MINUTE; } |
| | HOUR { $<number>$ = TIME_HOUR; } |
| | DAY { $<number>$ = TIME_DAY; } |
| ; |
| |
| action : ALERT { $<number>$ = ACTION_ALERT; } |
| | EXEC argumentlist { $<number>$ = ACTION_EXEC; } |
| | EXEC argumentlist useroptionlist { $<number>$ = ACTION_EXEC; } |
| | RESTART { $<number>$ = ACTION_RESTART; } |
| | START { $<number>$ = ACTION_START; } |
| | STOP { $<number>$ = ACTION_STOP; } |
| | UNMONITOR { $<number>$ = ACTION_UNMONITOR; } |
| ; |
| |
| action1 : action { |
| $<number>$ = $<number>1; |
| if ($<number>1 == ACTION_EXEC && command) { |
| command1 = command; |
| command = NULL; |
| } |
| } |
| ; |
| |
| action2 : action { |
| $<number>$ = $<number>1; |
| if ($<number>1 == ACTION_EXEC && command) { |
| command2 = command; |
| command = NULL; |
| } |
| } |
| ; |
| |
| rate1 : /* EMPTY */ |
| | NUMBER CYCLE { |
| rate1.count = $<number>1; |
| rate1.cycles = $<number>1; |
| if (rate1.cycles < 1 || rate1.cycles > BITMAP_MAX) |
| yyerror2("the number of cycles must be between 1 and %d", BITMAP_MAX); |
| } |
| | NUMBER NUMBER CYCLE { |
| rate1.count = $<number>1; |
| rate1.cycles = $<number>2; |
| if (rate1.cycles < 1 || rate1.cycles > BITMAP_MAX) |
| yyerror2("the number of cycles must be between 1 and %d", BITMAP_MAX); |
| if (rate1.count < 1 || rate1.count > rate1.cycles) |
| yyerror2("the number of events must be bigger then 0 and less than poll cycles"); |
| } |
| ; |
| |
| rate2 : /* EMPTY */ |
| | NUMBER CYCLE { |
| rate2.count = $<number>1; |
| rate2.cycles = $<number>1; |
| if (rate2.cycles < 1 || rate2.cycles > BITMAP_MAX) |
| yyerror2("the number of cycles must be between 1 and %d", BITMAP_MAX); |
| } |
| | NUMBER NUMBER CYCLE { |
| rate2.count = $<number>1; |
| rate2.cycles = $<number>2; |
| if (rate2.cycles < 1 || rate2.cycles > BITMAP_MAX) |
| yyerror2("the number of cycles must be between 1 and %d", BITMAP_MAX); |
| if (rate2.count < 1 || rate2.count > rate2.cycles) |
| yyerror2("the number of events must be bigger then 0 and less than poll cycles"); |
| } |
| ; |
| |
| recovery : /* EMPTY */ { |
| $<number>$ = ACTION_ALERT; |
| } |
| | ELSE IF RECOVERED rate2 THEN action2 { |
| $<number>$ = $<number>6; |
| } |
| | ELSE IF PASSED rate2 THEN action2 { |
| $<number>$ = $<number>6; |
| } |
| | ELSE IF SUCCEEDED rate2 THEN action2 { |
| $<number>$ = $<number>6; |
| } |
| ; |
| |
| checksum : IF FAILED hashtype CHECKSUM rate1 THEN action1 recovery { |
| addeventaction(&(checksumset).action, $<number>7, $<number>8); |
| addchecksum(&checksumset); |
| } |
| | IF FAILED hashtype CHECKSUM EXPECT STRING rate1 THEN action1 |
| recovery { |
| snprintf(checksumset.hash, sizeof(checksumset.hash), "%s", $6); |
| FREE($6); |
| addeventaction(&(checksumset).action, $<number>9, $<number>10); |
| addchecksum(&checksumset); |
| } |
| | IF CHANGED hashtype CHECKSUM rate1 THEN action1 { |
| checksumset.test_changes = TRUE; |
| addeventaction(&(checksumset).action, $<number>7, ACTION_IGNORE); |
| addchecksum(&checksumset); |
| } |
| ; |
| hashtype : /* EMPTY */ { checksumset.type = HASH_UNKNOWN; } |
| | MD5HASH { checksumset.type = HASH_MD5; } |
| | SHA1HASH { checksumset.type = HASH_SHA1; } |
| ; |
| |
| inode : IF INODE operator NUMBER rate1 THEN action1 recovery { |
| filesystemset.resource = RESOURCE_ID_INODE; |
| filesystemset.operator = $<number>3; |
| filesystemset.limit_absolute = $4; |
| addeventaction(&(filesystemset).action, $<number>7, $<number>8); |
| addfilesystem(&filesystemset); |
| } |
| | IF INODE operator NUMBER PERCENT rate1 THEN action1 recovery { |
| filesystemset.resource = RESOURCE_ID_INODE; |
| filesystemset.operator = $<number>3; |
| filesystemset.limit_percent = (int)($4 * 10); |
| addeventaction(&(filesystemset).action, $<number>8, $<number>9); |
| addfilesystem(&filesystemset); |
| } |
| ; |
| |
| space : IF SPACE operator value unit rate1 THEN action1 recovery { |
| if (!filesystem_usage(current->inf, current->path)) |
| yyerror2("cannot read usage of filesystem %s", current->path); |
| filesystemset.resource = RESOURCE_ID_SPACE; |
| filesystemset.operator = $<number>3; |
| filesystemset.limit_absolute = (int)((float)$<real>4 / (float)current->inf->priv.filesystem.f_bsize * (float)$<number>5); |
| addeventaction(&(filesystemset).action, $<number>8, $<number>9); |
| addfilesystem(&filesystemset); |
| } |
| | IF SPACE operator NUMBER PERCENT rate1 THEN action1 recovery { |
| filesystemset.resource = RESOURCE_ID_SPACE; |
| filesystemset.operator = $<number>3; |
| filesystemset.limit_percent = (int)($4 * 10); |
| addeventaction(&(filesystemset).action, $<number>8, $<number>9); |
| addfilesystem(&filesystemset); |
| } |
| ; |
| |
| fsflag : IF CHANGED FSFLAG rate1 THEN action1 { |
| seteventaction(&(current)->action_FSFLAG, $<number>6, ACTION_IGNORE); |
| } |
| ; |
| |
| unit : /* empty */ { $<number>$ = UNIT_BYTE; } |
| | BYTE { $<number>$ = UNIT_BYTE; } |
| | KILOBYTE { $<number>$ = UNIT_KILOBYTE; } |
| | MEGABYTE { $<number>$ = UNIT_MEGABYTE; } |
| | GIGABYTE { $<number>$ = UNIT_GIGABYTE; } |
| ; |
| |
| permission : IF FAILED PERMISSION NUMBER rate1 THEN action1 recovery { |
| permset.perm = check_perm($4); |
| addeventaction(&(permset).action, $<number>7, $<number>8); |
| addperm(&permset); |
| } |
| ; |
| |
| match : IF matchflagnot MATCH PATH rate1 THEN action1 { |
| matchset.ignore = FALSE; |
| matchset.match_path = $4; |
| matchset.match_string = NULL; |
| addmatchpath(&matchset, $<number>7); |
| FREE($4); |
| } |
| | IF matchflagnot MATCH STRING rate1 THEN action1 { |
| matchset.ignore = FALSE; |
| matchset.match_path = NULL; |
| matchset.match_string = $4; |
| addmatch(&matchset, $<number>7, 0); |
| } |
| | IGNORE matchflagnot MATCH PATH { |
| matchset.ignore = TRUE; |
| matchset.match_path = $4; |
| matchset.match_string = NULL; |
| addmatchpath(&matchset, ACTION_IGNORE); |
| FREE($4); |
| } |
| | IGNORE matchflagnot MATCH STRING { |
| matchset.ignore = TRUE; |
| matchset.match_path = NULL; |
| matchset.match_string = $4; |
| addmatch(&matchset, ACTION_IGNORE, 0); |
| } |
| ; |
| |
| matchflagnot : /* EMPTY */ { |
| matchset.not = FALSE; |
| } |
| | NOT { |
| matchset.not = TRUE; |
| } |
| ; |
| |
| |
| size : IF SIZE operator NUMBER unit rate1 THEN action1 recovery { |
| sizeset.operator = $<number>3; |
| sizeset.size = ((unsigned long long)$4 * $<number>5); |
| addeventaction(&(sizeset).action, $<number>8, $<number>9); |
| addsize(&sizeset); |
| } |
| | IF CHANGED SIZE rate1 THEN action1 { |
| sizeset.test_changes = TRUE; |
| addeventaction(&(sizeset).action, $<number>6, ACTION_IGNORE); |
| addsize(&sizeset); |
| } |
| ; |
| |
| uid : IF FAILED UID STRING rate1 THEN action1 recovery { |
| uidset.uid = get_uid($4, 0); |
| addeventaction(&(uidset).action, $<number>7, $<number>8); |
| adduid(&uidset); |
| FREE($4); |
| } |
| | IF FAILED UID NUMBER rate1 THEN action1 recovery { |
| uidset.uid = get_uid(NULL, $4); |
| addeventaction(&(uidset).action, $<number>7, $<number>8); |
| adduid(&uidset); |
| } |
| ; |
| |
| gid : IF FAILED GID STRING rate1 THEN action1 recovery { |
| gidset.gid = get_gid($4, 0); |
| addeventaction(&(gidset).action, $<number>7, $<number>8); |
| addgid(&gidset); |
| FREE($4); |
| } |
| | IF FAILED GID NUMBER rate1 THEN action1 recovery { |
| gidset.gid = get_gid(NULL, $4); |
| addeventaction(&(gidset).action, $<number>7, $<number>8); |
| addgid(&gidset); |
| } |
| ; |
| |
| icmptype : TYPE ICMPECHO { $<number>$ = ICMP_ECHO; } |
| ; |
| |
| reminder : /* EMPTY */ { mailset.reminder = 0; } |
| | REMINDER NUMBER { mailset.reminder = $<number>2; } |
| | REMINDER NUMBER CYCLE { mailset.reminder = $<number>2; } |
| ; |
| |
| %% |
| |
| |
| /* -------------------------------------------------------- Parser interface */ |
| |
| |
| /** |
| * Syntactic error routine |
| * |
| * This routine is automatically called by the lexer! |
| */ |
| void yyerror(const char *s, ...) { |
| va_list ap; |
| char *msg = NULL; |
| |
| ASSERT(s); |
| |
| va_start(ap,s); |
| msg = Str_vcat(s, ap); |
| va_end(ap); |
| |
| LogError("%s:%i: Error: %s '%s'\n", currentfile, lineno, msg, yytext); |
| cfg_errflag++; |
| |
| FREE(msg); |
| |
| } |
| |
| /** |
| * Syntactical warning routine |
| */ |
| void yywarning(const char *s, ...) { |
| va_list ap; |
| char *msg = NULL; |
| |
| ASSERT(s); |
| |
| va_start(ap,s); |
| msg = Str_vcat(s, ap); |
| va_end(ap); |
| |
| LogWarning("%s:%i: Warning: %s '%s'\n", currentfile, lineno, msg, yytext); |
| |
| FREE(msg); |
| |
| } |
| |
| /** |
| * Argument error routine |
| */ |
| void yyerror2(const char *s, ...) { |
| va_list ap; |
| char *msg = NULL; |
| |
| ASSERT(s); |
| |
| va_start(ap,s); |
| msg = Str_vcat(s, ap); |
| va_end(ap); |
| |
| LogError("%s:%i: Error: %s '%s'\n", argcurrentfile, arglineno, msg, argyytext); |
| cfg_errflag++; |
| |
| FREE(msg); |
| |
| } |
| |
| /** |
| * Argument warning routine |
| */ |
| void yywarning2(const char *s, ...) { |
| va_list ap; |
| char *msg = NULL; |
| |
| ASSERT(s); |
| |
| va_start(ap,s); |
| msg = Str_vcat(s, ap); |
| va_end(ap); |
| |
| LogWarning("%s:%i: Warning: %s '%s'\n", argcurrentfile, arglineno, msg, argyytext); |
| |
| FREE(msg); |
| |
| } |
| |
| /* |
| * The Parser hook - start parsing the control file |
| * Returns TRUE if parsing succeeded, otherwise FALSE |
| */ |
| int parse(char *controlfile) { |
| |
| ASSERT(controlfile); |
| |
| servicelist = tail = current = NULL; |
| |
| /* |
| * Secure check the monitrc file. The run control file must have the |
| * same uid as the REAL uid of this process, it must have permissions |
| * no greater than 700 and it must not be a symbolic link. |
| */ |
| if (! file_checkStat(controlfile, "control file", S_IRUSR|S_IWUSR|S_IXUSR)) |
| return FALSE; |
| |
| if ((yyin = fopen(controlfile,"r")) == (FILE *)NULL) { |
| LogError("%s: Error: cannot open the control file '%s' -- %s\n", prog, controlfile, STRERROR); |
| return FALSE; |
| } |
| |
| currentfile = Str_dup(controlfile); |
| |
| /* |
| * Creation of the global service list is synchronized |
| */ |
| LOCK(Run.mutex) |
| preparse(); |
| yyparse(); |
| fclose(yyin); |
| /* Add the default general system service if not specified explicitly */ |
| if (!hassystem) { |
| char *name = Str_cat("system_%s", Run.localhostname); |
| if (Util_existService(name) || (current && IS(name, current->name))) { |
| LogError("'check system' not defined in control file, failed to add automatic configuration (service name %s is used already) -- please add 'check system <name>' manually\n", name, name); |
| FREE(name); |
| cfg_errflag++; |
| } else { |
| createservice(TYPE_SYSTEM, name, Str_dup(""), check_system); |
| } |
| } |
| /* If defined - add the last service to the service list */ |
| if (current) { |
| addservice(current); |
| FREE(current); |
| } |
| postparse(); |
| END_LOCK; |
| |
| FREE(currentfile); |
| |
| if (argyytext != NULL) |
| FREE(argyytext); |
| |
| return(cfg_errflag == 0); |
| } |
| |
| |
| /* ----------------------------------------------------------------- Private */ |
| |
| |
| /** |
| * Initialize objects used by the parser. |
| */ |
| static void preparse() { |
| int i; |
| char localhost[STRLEN]; |
| |
| /* |
| * Get the localhost name |
| */ |
| if (Util_getfqdnhostname(localhost, sizeof(localhost))) |
| snprintf(localhost, STRLEN, "%s", LOCALHOST); |
| |
| /* Set instance incarnation ID */ |
| time(&Run.incarnation); |
| /* Reset lexer */ |
| buffer_stack_ptr = 0; |
| lineno = 1; |
| arglineno = 1; |
| argcurrentfile = NULL; |
| argyytext = NULL; |
| /* Reset parser */ |
| Run.stopped = FALSE; |
| Run.dolog = FALSE; |
| Run.dohttpd = FALSE; |
| Run.doaction = FALSE; |
| Run.httpdsig = TRUE; |
| Run.dommonitcredentials = TRUE; |
| Run.mmonitcredentials = NULL; |
| Run.credentials = NULL; |
| Run.httpdssl = FALSE; |
| Run.httpsslpem = NULL; |
| Run.httpsslclientpem = NULL; |
| Run.clientssl = FALSE; |
| Run.allowselfcert = FALSE; |
| Run.mailserver_timeout = NET_TIMEOUT; |
| Run.bind_addr = NULL; |
| Run.eventlist = NULL; |
| Run.eventlist_dir = NULL; |
| Run.eventlist_slots = -1; |
| Run.system = NULL; |
| Run.expectbuffer = STRLEN; |
| Run.mmonits = NULL; |
| Run.maillist = NULL; |
| Run.mailservers = NULL; |
| Run.MailFormat.from = NULL; |
| Run.MailFormat.replyto = NULL; |
| Run.MailFormat.subject = NULL; |
| Run.MailFormat.message = NULL; |
| Run.localhostname = Str_dup(localhost); |
| depend_list = NULL; |
| Run.handler_init = TRUE; |
| #ifdef OPENSSL_FIPS |
| Run.fipsEnabled = FALSE; |
| #endif |
| for (i = 0; i <= HANDLER_MAX; i++) |
| Run.handler_queue[i] = 0; |
| /* |
| * Initialize objects |
| */ |
| reset_uidset(); |
| reset_programset(); |
| reset_gidset(); |
| reset_sizeset(); |
| reset_mailset(); |
| reset_mailserverset(); |
| reset_portset(); |
| reset_permset(); |
| reset_icmpset(); |
| reset_rateset(); |
| reset_filesystemset(); |
| reset_resourceset(); |
| reset_checksumset(); |
| reset_timestampset(); |
| reset_actionrateset(); |
| } |
| |
| |
| /* |
| * Check that values are reasonable after parsing |
| */ |
| static void postparse() { |
| Service_T s; |
| |
| if (cfg_errflag || ! servicelist) |
| return; |
| |
| /* Check the sanity of any dependency graph */ |
| check_depend(); |
| |
| /* Check that we do not start monit in daemon mode without having a |
| * poll time */ |
| if (!Run.polltime && (Run.isdaemon || Run.init)) { |
| LogError("%s: Error: Poll time not defined. Please define poll time in the\n control file or use the -d option when starting monit\n", prog); |
| cfg_errflag++; |
| } |
| |
| if (Run.logfile) |
| Run.dolog = TRUE; |
| |
| for (s = servicelist; s; s = s->next) { |
| /* Set the general system service shortcut */ |
| if (s->type == TYPE_SYSTEM) |
| Run.system = s; |
| else if (s->type == TYPE_HOST) { |
| /* Verify that a remote service has a port or an icmp list */ |
| if (!s->portlist && !s->icmplist) { |
| LogError("%s: Error: 'check host' statement is incomplete; Please specify a port number to test\n or an icmp test at the remote host: '%s'\n", prog, s->name); |
| cfg_errflag++; |
| } |
| } |
| else if (s->type == TYPE_PROGRAM) { |
| /* Verify that a program test has a status test */ |
| if (! s->program) { |
| LogError("%s: Error: 'check program %s' is incomplete; Please add an 'if status != n' test\n", prog, s->name); |
| cfg_errflag++; |
| } |
| } |
| } |
| |
| if (Run.mmonits) { |
| if (Run.dohttpd) { |
| if (Run.dommonitcredentials) { |
| Auth_T c; |
| for (c = Run.credentials; c; c = c->next) { |
| if (c->digesttype == DIGEST_CLEARTEXT && ! c->is_readonly) { |
| Run.mmonitcredentials = c; |
| break; |
| } |
| } |
| if (! Run.mmonitcredentials) |
| LogWarning("%s: Warning: M/Monit registration with credentials enabled, but no suitable credentials found in monit configuration file -- please add 'allow user:password' option to 'set httpd' statement\n", prog); |
| } |
| } else |
| LogWarning("%s: Warning: M/Monit enabled but no httpd allowed -- please add 'set httpd' statement\n", prog); |
| } |
| } |
| |
| |
| /* |
| * Create a new service object and add any current objects to the |
| * service list. |
| */ |
| static void createservice(int type, char *name, char *value, int (*check)(Service_T s)) { |
| |
| ASSERT(name); |
| ASSERT(value); |
| |
| check_name(name); |
| |
| if (current) { |
| addservice(current); |
| memset(current, 0, sizeof(*current)); |
| } else { |
| NEW(current); |
| } |
| |
| current->type = type; |
| |
| NEW(current->inf); |
| Util_resetInfo(current); |
| |
| /* Set default values */ |
| current->monitor = MONITOR_INIT; |
| current->mode = MODE_ACTIVE; |
| current->name = name; |
| current->check = check; |
| current->path = value; |
| |
| /* Initialize general event handlers */ |
| addeventaction(&(current)->action_DATA, ACTION_ALERT, ACTION_ALERT); |
| addeventaction(&(current)->action_EXEC, ACTION_ALERT, ACTION_ALERT); |
| addeventaction(&(current)->action_INVALID, ACTION_RESTART, ACTION_ALERT); |
| addeventaction(&(current)->action_NONEXIST, ACTION_RESTART, ACTION_ALERT); |
| addeventaction(&(current)->action_PID, ACTION_ALERT, ACTION_IGNORE); |
| addeventaction(&(current)->action_PPID, ACTION_ALERT, ACTION_IGNORE); |
| addeventaction(&(current)->action_FSFLAG, ACTION_ALERT, ACTION_IGNORE); |
| |
| /* Initialize internal event handlers */ |
| addeventaction(&(current)->action_MONIT_START, ACTION_START, ACTION_IGNORE); |
| addeventaction(&(current)->action_MONIT_STOP, ACTION_STOP, ACTION_IGNORE); |
| addeventaction(&(current)->action_MONIT_RELOAD, ACTION_START, ACTION_IGNORE); |
| addeventaction(&(current)->action_ACTION, ACTION_ALERT, ACTION_IGNORE); |
| |
| gettimeofday(¤t->collected, NULL); |
| } |
| |
| |
| /* |
| * Add a service object to the servicelist |
| */ |
| static void addservice(Service_T s) { |
| Service_T n; |
| |
| ASSERT(s); |
| |
| NEW(n); |
| memcpy(n, s, sizeof(*s)); |
| /* Add the service to the end of the service list */ |
| if (tail != NULL) { |
| tail->next = n; |
| tail->next_conf = n; |
| } else { |
| servicelist = n; |
| servicelist_conf = n; |
| } |
| tail = n; |
| } |
| |
| |
| /* |
| * Add entry to service group list |
| */ |
| static void addservicegroup(char *name) { |
| ServiceGroup_T g; |
| ServiceGroupMember_T m; |
| |
| ASSERT(name); |
| |
| /* Check if service group with the same name is defined already */ |
| for (g = servicegrouplist; g; g = g->next) |
| if (! strcasecmp(g->name, name)) |
| break; |
| |
| if (! g) { |
| NEW(g); |
| g->name = Str_dup(name); |
| g->next = servicegrouplist; |
| servicegrouplist = g; |
| } |
| |
| NEW(m); |
| m->name = Str_dup(current->name); |
| m->next = g->members; |
| g->members = m; |
| } |
| |
| |
| /* |
| * Add a dependant entry to the current service dependant list |
| * |
| */ |
| static void adddependant(char *dependant) { |
| Dependant_T d; |
| |
| ASSERT(dependant); |
| |
| NEW(d); |
| |
| if (current->dependantlist != NULL) |
| d->next = current->dependantlist; |
| |
| d->dependant = dependant; |
| current->dependantlist = d; |
| |
| } |
| |
| |
| /* |
| * Add the given mailaddress with the appropriate alert notification |
| * values and mail attributes to the given mailinglist. |
| */ |
| static void addmail(char *mailto, Mail_T f, Mail_T *l) { |
| Mail_T m; |
| |
| ASSERT(mailto); |
| |
| NEW(m); |
| m->to = mailto; |
| m->from = f->from; |
| m->subject = f->subject; |
| m->message = f->message; |
| m->events = f->events; |
| m->reminder = f->reminder; |
| |
| m->next = *l; |
| *l = m; |
| |
| reset_mailset(); |
| } |
| |
| |
| /* |
| * Add the given portset to the current service's portlist |
| */ |
| static void addport(Port_T port) { |
| Port_T p; |
| |
| ASSERT(port); |
| |
| NEW(p); |
| p->port = port->port; |
| p->type = port->type; |
| p->socket = port->socket; |
| p->family = port->family; |
| p->action = port->action; |
| p->timeout = port->timeout; |
| p->retry = port->retry; |
| p->request = port->request; |
| p->generic = port->generic; |
| p->protocol = port->protocol; |
| p->pathname = port->pathname; |
| p->hostname = port->hostname; |
| p->url_request = port->url_request; |
| p->request_checksum = port->request_checksum; |
| p->request_hostheader = port->request_hostheader; |
| memcpy(&p->ApacheStatus, &port->ApacheStatus, sizeof(struct apache_status)); |
| |
| if (p->request_checksum) { |
| cleanup_hash_string(p->request_checksum); |
| if (strlen(p->request_checksum) == 32) |
| p->request_hashtype = HASH_MD5; |
| else if (strlen(p->request_checksum) == 40) |
| p->request_hashtype = HASH_SHA1; |
| else |
| yyerror2("invalid checksum [%s]", p->request_checksum); |
| } else |
| p->request_hashtype = 0; |
| |
| if (port->SSL.use_ssl == TRUE) { |
| if (!have_ssl()) { |
| yyerror("ssl check cannot be activated. SSL is not supported"); |
| } else { |
| if (port->SSL.certmd5 != NULL) { |
| p->SSL.certmd5 = port->SSL.certmd5; |
| cleanup_hash_string(p->SSL.certmd5); |
| } |
| p->SSL.use_ssl = TRUE; |
| p->SSL.version = port->SSL.version; |
| } |
| } |
| p->maxforward = port->maxforward; |
| p->next = current->portlist; |
| current->portlist = p; |
| |
| reset_portset(); |
| |
| } |
| |
| |
| /* |
| * Add a new resource object to the current service resource list |
| */ |
| static void addresource(Resource_T rr) { |
| Resource_T r; |
| |
| ASSERT(rr); |
| |
| NEW(r); |
| if (! Run.doprocess) |
| yyerror("Cannot activate service check. The process status engine was disabled. On certain systems you must run monit as root to utilize this feature)\n"); |
| r->resource_id = rr->resource_id; |
| r->limit = rr->limit; |
| r->action = rr->action; |
| r->operator = rr->operator; |
| r->next = current->resourcelist; |
| |
| current->resourcelist = r; |
| reset_resourceset(); |
| } |
| |
| |
| /* |
| * Add a new file object to the current service timestamp list |
| */ |
| static void addtimestamp(Timestamp_T ts, int notime) { |
| Timestamp_T t; |
| |
| ASSERT(ts); |
| |
| NEW(t); |
| t->operator = ts->operator; |
| t->time = ts->time; |
| t->action = ts->action; |
| t->test_changes = ts->test_changes; |
| |
| if (t->test_changes || notime) { |
| if (! file_exist(current->path)) { |
| DEBUG("%s: Debug: the path '%s' used in the TIMESTAMP statement refer to a non-existing object\n", prog, current->path); |
| } else if (!(t->timestamp = file_getTimestamp(current->path, S_IFDIR|S_IFREG))) { |
| yyerror2("cannot get the timestamp for '%s'", current->path); |
| } |
| } |
| |
| t->next = current->timestamplist; |
| current->timestamplist = t; |
| |
| reset_timestampset(); |
| } |
| |
| |
| /* |
| * Add a new object to the current service actionrate list |
| */ |
| static void addactionrate(ActionRate_T ar) { |
| ActionRate_T a; |
| |
| ASSERT(ar); |
| |
| if (ar->count > ar->cycle) |
| yyerror2("the number of restarts must be less than poll cycles"); |
| if (ar->count <= 0 || ar->cycle <= 0) |
| yyerror2("zero or negative values not allowed in a action rate statement"); |
| |
| NEW(a); |
| a->count = ar->count; |
| a->cycle = ar->cycle; |
| a->action = ar->action; |
| |
| a->next = current->actionratelist; |
| current->actionratelist = a; |
| |
| reset_actionrateset(); |
| } |
| |
| |
| |
| /* |
| * Add a new Size object to the current service size list |
| */ |
| static void addsize(Size_T ss) { |
| Size_T s; |
| struct stat buf; |
| |
| ASSERT(ss); |
| |
| NEW(s); |
| s->operator = ss->operator; |
| s->size = ss->size; |
| s->action = ss->action; |
| s->test_changes = ss->test_changes; |
| /* Get the initial size for future comparision, if the file exists */ |
| if (s->test_changes) { |
| s->test_changes_ok = !stat(current->path, &buf); |
| if (s->test_changes_ok) |
| s->size = (unsigned long long)buf.st_size; |
| } |
| |
| s->next = current->sizelist; |
| current->sizelist = s; |
| |
| reset_sizeset(); |
| } |
| |
| |
| /* |
| * Add a new Uptime object to the current service uptime list |
| */ |
| static void adduptime(Uptime_T uu) { |
| Uptime_T u; |
| |
| ASSERT(uu); |
| |
| NEW(u); |
| u->operator = uu->operator; |
| u->uptime = uu->uptime; |
| u->action = uu->action; |
| |
| u->next = current->uptimelist; |
| current->uptimelist = u; |
| |
| reset_uptimeset(); |
| } |
| |
| |
| /* |
| * Set Checksum object in the current service |
| */ |
| static void addchecksum(Checksum_T cs) { |
| |
| int len; |
| Checksum_T c; |
| |
| ASSERT(cs); |
| |
| cs->test_changes_ok = TRUE; |
| |
| if (! *cs->hash) { |
| if (cs->type == HASH_UNKNOWN) |
| cs->type = DEFAULT_HASH; |
| if ( !(Util_getChecksum(current->path, cs->type, cs->hash, sizeof(cs->hash)))) { |
| if (cs->test_changes == TRUE) { |
| /* If the file doesn't exist and we're checking for checksum changes, set dummy value */ |
| cs->test_changes_ok = FALSE; |
| snprintf(cs->hash, sizeof(cs->hash), "00000000000000000000000000000000"); |
| } else { |
| yyerror2("cannot compute a checksum for file %s", current->path); |
| reset_checksumset(); |
| return; |
| } |
| } |
| } |
| |
| len = cleanup_hash_string(cs->hash); |
| |
| if (cs->type == HASH_UNKNOWN) { |
| if (len == 32) { |
| cs->type = HASH_MD5; |
| } else if (len == 40) { |
| cs->type = HASH_SHA1; |
| } else { |
| yyerror2("invalid checksum [%s] for file %s", cs->hash, current->path); |
| reset_checksumset(); |
| return; |
| } |
| } else if (( cs->type == HASH_MD5 && len!=32 ) || ( cs->type == HASH_SHA1 && len != 40 )) { |
| yyerror2("invalid checksum [%s] for file %s", cs->hash, current->path); |
| reset_checksumset(); |
| return; |
| } |
| |
| NEW(c); |
| |
| c->type = cs->type; |
| c->test_changes = cs->test_changes; |
| c->test_changes_ok = cs->test_changes_ok; |
| c->action = cs->action; |
| snprintf(c->hash, sizeof(c->hash), "%s", cs->hash); |
| |
| current->checksum = c; |
| |
| reset_checksumset(); |
| |
| } |
| |
| |
| /* |
| * Set Perm object in the current service |
| */ |
| static void addperm(Perm_T ps) { |
| Perm_T p; |
| |
| ASSERT(ps); |
| |
| NEW(p); |
| p->perm = ps->perm; |
| p->action = ps->action; |
| current->perm = p; |
| reset_permset(); |
| |
| } |
| |
| |
| static void appendmatch(Match_T *list, Match_T item) { |
| if (*list) { |
| /* Find the end of the list (keep the same patterns order as in the config file) */ |
| Match_T last; |
| for (last = *list; last->next; last = last->next) |
| ; |
| last->next = item; |
| } else { |
| *list = item; |
| } |
| } |
| |
| |
| /* |
| * Set Match object in the current service |
| */ |
| static void addmatch(Match_T ms, int actionnumber, int linenumber) { |
| Match_T m; |
| int reg_return; |
| |
| ASSERT(ms); |
| |
| NEW(m); |
| #ifdef HAVE_REGEX_H |
| NEW(m->regex_comp); |
| #endif |
| |
| m->match_string = ms->match_string; |
| m->match_path = ms->match_path ? Str_dup(ms->match_path) : NULL; |
| m->action = ms->action; |
| m->not = ms->not; |
| m->ignore = ms->ignore; |
| m->next = NULL; |
| |
| addeventaction(&(m->action), actionnumber, ACTION_IGNORE); |
| |
| #ifdef HAVE_REGEX_H |
| reg_return = regcomp(m->regex_comp, ms->match_string, REG_NOSUB|REG_EXTENDED); |
| |
| if (reg_return != 0) { |
| char errbuf[STRLEN]; |
| regerror(reg_return, ms->regex_comp, errbuf, STRLEN); |
| if (m->match_path != NULL) |
| yyerror2("regex parsing error:%s on line %i of", errbuf, linenumber); |
| else |
| yyerror2("regex parsing error:%s", errbuf); |
| } |
| #endif |
| appendmatch(m->ignore ? ¤t->matchignorelist : ¤t->matchlist, m); |
| } |
| |
| |
| static void addmatchpath(Match_T ms, int actionnumber) { |
| |
| FILE *handle; |
| command_t savecommand = NULL; |
| char buf[2048]; |
| int linenumber = 0; |
| |
| ASSERT(ms->match_path); |
| |
| handle = fopen(ms->match_path, "r"); |
| if (handle == NULL) { |
| yyerror2("cannot read regex match file (%s)", ms->match_path); |
| return; |
| } |
| |
| while (!feof(handle)) { |
| size_t len; |
| |
| linenumber++; |
| |
| if (! fgets(buf, 2048, handle)) |
| continue; |
| |
| len = strlen(buf); |
| |
| if (len == 0 || buf[0] == '\n') |
| continue; |
| |
| if (buf[len-1] == '\n') |
| buf[len-1] = 0; |
| |
| ms->match_string = Str_dup(buf); |
| |
| /* The addeventaction() called from addmatch() will reset the |
| * command1 to NULL, but we need to duplicate the command for |
| * each line, thus need to save it here */ |
| if (actionnumber == ACTION_EXEC) { |
| if (command1 == NULL) { |
| ASSERT(savecommand); |
| command1 = savecommand; |
| } |
| savecommand = copycommand(command1); |
| } |
| |
| addmatch(ms, actionnumber, linenumber); |
| } |
| |
| if (actionnumber == ACTION_EXEC && savecommand) |
| gccmd(&savecommand); |
| |
| fclose(handle); |
| } |
| |
| |
| /* |
| * Set program object in the current service |
| */ |
| static void addprogram(Program_T program) { |
| Program_T p; |
| ASSERT(program); |
| NEW(p); |
| p->return_value = program->return_value; |
| p->operator = program->operator; |
| p->action = program->action; |
| p->timeout = program->timeout; |
| p->C = program->C; |
| current->program = p; |
| reset_programset(); |
| } |
| |
| |
| /* |
| * Set Uid object in the current service |
| */ |
| static void adduid(Uid_T us) { |
| Uid_T u; |
| |
| ASSERT(us); |
| |
| NEW(u); |
| u->uid = us->uid; |
| u->action = us->action; |
| current->uid = u; |
| reset_uidset(); |
| } |
| |
| |
| /* |
| * Set Gid object in the current service |
| */ |
| static void addgid(Gid_T gs) { |
| Gid_T g; |
| |
| ASSERT(gs); |
| |
| NEW(g); |
| g->gid = gs->gid; |
| g->action = gs->action; |
| current->gid = g; |
| reset_gidset(); |
| } |
| |
| |
| /* |
| * Add a new filesystem to the current service's filesystem list |
| */ |
| static void addfilesystem(Filesystem_T ds) { |
| Filesystem_T dev; |
| |
| ASSERT(ds); |
| |
| NEW(dev); |
| dev->resource = ds->resource; |
| dev->operator = ds->operator; |
| dev->limit_absolute = ds->limit_absolute; |
| dev->limit_percent = ds->limit_percent; |
| dev->action = ds->action; |
| |
| dev->next = current->filesystemlist; |
| current->filesystemlist = dev; |
| |
| reset_filesystemset(); |
| |
| } |
| |
| |
| /* |
| * Add a new icmp object to the current service's icmp list |
| */ |
| static void addicmp(Icmp_T is) { |
| Icmp_T icmp; |
| |
| ASSERT(is); |
| |
| NEW(icmp); |
| icmp->type = is->type; |
| icmp->count = is->count; |
| icmp->timeout = is->timeout; |
| icmp->action = is->action; |
| icmp->is_available = FALSE; |
| icmp->response = -1; |
| |
| icmp->next = current->icmplist; |
| current->icmplist = icmp; |
| |
| reset_icmpset(); |
| } |
| |
| |
| /* |
| * Set EventAction object |
| */ |
| static void addeventaction(EventAction_T *_ea, int failed, int succeeded) { |
| EventAction_T ea; |
| |
| ASSERT(_ea); |
| |
| NEW(ea); |
| NEW(ea->failed); |
| NEW(ea->succeeded); |
| |
| ea->failed->id = failed; |
| ea->failed->count = rate1.count; |
| ea->failed->cycles = rate1.cycles; |
| if (failed == ACTION_EXEC) { |
| ASSERT(command1); |
| ea->failed->exec = command1; |
| command1 = NULL; |
| } |
| |
| ea->succeeded->id = succeeded; |
| ea->succeeded->count = rate2.count; |
| ea->succeeded->cycles = rate2.cycles; |
| if (succeeded == ACTION_EXEC) { |
| ASSERT(command2); |
| ea->succeeded->exec = command2; |
| command2 = NULL; |
| } |
| *_ea = ea; |
| reset_rateset(); |
| } |
| |
| |
| /* |
| * Redefine EventAction object (used for default action overloading) |
| */ |
| static void seteventaction(EventAction_T *_ea, int failed, int succeeded) { |
| EventAction_T ea = *_ea; |
| |
| ASSERT(ea); |
| ASSERT(ea->failed); |
| ASSERT(ea->succeeded); |
| |
| ea->failed->id = failed; |
| ea->failed->count = rate1.count; |
| ea->failed->cycles = rate1.cycles; |
| if (failed == ACTION_EXEC) { |
| ASSERT(command1); |
| ea->failed->exec = command1; |
| command1 = NULL; |
| } |
| |
| ea->succeeded->id = succeeded; |
| ea->succeeded->count = rate2.count; |
| ea->succeeded->cycles = rate2.cycles; |
| if (succeeded == ACTION_EXEC) { |
| ASSERT(command2); |
| ea->succeeded->exec = command2; |
| command2 = NULL; |
| } |
| } |
| |
| |
| /* |
| * Add a generic protocol handler to |
| */ |
| static void addgeneric(Port_T port, char *send, char *expect) { |
| Generic_T g = port->generic; |
| |
| if (g == NULL) { |
| NEW(g); |
| port->generic = g; |
| } else { |
| while (g->next != NULL) |
| g = g->next; |
| NEW(g->next); |
| g = g->next; |
| } |
| |
| if (send != NULL) { |
| g->send = Str_dup(send); |
| g->expect = NULL; |
| } else if (expect != NULL) { |
| #ifdef HAVE_REGEX_H |
| |
| int reg_return; |
| NEW(g->expect); |
| reg_return = regcomp(g->expect, expect, REG_NOSUB|REG_EXTENDED); |
| if (reg_return != 0) { |
| char errbuf[STRLEN]; |
| regerror(reg_return, g->expect, errbuf, STRLEN); |
| yyerror2("regex parsing error:%s", errbuf); |
| } |
| #else |
| g->expect = Str_dup(expect); |
| #endif |
| g->send = NULL; |
| } |
| } |
| |
| |
| /* |
| * Add the current command object to the current service object's |
| * start or stop program. |
| */ |
| static void addcommand(int what, unsigned timeout) { |
| |
| switch(what) { |
| case START: current->start = command; break; |
| case STOP: current->stop = command; break; |
| case RESTART: current->restart = command; break; |
| } |
| |
| command->timeout = timeout; |
| |
| command = NULL; |
| |
| } |
| |
| |
| /* |
| * Add a new argument to the argument list |
| */ |
| static void addargument(char *argument) { |
| |
| ASSERT(argument); |
| |
| if (! command) { |
| |
| NEW(command); |
| check_exec(argument); |
| |
| } |
| |
| command->arg[command->length++] = argument; |
| command->arg[command->length] = NULL; |
| |
| if (command->length >= ARGMAX) |
| yyerror("exceeded maximum number of program arguments"); |
| |
| } |
| |
| |
| /* |
| * Setup a url request for the current port object |
| */ |
| static void prepare_urlrequest(URL_T U) { |
| |
| ASSERT(U); |
| |
| portset.protocol = Protocol_get(Protocol_HTTP); |
| |
| if (urlrequest == NULL) |
| NEW(urlrequest); |
| urlrequest->url = U; |
| portset.hostname = Str_dup(U->hostname); |
| check_hostname(portset.hostname); |
| portset.port = U->port; |
| portset.url_request = urlrequest; |
| portset.type = SOCK_STREAM; |
| portset.request = Str_cat("%s%s%s", U->path, U->query ? "?" : "", U->query ? U->query : ""); |
| /* Only the HTTP protocol is supported for URLs. |
| See also the lexer if this is to be changed in |
| the future */ |
| portset.protocol = Protocol_get(Protocol_HTTP); |
| if (IS(U->protocol, "https")) |
| portset.SSL.use_ssl = TRUE; |
| |
| } |
| |
| |
| /* |
| * Set the url request for a port |
| */ |
| static void seturlrequest(int operator, char *regex) { |
| |
| ASSERT(regex); |
| |
| if (! urlrequest) |
| NEW(urlrequest); |
| urlrequest->operator = operator; |
| #ifdef HAVE_REGEX_H |
| { |
| int reg_return; |
| NEW(urlrequest->regex); |
| reg_return = regcomp(urlrequest->regex, regex, REG_NOSUB|REG_EXTENDED); |
| if (reg_return != 0) { |
| char errbuf[STRLEN]; |
| regerror(reg_return, urlrequest->regex, errbuf, STRLEN); |
| yyerror2("regex parsing error: %s", errbuf); |
| } |
| } |
| #else |
| urlrequest->regex = Str_dup(regex); |
| #endif |
| |
| } |
| |
| |
| /* |
| * Add a new data recipient server to the mmonit server list |
| */ |
| static void addmmonit(URL_T url, int timeout, int sslversion, char *certmd5) { |
| Mmonit_T c; |
| |
| ASSERT(url); |
| |
| NEW(c); |
| c->url = url; |
| if (!strcmp(c->url->protocol, "https")) { |
| if (!have_ssl()) { |
| yyerror("ssl check cannot be activated. SSL is not supported"); |
| } else { |
| c->ssl.use_ssl = TRUE; |
| c->ssl.version = (sslversion == SSL_VERSION_NONE) ? SSL_VERSION_AUTO : sslversion; |
| if (certmd5) { |
| c->ssl.certmd5 = certmd5; |
| cleanup_hash_string(c->ssl.certmd5); |
| } |
| } |
| } |
| c->timeout = timeout; |
| c->next = NULL; |
| |
| if (Run.mmonits) { |
| Mmonit_T C; |
| for (C = Run.mmonits; C->next; C = C->next) |
| /* Empty */ ; |
| C->next = c; |
| } else { |
| Run.mmonits = c; |
| } |
| } |
| |
| |
| /* |
| * Add a new smtp server to the mail server list |
| */ |
| static void addmailserver(MailServer_T mailserver) { |
| |
| MailServer_T s; |
| |
| ASSERT(mailserver->host); |
| |
| NEW(s); |
| s->host = mailserver->host; |
| s->port = mailserver->port; |
| s->username = mailserver->username; |
| s->password = mailserver->password; |
| s->ssl.use_ssl = mailserver->ssl.use_ssl; |
| s->ssl.version = mailserver->ssl.version; |
| s->ssl.certmd5 = mailserver->ssl.certmd5; |
| |
| s->next = NULL; |
| |
| if (Run.mailservers) { |
| MailServer_T l; |
| for (l = Run.mailservers; l->next; l = l->next) /* empty */; |
| l->next = s; |
| } else { |
| Run.mailservers = s; |
| } |
| |
| reset_mailserverset(); |
| } |
| |
| |
| /* |
| * Return uid if found on the system. If the parameter user is NULL |
| * the uid parameter is used for looking up the user id on the system, |
| * otherwise the user parameter is used. |
| */ |
| static uid_t get_uid(char *user, uid_t uid) { |
| struct passwd *pwd; |
| |
| if (user) { |
| pwd = getpwnam(user); |
| |
| if (pwd == NULL) { |
| yyerror2("requested user not found on the system"); |
| return(0); |
| } |
| |
| } else { |
| |
| if ( (pwd = getpwuid(uid)) == NULL ) { |
| yyerror2("requested uid not found on the system"); |
| return(0); |
| } |
| } |
| |
| return(pwd->pw_uid); |
| |
| } |
| |
| |
| /* |
| * Return gid if found on the system. If the parameter group is NULL |
| * the gid parameter is used for looking up the group id on the system, |
| * otherwise the group parameter is used. |
| */ |
| static gid_t get_gid(char *group, gid_t gid) { |
| struct group *grd; |
| |
| if (group) { |
| grd = getgrnam(group); |
| |
| if (grd == NULL) { |
| yyerror2("requested group not found on the system"); |
| return(0); |
| } |
| |
| } else { |
| |
| if ( (grd = getgrgid(gid)) == NULL ) { |
| yyerror2("requested gid not found on the system"); |
| return(0); |
| } |
| |
| } |
| |
| return(grd->gr_gid); |
| |
| } |
| |
| |
| /* |
| * Add a new user id to the current command object. |
| */ |
| static void addeuid(uid_t uid) { |
| if (!getuid()) { |
| command->has_uid = TRUE; |
| command->uid = uid; |
| } else |
| yyerror("uid statement requires root privileges"); |
| } |
| |
| |
| /* |
| * Add a new group id to the current command object. |
| */ |
| static void addegid(gid_t gid) { |
| if (!getuid()) { |
| command->has_gid = TRUE; |
| command->gid = gid; |
| } else |
| yyerror("gid statement requires root privileges"); |
| } |
| |
| |
| /* |
| * Reset the logfile if changed |
| */ |
| static void setlogfile(char *logfile) { |
| if (Run.logfile) { |
| if (IS(Run.logfile, logfile)) { |
| FREE(logfile); |
| return; |
| } else |
| FREE(Run.logfile); |
| } |
| Run.logfile = logfile; |
| } |
| |
| |
| /* |
| * Reset the pidfile if changed |
| */ |
| static void setpidfile(char *pidfile) { |
| if (Run.pidfile) { |
| if (IS(Run.pidfile, pidfile)) { |
| FREE(pidfile); |
| return; |
| } else |
| FREE(Run.pidfile); |
| } |
| Run.pidfile = pidfile; |
| } |
| |
| |
| /* |
| * Read a apache htpasswd file and add credentials found for username |
| */ |
| static void addhtpasswdentry(char *filename, char *username, int dtype) { |
| char *ht_username = NULL; |
| char *ht_passwd = NULL; |
| char buf[STRLEN]; |
| FILE *handle = NULL; |
| int credentials_added = 0; |
| |
| ASSERT(filename); |
| |
| handle = fopen(filename, "r"); |
| |
| if ( handle == NULL ) { |
| if (username != NULL) |
| yyerror2("cannot read htpasswd (%s)", filename); |
| else |
| yyerror2("cannot read htpasswd", filename); |
| return; |
| } |
| |
| while (!feof(handle)) { |
| char *colonindex = NULL; |
| int i; |
| |
| if (! fgets(buf, STRLEN, handle)) |
| continue; |
| |
| /* strip trailing non visible characters */ |
| for (i = (int)strlen(buf)-1; i >= 0; i--) { |
| if ( buf[i] == ' ' || buf[i] == '\r' || buf[i] == '\n' || buf[i] == '\t' ) |
| buf[i] ='\0'; |
| <
|