diff options
Diffstat (limited to 'src/pmdas/sendmail')
-rw-r--r-- | src/pmdas/sendmail/GNUmakefile | 58 | ||||
-rw-r--r-- | src/pmdas/sendmail/Install | 27 | ||||
-rw-r--r-- | src/pmdas/sendmail/README | 50 | ||||
-rw-r--r-- | src/pmdas/sendmail/Remove | 38 | ||||
-rw-r--r-- | src/pmdas/sendmail/Sendmail.pmchart | 10 | ||||
-rw-r--r-- | src/pmdas/sendmail/help | 73 | ||||
-rw-r--r-- | src/pmdas/sendmail/pmns | 39 | ||||
-rw-r--r-- | src/pmdas/sendmail/root | 10 | ||||
-rw-r--r-- | src/pmdas/sendmail/sendmail.c | 524 |
9 files changed, 829 insertions, 0 deletions
diff --git a/src/pmdas/sendmail/GNUmakefile b/src/pmdas/sendmail/GNUmakefile new file mode 100644 index 0000000..171c7c0 --- /dev/null +++ b/src/pmdas/sendmail/GNUmakefile @@ -0,0 +1,58 @@ +# +# Copyright (c) 2000-2001,2004 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 2 of the License, or (at your +# option) any later version. +# +# 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. +# + +TOPDIR = ../../.. +include $(TOPDIR)/src/include/builddefs + +IAM = sendmail +DOMAIN = SENDMAIL +CMDTARGET = $(IAM)$(EXECSUFFIX) +LIBTARGET = pmda_$(IAM).$(DSOSUFFIX) +CFILES = sendmail.c +SCRIPTS = Install Remove +DFILES = README +LSRCFILES= $(SCRIPTS) pmns help root Sendmail.pmchart $(DFILES) + +VERSION_SCRIPT = exports +PMDAINIT = $(IAM)_init +PMDADIR = $(PCP_PMDAS_DIR)/$(IAM) +PMCHART = $(PCP_VAR_DIR)/config/pmchart + +LDIRT = domain.h *.o $(IAM).log $(LIBTARGET) $(CMDTARGET) $(VERSION_SCRIPT) +LLDLIBS = $(PCP_PMDALIB) +LCFLAGS = $(INVISIBILITY) + +default_pcp default: $(CMDTARGET) $(LIBTARGET) + +include $(BUILDRULES) + +install install_pcp: default + $(INSTALL) -m 755 -d $(PMDADIR) + $(INSTALL) -m 755 $(LIBTARGET) $(PMDADIR)/$(LIBTARGET) + $(INSTALL) -m 755 $(CMDTARGET) $(PMDADIR)/pmda$(IAM)$(EXECSUFFIX) + $(INSTALL) -m 755 $(SCRIPTS) $(PMDADIR) + $(INSTALL) -m 644 $(DFILES) pmns help root domain.h $(PMDADIR) + $(INSTALL) -m 644 Sendmail.pmchart $(PMCHART)/Sendmail + +$(CMDTARGET): $(OBJECTS) + +$(LIBTARGET): $(OBJECTS) $(VERSION_SCRIPT) + +sendmail.o: domain.h + +domain.h: ../../pmns/stdpmid + $(DOMAIN_MAKERULE) + +$(VERSION_SCRIPT): + $(VERSION_SCRIPT_MAKERULE) diff --git a/src/pmdas/sendmail/Install b/src/pmdas/sendmail/Install new file mode 100644 index 0000000..5ce3c57 --- /dev/null +++ b/src/pmdas/sendmail/Install @@ -0,0 +1,27 @@ +#! /bin/sh +# +# Copyright (c) 1997 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 2 of the License, or (at your +# option) any later version. +# +# 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. +# +# Install the sendmail PMDA and/or PMNS +# + +. $PCP_DIR/etc/pcp.env +. $PCP_SHARE_DIR/lib/pmdaproc.sh + +iam=sendmail +pmda_interface=3 +forced_restart=false + +pmdaSetup +pmdaInstall +exit 0 diff --git a/src/pmdas/sendmail/README b/src/pmdas/sendmail/README new file mode 100644 index 0000000..1a89adc --- /dev/null +++ b/src/pmdas/sendmail/README @@ -0,0 +1,50 @@ +Sendmail PMDA +============= + +Export information from the sendmail statistics file. + +Metrics +======= + +The file ./help contains descriptions for all of the metrics exported +by this PMDA. + +Once the PMDA has been installed, the following command will list all +the available metrics and their explanatory "help" text: + + $ pminfo -fT sendmail + +Installation +============ + + + # cd $PCP_PMDAS_DIR/sendmail + + + Check that there is no clash in the Performance Metrics Domain + defined in ./domain.h and the other PMDAs currently in use (see + $PCP_PMCDCONF_PATH). If there is, edit ./domain.h to choose another + domain number. + + + Then simply use + + # ./Install + + and choose both the "collector" and "monitor" installation + configuration options. + + Everything else is automated. + +De-installation +=============== + + + Simply use + + # cd $PCP_PMDAS_DIR/sendmail + # ./Remove + +Troubleshooting +=============== + + + After installing or restarting the agent, the PMCD log file + ($PCP_LOG_DIR/pmcd/pmcd.log) and the PMDA log file + ($PCP_LOG_DIR/pmcd/sendmail.log) should be checked for any warnings + or errors. diff --git a/src/pmdas/sendmail/Remove b/src/pmdas/sendmail/Remove new file mode 100644 index 0000000..c0275d7 --- /dev/null +++ b/src/pmdas/sendmail/Remove @@ -0,0 +1,38 @@ +#! /bin/sh +# +# Copyright (c) 1997 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 2 of the License, or (at your +# option) any later version. +# +# 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 General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +# +# Remove the sendmail PMDA +# + +# Get standard environment +. $PCP_DIR/etc/pcp.env + +# Get the common procedures and variable assignments +# +. $PCP_SHARE_DIR/lib/pmdaproc.sh + +# The name of the PMDA +# +iam=sendmail + +# Do it +# +pmdaSetup +pmdaRemove + +exit 0 diff --git a/src/pmdas/sendmail/Sendmail.pmchart b/src/pmdas/sendmail/Sendmail.pmchart new file mode 100644 index 0000000..446decf --- /dev/null +++ b/src/pmdas/sendmail/Sendmail.pmchart @@ -0,0 +1,10 @@ +#pmchart +Version 2.0 host dynamic + +Chart Style plot + Plot Color #137bfe Host * Metric sendmail.total.bytes_from + Plot Color #fefa1a Host * Metric sendmail.total.bytes_to +Chart Style plot + Plot Color #1e1cfe Host * Metric sendmail.total.msgs_from + Plot Color #fe9913 Host * Metric sendmail.total.msgs_to + diff --git a/src/pmdas/sendmail/help b/src/pmdas/sendmail/help new file mode 100644 index 0000000..593469d --- /dev/null +++ b/src/pmdas/sendmail/help @@ -0,0 +1,73 @@ +# +# Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 2 of the License, or (at your +# option) any later version. +# +# 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 General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +# +# sendmail PMDA help file in the ASCII format +# +# lines beginning with a # are ignored +# lines beginning @ introduce a new entry of the form +# @ metric_name oneline-text +# help test goes +# here over multiple lines +# ... +# +# the metric_name is decoded against the default PMNS -- as a special case, +# a name of the form NNN.MM (for numeric NNN and MM) is interpreted as an +# instance domain identification, and the text describes the instance domain +# +# blank lines before the @ line are ignored +# + +@ SENDMAIL.0 Instance domain "mailer" for sendmail PMDA +The mailers 0 (prog), 1 (*file*), and 2 (*include*) are fixed. Other +mailers are defined by the order of any additional "M" records in the +sendmail.cf file. + +@ sendmail.start_date Date on which sendmail stats file was created +The date in ctime(2) format on which the sendmail statistics file was +first created. All statistics are cumulative from that time. + +The sendmail statistics file is /var/sendmailst by default, but may be +redefined by an "OS" or "O StatusFile" record in the sendmail.cf file. + +@ sendmail.permailer.msgs_from Messages received from each mailer +Count of messages received from each "mailer" defined in sendmail's +configuration file (/etc/sendmail.cf). + +@ sendmail.permailer.bytes_from Kbytes received from each mailer +Count of Kbytes summed over all messages received from each "mailer" +defined in sendmail's configuration file (/etc/sendmail.cf). + +@ sendmail.permailer.msgs_to Messages sent to each mailer +Count of messages sent to each "mailer" defined in sendmail's +configuration file (/etc/sendmail.cf). + +@ sendmail.permailer.bytes_to Kbytes sent to each mailer +Count of Kbytes summed over all messages sent to each "mailer" defined +in sendmail's configuration file (/etc/sendmail.cf). + +@ sendmail.total.msgs_from Messages received from all mailers +Count of messages received by sendmail. + +@ sendmail.total.bytes_from Kbytes received from all mailers +Count of Kbytes summed over all messages received by sendmail. + +@ sendmail.total.msgs_to Messages sent to all mailers +Count of messages sent by sendmail. + +@ sendmail.total.bytes_to Kbytes sent to all mailers +Count of Kbytes summed over all messages sent by sendmail. + diff --git a/src/pmdas/sendmail/pmns b/src/pmdas/sendmail/pmns new file mode 100644 index 0000000..856448f --- /dev/null +++ b/src/pmdas/sendmail/pmns @@ -0,0 +1,39 @@ +/* + * Metrics for sendmail PMDA + * + * Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * 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 General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +sendmail { + start_date SENDMAIL:0:0 + permailer + total +} + +sendmail.permailer { + msgs_from SENDMAIL:1:0 + bytes_from SENDMAIL:1:1 + msgs_to SENDMAIL:1:2 + bytes_to SENDMAIL:1:3 +} + +sendmail.total { + msgs_from SENDMAIL:2:0 + bytes_from SENDMAIL:2:1 + msgs_to SENDMAIL:2:2 + bytes_to SENDMAIL:2:3 +} diff --git a/src/pmdas/sendmail/root b/src/pmdas/sendmail/root new file mode 100644 index 0000000..ead8f5a --- /dev/null +++ b/src/pmdas/sendmail/root @@ -0,0 +1,10 @@ +/* + * fake "root" for validating the local PMNS subtree + */ + +#include <stdpmid> + +root { sendmail } + +#include "pmns" + diff --git a/src/pmdas/sendmail/sendmail.c b/src/pmdas/sendmail/sendmail.c new file mode 100644 index 0000000..7b2b542 --- /dev/null +++ b/src/pmdas/sendmail/sendmail.c @@ -0,0 +1,524 @@ +/* + * Sendmail PMDA + * + * Copyright (c) 1995-2000,2003 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * 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. + */ + +#include <ctype.h> +#include "pmapi.h" +#include "impl.h" +#include "pmda.h" +#include "domain.h" +#include <sys/stat.h> + +/* + * Sendmail PMDA + * + * This PMDA uses the statistics file that sendmail optionally maintains + * -- see "OS<file>" or "O StatusFile=<file>" in sendmail.cf and sendmail(1) + * + * This file (defaults to /var/sendmail.st) must be created before sendmail + * will update any statistics. + */ + +/* + * list of instances + */ + +static pmdaIndom indomtab[] = { +#define MAILER_INDOM 0 + { MAILER_INDOM, 0, NULL }, +}; + +static char *statsfile = "/var/sendmail.st"; +static char *username; +static int nmailer; +static void *ptr; +static struct stat laststatbuf; +static time_t *start_date; +static __uint32_t *msgs_from; +static __uint32_t *kbytes_from; +static __uint32_t *msgs_to; +static __uint32_t *kbytes_to; + +static pmdaMetric metrictab[] = { +/* start_date */ + { NULL, + { PMDA_PMID(0,0), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_DISCRETE, + PMDA_PMUNITS(0,0,0,0,0,0) }, }, +/* permailer.msgs_from */ + { NULL, + { PMDA_PMID(1,0), PM_TYPE_U32, MAILER_INDOM, PM_SEM_COUNTER, + PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, +/* permailer.bytes_from */ + { NULL, + { PMDA_PMID(1,1), PM_TYPE_U32, MAILER_INDOM, PM_SEM_COUNTER, + PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, +/* permailer.msgs_to */ + { NULL, + { PMDA_PMID(1,2), PM_TYPE_U32, MAILER_INDOM, PM_SEM_COUNTER, + PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, +/* permailer.bytes_to */ + { NULL, + { PMDA_PMID(1,3), PM_TYPE_U32, MAILER_INDOM, PM_SEM_COUNTER, + PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, +/* total.msgs_from */ + { NULL, + { PMDA_PMID(2,0), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, + PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, +/* total.bytes_from */ + { NULL, + { PMDA_PMID(2,1), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, + PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, +/* total.msgs_to */ + { NULL, + { PMDA_PMID(2,2), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, + PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, +/* total.bytes_to */ + { NULL, + { PMDA_PMID(2,3), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, + PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, +}; + +static void +map_stats(void) +{ + struct stat statbuf; + static int fd; + + static int notified = 0; +#define MAPSTATS_NULL 0x01 +#define MAPSTATS_NOTV2STRUCT 0x02 +#define MAPSTATS_MAPFAIL 0x04 + + /* From mailstats.h in sendmail(1) 8.x... */ + struct smstat_s + { +#define MAXMAILERS 25 +#define STAT_VERSION 2 +#define STAT_MAGIC 0x1B1DE + int stat_magic; /* magic number */ + int stat_version; /* stat file version */ + time_t stat_itime; /* file initialization time */ + short stat_size; /* size of this structure */ + long stat_nf[MAXMAILERS]; /* # msgs from each mailer */ + long stat_bf[MAXMAILERS]; /* kbytes from each mailer */ + long stat_nt[MAXMAILERS]; /* # msgs to each mailer */ + long stat_bt[MAXMAILERS]; /* kbytes to each mailer */ + long stat_nr[MAXMAILERS]; /* # rejects by each mailer */ + long stat_nd[MAXMAILERS]; /* # discards by each mailer */ + } *smstat; + + +#ifdef PCP_DEBUG + if (pmDebug & DBG_TRACE_APPL0) { + fprintf(stderr, "%s: map_stats: Entering:\n", pmProgname); + fprintf(stderr, "%s: map_stats: Check: ptr = " PRINTF_P_PFX "%p\n", pmProgname, ptr); + fprintf(stderr, "%s: map_stats: Check: statsfile = " PRINTF_P_PFX "%p\n", pmProgname, statsfile); + if (statsfile != NULL) + fprintf(stderr, "%s: map_stats: = %s\n", pmProgname, statsfile); + } +#endif + + if (statsfile == NULL || stat(statsfile, &statbuf) < 0) { + /* if sendmail not collecting stats this is expected */ + if (ptr != NULL) { + /* must have gone away */ + __pmMemoryUnmap(ptr, laststatbuf.st_size); + close(fd); + ptr = NULL; + notified &= ~MAPSTATS_NOTV2STRUCT; +#ifdef PCP_DEBUG + if (pmDebug & DBG_TRACE_APPL0) { + fprintf(stderr, "%s: map_stats: (Maybe) stat() < 0; pmunmap() called\n", pmProgname); + } +#endif + } + return; + } + +#ifdef PCP_DEBUG + if (pmDebug & DBG_TRACE_APPL0) { + fprintf(stderr, "%s: map_stats: Check: statbuf.st_ino = %lu\n", pmProgname, (unsigned long)statbuf.st_ino); + fprintf(stderr, "%s: map_stats: Check: statbuf.st_dev = %lu\n", pmProgname, (unsigned long)statbuf.st_dev); + fprintf(stderr, "%s: map_stats: Check: laststatbuf.st_ino = %lu\n", pmProgname, (unsigned long)laststatbuf.st_ino); + fprintf(stderr, "%s: map_stats: Check: laststatbuf.st_dev = %lu\n", pmProgname, (unsigned long)laststatbuf.st_dev); + } +#endif + if (statbuf.st_ino != laststatbuf.st_ino || + statbuf.st_dev != laststatbuf.st_dev || + ptr == NULL) { + /* + * Not the same as the file we saw last time, or statsfile is + * not mapped into memory (because it was zero length). + * + * The file can change due to rotation or restarting sendmail... + * note the times (st_atim, st_mtim and st_ctim) are all expected + * to change as sendmail updates the file, hence we must use dev + * and ino. + * + * ino is guaranteed to change for different instances of the + * sendmail stats file, since a mmap()'d file is never closed + * until after it's munmap()'d. + */ + + if (ptr != NULL) { + __pmMemoryUnmap(ptr, laststatbuf.st_size); + close(fd); + ptr = NULL; + notified &= ~MAPSTATS_NOTV2STRUCT; +#ifdef PCP_DEBUG + if (pmDebug & DBG_TRACE_APPL0) { + fprintf(stderr, "%s: map_stats: statbuf.st_[dev|ido] changed; pmunmap() called\n", pmProgname); + } +#endif + } + + if ((fd = open(statsfile, O_RDONLY)) < 0) { + __pmNotifyErr(LOG_WARNING, "%s: map_stats: cannot open(\"%s\",...): %s", + pmProgname, statsfile, osstrerror()); + return; + } + ptr = __pmMemoryMap(fd, statbuf.st_size, 0); + if (ptr == NULL) { + if (!(notified & MAPSTATS_MAPFAIL)) { + __pmNotifyErr(LOG_ERR, "%s: map_stats: memmap of %s failed: %s", + pmProgname, statsfile, osstrerror()); + } + close(fd); + ptr = NULL; + notified |= MAPSTATS_MAPFAIL; + return; + } + + laststatbuf = statbuf; /* struct assignment */ + notified &= ~(MAPSTATS_NULL | MAPSTATS_MAPFAIL); +#ifdef PCP_DEBUG + if (pmDebug & DBG_TRACE_APPL0) { + fprintf(stderr, "%s: map_stats: mmap() called, succeeded\n", pmProgname); + } +#endif + + /* Check for a statistics file from sendmail(1) 8.x: */ + smstat = (struct smstat_s *)ptr; + if (smstat->stat_magic != STAT_MAGIC || + smstat->stat_version != STAT_VERSION) { + if (! (notified & MAPSTATS_NOTV2STRUCT)) { + __pmNotifyErr(LOG_WARNING, "%s: map_stats: cannot find magic number in file %s; assuming version 1 format", + pmProgname, statsfile); +#ifdef PCP_DEBUG + if (pmDebug & DBG_TRACE_APPL0) { + fprintf(stderr, "%s: map_stats: smstat_s contents:\n", pmProgname); + fprintf(stderr, "%s: map_stats: Version 2 format:\n", pmProgname); + fprintf(stderr, "%s: map_stats: Check: stat_magic = 0x%x\n", pmProgname, smstat->stat_magic); + fprintf(stderr, "%s: map_stats: Check: stat_version = 0x%x\n", pmProgname, smstat->stat_version); + fprintf(stderr, "%s: map_stats: Check: stat_itime = %s", pmProgname, ctime(&(smstat->stat_itime))); + fprintf(stderr, "%s: map_stats: Check: stat_size = %d\n", pmProgname, smstat->stat_size); + + /* We're being difficult here... using smstat_s the wrong way! */ + fprintf(stderr, "%s: map_stats: Version 1 format:\n", pmProgname); + fprintf(stderr, "%s: map_stats: Check: stat_itime = %s", pmProgname, ctime((time_t *)&(smstat->stat_magic))); + fprintf(stderr, "%s: map_stats: Check: stat_size = %d\n", pmProgname, *((short *)&(smstat->stat_version))); + } +#endif + notified |= MAPSTATS_NOTV2STRUCT; + } + + /* Could be older version of stats file... here is the original code + that dealt with that case */ + /* + * format of [older version] sendmail stats file: + * word[0] time_t file first created + * word[1] N/A + * word[2] .. word[K+2] msgs_from mailers 0 .. K + * word[K+3] .. word[2*K+3] kbytes_from mailers 0 .. K + * word[2*K+3] .. word[3*K+4] msgs_to mailers 0 .. K + * word[3*K+4] .. word[4*K+5] kbytes_to mailers 0 .. K + */ + nmailer = (statbuf.st_size - sizeof(__int32_t) - sizeof(__int32_t)) / (4 * sizeof(__uint32_t)); + msgs_from = &((__uint32_t *)ptr)[2]; + kbytes_from = &msgs_from[nmailer]; + msgs_to = &kbytes_from[nmailer]; + kbytes_to = &msgs_to[nmailer]; + start_date = (time_t *)ptr; + } + else { + /* Assign pointers to point to parts of the v2 struct */ + nmailer = ((char *)smstat->stat_bf - (char *)smstat->stat_nf) / sizeof(long); + msgs_from = (__uint32_t *)&(smstat->stat_nf); + kbytes_from = (__uint32_t *)&(smstat->stat_bf); + msgs_to = (__uint32_t *)&(smstat->stat_nt); + kbytes_to = (__uint32_t *)&(smstat->stat_bt); + start_date = &(smstat->stat_itime); + } + } +} + +/* + * logic here is similar to that used by mailstats(1) + */ +static void +do_sendmail_cf(void) +{ + FILE *fp; + char buf[MAXPATHLEN+20]; + char *bp; + int i; + int lineno = 0; + + if ((fp = fopen("/etc/sendmail.cf", "r")) == NULL) { + if ((fp = fopen("/etc/mail/sendmail.cf", "r")) == NULL) { + /* this is pretty serious! */ + nmailer = 0; + statsfile = NULL; +#ifdef PCP_DEBUG + if (pmDebug & DBG_TRACE_APPL0) + fprintf(stderr, "Warning: cannot find sendmail.cf, so no stats!\n"); +#endif + return; + } + } + + nmailer = 3; + indomtab[MAILER_INDOM].it_set = (pmdaInstid *)malloc(nmailer * sizeof(pmdaInstid)); + indomtab[MAILER_INDOM].it_set[0].i_inst = 0; + indomtab[MAILER_INDOM].it_set[0].i_name = "prog"; + indomtab[MAILER_INDOM].it_set[1].i_inst = 1; + indomtab[MAILER_INDOM].it_set[1].i_name = "*file*"; + indomtab[MAILER_INDOM].it_set[2].i_inst = 2; + indomtab[MAILER_INDOM].it_set[2].i_name = "*include*"; + + while (fgets(buf, sizeof(buf), fp) != NULL) { + lineno++; + bp = buf; + + if (*bp == 'M') { + /* mailer definition */ + bp++; + while (*bp != ',' && !isspace((int)*bp) && *bp != '\0') + bp++; + *bp = '\0'; + for (i = 0; i < nmailer; i++) { + if (strcmp(&buf[1], indomtab[MAILER_INDOM].it_set[i].i_name) == 0) + break; + } + if (i == nmailer) { + indomtab[MAILER_INDOM].it_set = (pmdaInstid *)realloc(indomtab[MAILER_INDOM].it_set, (nmailer+1) * sizeof(pmdaInstid)); + indomtab[MAILER_INDOM].it_set[nmailer].i_name = strdup(&buf[1]); + indomtab[MAILER_INDOM].it_set[nmailer].i_inst = nmailer; +#ifdef PCP_DEBUG + if (pmDebug & DBG_TRACE_APPL0) + fprintf(stderr, "sendmail.cf[%d]: mailer \"%s\" inst=%d\n", + lineno, &buf[1], nmailer); +#endif + nmailer++; + } + } + else if (*bp == 'O') { + char *tp; + + if (strncasecmp(++bp, " StatusFile", 11) == 0 && + !isalnum((int)bp[11])) { + bp = strchr(bp, '='); + if (bp == NULL) + continue; + while (isspace((int)*++bp)) + continue; + } + else if (*bp == 'S') + bp++; + else + continue; + + tp = bp++; + while (*bp && !isspace((int)*bp) && *bp != '#') + bp++; + *bp = '\0'; + + statsfile = strdup(tp); +#ifdef PCP_DEBUG + if (pmDebug & DBG_TRACE_APPL0) + fprintf(stderr, "sendmail.cf[%d]: statsfile \"%s\"\n", + lineno, tp); +#endif + } + } + fclose(fp); + + indomtab[MAILER_INDOM].it_numinst = nmailer; +} + +/* + * callback provided to pmdaFetch + */ +static int +sendmail_fetchCallBack(pmdaMetric *mdesc, unsigned int inst, pmAtomValue *atom) +{ + __pmID_int *idp = (__pmID_int *)&(mdesc->m_desc.pmid); + + if (ptr == NULL) + return 0; + + if (idp->cluster == 0) { + if (idp->item == 0) { + /* sendmail.start_date */ + atom->cp = ctime(start_date); + atom->cp[24] = '\0'; /* no newline */ + return 1; + } + } + else if (idp->cluster == 1) { + if (inst >= nmailer) + return 0; + + if (msgs_from[inst] == 0 && msgs_to[inst] == 0) { + return 0; + } + + switch (idp->item) { + case 0: /* sendmail.permailer.msgs_from */ + atom->ul = msgs_from[inst]; + break; + + case 1: /* sendmail.permailer.bytes_from */ + atom->ul = kbytes_from[inst]; + break; + + case 2: /* sendmail.permailer.msgs_to */ + atom->ul = msgs_to[inst]; + break; + + case 3: /* sendmail.permailer.bytes_to */ + atom->ul = kbytes_to[inst]; + break; + + default: + return PM_ERR_PMID; + } + + return 1; + } + else if (idp->cluster == 2) { + int i; + + atom->ul = 0; + + switch (idp->item) { + case 0: /* sendmail.total.msgs_from */ + for (i = 0; i < nmailer; i++) + atom->ul += msgs_from[i]; + break; + + case 1: /* sendmail.total.bytes_from */ + for (i = 0; i < nmailer; i++) + atom->ul += kbytes_from[i]; + break; + + case 2: /* sendmail.total.msgs_to */ + for (i = 0; i < nmailer; i++) + atom->ul += msgs_to[i]; + break; + + case 3: /* sendmail.total.bytes_to */ + for (i = 0; i < nmailer; i++) + atom->ul += kbytes_to[i]; + break; + + default: + return PM_ERR_PMID; + } + + return 1; + } + + return PM_ERR_PMID; +} + +static int +sendmail_fetch(int numpmid, pmID pmidlist[], pmResult **resp, pmdaExt *pmda) +{ + map_stats(); + return pmdaFetch(numpmid, pmidlist, resp, pmda); +} + +/* + * Initialise the agent + */ +void +__PMDA_INIT_CALL +sendmail_init(pmdaInterface *dp) +{ + if (dp->status != 0) + return; + + if (username) + __pmSetProcessIdentity(username); + + do_sendmail_cf(); + map_stats(); + + dp->version.two.fetch = sendmail_fetch; + + pmdaSetFetchCallBack(dp, sendmail_fetchCallBack); + + pmdaInit(dp, indomtab, sizeof(indomtab)/sizeof(indomtab[0]), metrictab, + sizeof(metrictab)/sizeof(metrictab[0])); +} + +pmLongOptions longopts[] = { + PMDA_OPTIONS_HEADER("Options"), + PMOPT_DEBUG, + PMDAOPT_DOMAIN, + PMDAOPT_LOGFILE, + PMDAOPT_USERNAME, + PMOPT_HELP, + PMDA_OPTIONS_END +}; + +pmdaOptions opts = { + .short_options = "D:d:l:U:?", + .long_options = longopts, +}; + +/* + * Set up the agent if running as a daemon. + */ +int +main(int argc, char **argv) +{ + int sep = __pmPathSeparator(); + pmdaInterface dispatch; + char mypath[MAXPATHLEN]; + + __pmSetProgname(argv[0]); + __pmGetUsername(&username); + + snprintf(mypath, sizeof(mypath), "%s%c" "sendmail" "%c" "help", + pmGetConfig("PCP_PMDAS_DIR"), sep, sep); + pmdaDaemon(&dispatch, PMDA_INTERFACE_3, pmProgname, SENDMAIL, + "sendmail.log", mypath); + + pmdaGetOptions(argc, argv, &opts, &dispatch); + if (opts.errors) { + pmdaUsageMessage(&opts); + exit(1); + } + if (opts.username) + username = opts.username; + + pmdaOpenLog(&dispatch); + sendmail_init(&dispatch); + pmdaConnect(&dispatch); + pmdaMain(&dispatch); + exit(0); +} |