2 * MTA-MIB implementation for sendmail - mibII/mta_sendmail.c
3 * Christoph Mammitzsch <Christoph.Mammitzsch@tu-clausthal.de>
5 * todo: put queue directory into description?
8 * - support sendmail 8.12 queue groups
13 * - supports sendmail 8.10.0 statistics files now
14 * - function read_option has been removed
18 * - renamed configuration tokens:
19 * sendmail config -> sendmail_config
20 * sendmail stats -> sendmail_stats
21 * sendmail queue -> sendmail_queue
22 * sendmail index -> sendmail_index
23 * sendmail statcachetime -> sendmail_stats_t
24 * sendmail dircacetime -> sendmail_queue_t
26 * - now using snmpd_register_config_handler instead of config_parse_dot_conf
30 * - introduced new function print_error
31 * - changed open_sendmailst and read_sendmailcf to use the new function
32 * - changed calls to open_sendmailst and read_sendmailcf
33 * - added some error handling to calls to chdir(), close() and closedir()
38 /** "include files" */
40 # define SNMP_NO_DEBUGGING 1 /* keeps lint from complaining about the DEBUGMSG* macros */
43 #include <net-snmp/net-snmp-config.h>
45 #include <net-snmp/net-snmp-includes.h>
46 #include <net-snmp/agent/net-snmp-agent-includes.h>
48 #include "mta_sendmail.h"
50 #include <sys/types.h>
77 # define dirent direct
79 # include <sys/ndir.h>
89 #ifdef HAVE_SYS_STAT_H
90 # include <sys/stat.h>
93 #if TIME_WITH_SYS_TIME
94 # include <sys/time.h>
98 # include <sys/time.h>
113 /** "macros and variables for registering the OID tree" */
115 * prefix for all OIDs
118 static FindVarMethod var_mtaEntry;
119 static FindVarMethod var_mtaGroupEntry;
121 static oid mta_variables_oid[] = { 1, 3, 6, 1, 2, 1, 28 };
124 * bits that indicate what's needed to compute the value
126 #define NEEDS_STATS (1 << 6)
127 #define NEEDS_DIR (1 << 7)
128 #define NEEDS (NEEDS_STATS | NEEDS_DIR)
131 * symbolic names for the magic values
134 MTARECEIVEDMESSAGES = 3 | NEEDS_STATS,
135 MTASTOREDMESSAGES = 4 | NEEDS_DIR,
136 MTATRANSMITTEDMESSAGES = 5 | NEEDS_STATS,
137 MTARECEIVEDVOLUME = 6 | NEEDS_STATS,
138 MTASTOREDVOLUME = 7 | NEEDS_DIR,
139 MTATRANSMITTEDVOLUME = 8 | NEEDS_STATS,
140 MTAGROUPSTOREDMESSAGES = 17 | NEEDS_DIR,
141 MTAGROUPSTOREDVOLUME = 18 | NEEDS_DIR,
142 MTAGROUPRECEIVEDMESSAGES = 19 | NEEDS_STATS,
143 MTAGROUPREJECTEDMESSAGES = 20 | NEEDS_STATS,
144 MTAGROUPTRANSMITTEDMESSAGES = 22 | NEEDS_STATS,
145 MTAGROUPRECEIVEDVOLUME = 23 | NEEDS_STATS,
146 MTAGROUPTRANSMITTEDVOLUME = 25 | NEEDS_STATS,
148 MTAGROUPHIERARCHY = 49,
152 * structure that tells the agent, which function returns what values
154 static struct variable3 mta_variables[] = {
155 {MTARECEIVEDMESSAGES, ASN_COUNTER, RONLY, var_mtaEntry, 3, {1, 1, 1}},
156 {MTASTOREDMESSAGES, ASN_GAUGE, RONLY, var_mtaEntry, 3, {1, 1, 2}},
157 {MTATRANSMITTEDMESSAGES, ASN_COUNTER, RONLY, var_mtaEntry, 3,
159 {MTARECEIVEDVOLUME, ASN_COUNTER, RONLY, var_mtaEntry, 3, {1, 1, 4}},
160 {MTASTOREDVOLUME, ASN_GAUGE, RONLY, var_mtaEntry, 3, {1, 1, 5}},
161 {MTATRANSMITTEDVOLUME, ASN_COUNTER, RONLY, var_mtaEntry, 3, {1, 1, 6}},
163 {MTAGROUPRECEIVEDMESSAGES, ASN_COUNTER, RONLY, var_mtaGroupEntry, 3,
165 {MTAGROUPREJECTEDMESSAGES, ASN_COUNTER, RONLY, var_mtaGroupEntry, 3,
167 {MTAGROUPSTOREDMESSAGES, ASN_GAUGE, RONLY, var_mtaGroupEntry, 3,
169 {MTAGROUPTRANSMITTEDMESSAGES, ASN_COUNTER, RONLY, var_mtaGroupEntry, 3,
171 {MTAGROUPRECEIVEDVOLUME, ASN_COUNTER, RONLY, var_mtaGroupEntry, 3,
173 {MTAGROUPSTOREDVOLUME, ASN_GAUGE, RONLY, var_mtaGroupEntry, 3,
175 {MTAGROUPTRANSMITTEDVOLUME, ASN_COUNTER, RONLY, var_mtaGroupEntry, 3,
177 {MTAGROUPNAME, ASN_OCTET_STR, RONLY, var_mtaGroupEntry, 3, {2, 1, 25}},
178 {MTAGROUPHIERARCHY, ASN_INTEGER, RONLY, var_mtaGroupEntry, 3,
182 /** "other macros and structures" */
196 * important constants
198 #define FILENAMELEN 200 /* maximum length for filenames */
199 #define MAXMAILERS 25 /* maximum number of mailers (copied from the sendmail sources) */
200 #define MAXQUEUEGROUPS 50 /* maximum # of queue groups (copied from sendmail) */
201 #define MNAMELEN 20 /* maximum length of mailernames (copied from the sendmail sources) */
202 #define STAT_VERSION_8_9 2 /* version of sendmail V8.9.x statistics files (copied from the sendmail sources) */
203 #define STAT_VERSION_8_10 3 /* version of sendmail V8.10.x statistics files (copied from the sendmail sources) */
204 #define STAT_MAGIC 0x1B1DE /* magic value to identify statistics files from sendmail V8.9.x or higher (copied from the sendmail sources) */
206 * structure of sendmail.st file from sendmail V8.10.x (copied from the sendmail sources)
208 struct statisticsV8_10 {
209 int stat_magic; /* magic number */
210 int stat_version; /* stat file version */
211 time_t stat_itime; /* file initialization time */
212 short stat_size; /* size of this structure */
213 long stat_cf; /* # from connections */
214 long stat_ct; /* # to connections */
215 long stat_cr; /* # rejected connections */
216 long stat_nf[MAXMAILERS]; /* # msgs from each mailer */
217 long stat_bf[MAXMAILERS]; /* kbytes from each mailer */
218 long stat_nt[MAXMAILERS]; /* # msgs to each mailer */
219 long stat_bt[MAXMAILERS]; /* kbytes to each mailer */
220 long stat_nr[MAXMAILERS]; /* # rejects by each mailer */
221 long stat_nd[MAXMAILERS]; /* # discards by each mailer */
225 * structure of sendmail.st file from sendmail V8.9.x (copied from the sendmail sources)
227 struct statisticsV8_9 {
228 int stat_magic; /* magic number */
229 int stat_version; /* stat file version */
230 time_t stat_itime; /* file initialization time */
231 short stat_size; /* size of this structure */
232 long stat_nf[MAXMAILERS]; /* # msgs from each mailer */
233 long stat_bf[MAXMAILERS]; /* kbytes from each mailer */
234 long stat_nt[MAXMAILERS]; /* # msgs to each mailer */
235 long stat_bt[MAXMAILERS]; /* kbytes to each mailer */
236 long stat_nr[MAXMAILERS]; /* # rejects by each mailer */
237 long stat_nd[MAXMAILERS]; /* # discards by each mailer */
241 * structure of sendmail.st file from sendmail V8.8.x (copied from the sendmail sources)
243 struct statisticsV8_8 {
244 time_t stat_itime; /* file initialization time */
245 short stat_size; /* size of this structure */
246 long stat_nf[MAXMAILERS]; /* # msgs from each mailer */
247 long stat_bf[MAXMAILERS]; /* kbytes from each mailer */
248 long stat_nt[MAXMAILERS]; /* # msgs to each mailer */
249 long stat_bt[MAXMAILERS]; /* kbytes to each mailer */
253 * queue groups (strictly a sendmail 8.12+ thing
256 char dir[FILENAMELEN + 1];
261 char *name; /* name of queuegroup */
263 time_t last; /* last time we counted */
264 int count; /* # of files */
265 int size; /* size of files */
267 struct QDir *dirs; /* directories in queue group */
270 /** "static variables" */
273 * a list of all the queue groups, NULL terminated
275 static struct QGrp qgrps[MAXQUEUEGROUPS];
276 static int nqgrps = 0;
278 static char sendmailst_fn[FILENAMELEN + 1]; /* name of statistics file */
279 static int sendmailst_fh = -1; /* filehandle for statistics file */
280 static char sendmailcf_fn[FILENAMELEN + 1]; /* name of sendmails config file */
281 static char mailernames[MAXMAILERS][MNAMELEN + 1]; /* array of mailer names */
282 static int mailers = MAXMAILERS; /* number of mailer names in array */
284 static long *stat_nf; /* pointer to stat_nf array within the statistics structure */
285 static long *stat_bf; /* pointer to stat_bf array within the statistics structure */
286 static long *stat_nt; /* pointer to stat_nt array within the statistics structure */
287 static long *stat_bt; /* pointer to stat_bt array within the statistics structure */
288 static long *stat_nr; /* pointer to stat_nr array within the statistics structure,
289 * only valid for statistics files from sendmail >=V8.9.0 */
290 static long *stat_nd; /* pointer to stat_nd array within the statistics structure,
291 * only valid for statistics files from sendmail >=V8.9.0 */
292 static int stats_size; /* size of statistics structure */
293 static long stats[sizeof(struct statisticsV8_10) / sizeof(long) + 1]; /* buffer for statistics structure */
294 static time_t lastreadstats; /* time stats file has been read */
295 static long applindex = 1; /* ApplIndex value for OIDs */
296 static long stat_cache_time = 5; /* time (in seconds) to wait before reading stats file again */
297 static long dir_cache_time = 10; /* time (in seconds) to wait before scanning queue directoy again */
300 /** static void print_error(int priority, BOOL config, BOOL config_only, char *function, char *format, ...)
304 * Called to print errors. It uses the config_perror or the snmp_log function
305 * depending on whether the config parameter is TRUE or FALSE.
309 * priority: priority to be used when calling the snmp_log function
311 * config: indicates whether this function has been called during the
312 * configuration process or not. If set to TRUE, the function
313 * config_perror will be used to report the error.
315 * config_only: if set to TRUE, the error will only be printed when function
316 * has been called during the configuration process.
318 * function: name of the calling function. Used when printing via snmp_log.
320 * format: format string for the error message
322 * ...: additional parameters to insert into the error message string
327 print_error(int priority, BOOL config, BOOL config_only,
328 const char *function, const char *format, ...)
331 print_error(va_alist)
336 char buffer[2 * FILENAMELEN + 200]; /* I know, that's not perfectly safe, but since I don't use more
337 * than two filenames in one error message, that should be enough */
340 va_start(ap, format);
345 const char *function;
349 priority = va_arg(ap, int);
350 config = va_arg(ap, BOOL);
351 config_only = va_arg(ap, BOOL);
352 function = va_arg(ap, char *);
353 format = va_arg(ap, char *);
356 vsnprintf(buffer, sizeof(buffer), format, ap);
359 config_perror(buffer);
360 } else if (!config_only) {
361 snmp_log(priority, "%s: %s\n", function, buffer);
367 /** static void open_sendmailst(BOOL config)
371 * Closes old sendmail.st file, then tries to open the new sendmail.st file
372 * and guess it's version. If it succeeds, it initializes the stat_*
373 * pointers and the stats_size variable.
377 * config: TRUE if function has been called during the configuration process
385 open_sendmailst(BOOL config)
389 if (sendmailst_fh != -1) {
390 while (close(sendmailst_fh) == -1 && errno == EINTR) {
397 sendmailst_fh = open(sendmailst_fn, O_RDONLY);
399 if (sendmailst_fh == -1) {
400 print_error(LOG_ERR, config, TRUE,
401 "mibII/mta_sendmail.c:open_sendmailst",
402 "could not open file \"%s\"\n", sendmailst_fn);
406 filelen = read(sendmailst_fh, (void *) &stats, sizeof stats);
408 if (((struct statisticsV8_10 *) stats)->stat_magic == STAT_MAGIC) {
409 if (((struct statisticsV8_10 *) stats)->stat_version ==
411 && ((struct statisticsV8_10 *) stats)->stat_size ==
412 sizeof(struct statisticsV8_10)
413 && filelen == sizeof(struct statisticsV8_10)) {
414 DEBUGMSGTL(("mibII/mta_sendmail.c:open_sendmailst",
415 "looks like file \"%s\" has been created by sendmail V8.10.0 or newer\n",
417 stat_nf = (((struct statisticsV8_10 *) stats)->stat_nf);
418 stat_bf = (((struct statisticsV8_10 *) stats)->stat_bf);
419 stat_nt = (((struct statisticsV8_10 *) stats)->stat_nt);
420 stat_bt = (((struct statisticsV8_10 *) stats)->stat_bt);
421 stat_nr = (((struct statisticsV8_10 *) stats)->stat_nr);
422 stat_nd = (((struct statisticsV8_10 *) stats)->stat_nd);
423 stats_size = sizeof(struct statisticsV8_10);
424 } else if (((struct statisticsV8_9 *) stats)->stat_version ==
426 && ((struct statisticsV8_9 *) stats)->stat_size ==
427 sizeof(struct statisticsV8_9)
428 && filelen == sizeof(struct statisticsV8_9)) {
429 DEBUGMSGTL(("mibII/mta_sendmail.c:open_sendmailst",
430 "looks like file \"%s\" has been created by sendmail V8.9.x\n",
432 stat_nf = (((struct statisticsV8_9 *) stats)->stat_nf);
433 stat_bf = (((struct statisticsV8_9 *) stats)->stat_bf);
434 stat_nt = (((struct statisticsV8_9 *) stats)->stat_nt);
435 stat_bt = (((struct statisticsV8_9 *) stats)->stat_bt);
436 stat_nr = (((struct statisticsV8_9 *) stats)->stat_nr);
437 stat_nd = (((struct statisticsV8_9 *) stats)->stat_nd);
438 stats_size = sizeof(struct statisticsV8_9);
440 print_error(LOG_WARNING, config, FALSE,
441 "mibII/mta_sendmail.c:open_sendmailst",
442 "could not guess version of statistics file \"%s\"\n",
444 while (close(sendmailst_fh) == -1 && errno == EINTR) {
452 if (((struct statisticsV8_8 *) stats)->stat_size ==
453 sizeof(struct statisticsV8_8)
454 && filelen == sizeof(struct statisticsV8_8)) {
455 DEBUGMSGTL(("mibII/mta_sendmail.c:open_sendmailst",
456 "looks like file \"%s\" has been created by sendmail V8.8.x\n",
458 stat_nf = (((struct statisticsV8_8 *) stats)->stat_nf);
459 stat_bf = (((struct statisticsV8_8 *) stats)->stat_bf);
460 stat_nt = (((struct statisticsV8_8 *) stats)->stat_nt);
461 stat_bt = (((struct statisticsV8_8 *) stats)->stat_bt);
462 stat_nr = (long *) NULL;
463 stat_nd = (long *) NULL;
464 stats_size = sizeof(struct statisticsV8_8);
466 print_error(LOG_WARNING, config, FALSE,
467 "mibII/mta_sendmail.c:open_sendmailst",
468 "could not guess version of statistics file \"%s\"\n",
470 while (close(sendmailst_fh) == -1 && errno == EINTR) {
481 count_queuegroup(struct QGrp *qg)
485 time_t current_time = time(NULL);
487 if (current_time <= (qg->last + dir_cache_time)) {
491 if (getcwd(cwd, sizeof cwd) == NULL) {
493 "mibII/mta_sendmail.c:count_queuegroup: could not get current working directory\n");
500 for (d = qg->dirs; d != NULL; d = d->next) {
503 struct stat filestat;
505 if (chdir(d->dir) != 0)
510 while ((dirp = readdir(dp)) != NULL) {
511 if (dirp->d_name[0] == 'd' && dirp->d_name[1] == 'f') {
512 if (stat(dirp->d_name, &filestat) == 0) {
513 qg->size += (filestat.st_size + 999) / 1000;
515 } else if (dirp->d_name[0] == 'q' && dirp->d_name[1] == 'f') {
522 qg->last = current_time;
527 /** static void add_queuegroup(const char *name, const char *path)
531 * Adds a queuegroup of 'name' with root path 'path' to the static
532 * list of queue groups. if 'path' ends in a *, we expand it out to
533 * all matching subdirs. also look for 'qf' subdirectories.
537 * qgname: name of the queuegroup discovered
538 * path: path of queuegroup discovered
541 add_queuegroup(const char *name, char *path)
543 char parentdir[FILENAMELEN];
545 struct QDir *new = NULL;
546 struct QDir *subdir = NULL;
550 if (nqgrps == MAXQUEUEGROUPS) {
557 if (strlen(path) > FILENAMELEN - 10) {
564 p = path + strlen(path) - 1;
565 if (*p == '*') { /* multiple queue dirs */
571 strcpy(parentdir, path);
573 * remove last directory component from parentdir
575 for (p = parentdir + strlen(parentdir) - 1; p >= parentdir; p--) {
595 * p is now the prefix we need to match
597 if ((dp = opendir(parentdir)) == NULL) {
599 * xxx can't open parentdir
604 while ((dirp = readdir(dp)) != NULL) {
605 if (!strncmp(dirp->d_name, p, strlen(p)) &&
606 dirp->d_name[0] != '.') {
608 * match, add it to the list
612 * single queue directory
614 subdir = (struct QDir *) malloc(sizeof(struct QDir));
615 snprintf(subdir->dir, FILENAMELEN - 5, "%s/%s", parentdir,
625 * single queue directory
627 new = (struct QDir *) malloc(sizeof(struct QDir));
628 strcpy(new->dir, path);
633 * check 'new' for /qf directories
635 for (subdir = new; subdir != NULL; subdir = subdir->next) {
636 char qf[FILENAMELEN + 1];
638 snprintf(qf, FILENAMELEN, "%s/qf", subdir->dir);
639 if ((dp = opendir(qf)) != NULL) {
643 strcpy(subdir->dir, qf);
649 * we now have the list of directories in 'new'; create the queuegroup
652 qgrps[nqgrps].name = strdup(name);
653 qgrps[nqgrps].last = 0;
654 qgrps[nqgrps].count = 0;
655 qgrps[nqgrps].size = 0;
656 qgrps[nqgrps].dirs = new;
661 /** static BOOL read_sendmailcf(BOOL config)
665 * Tries to open the file named in sendmailcf_fn and to get the names of
666 * the mailers, the status file and the mailqueue directories.
670 * config: TRUE if function has been called during the configuration process
674 * TRUE : config file has been successfully opened
676 * FALSE : could not open config file
681 read_sendmailcf(BOOL config)
689 int found_sendmailst = FALSE;
693 sendmailcf_fp = fopen(sendmailcf_fn, "r");
694 if (sendmailcf_fp == NULL) {
695 print_error(LOG_ERR, config, TRUE,
696 "mibII/mta_sendmail.c:read_sendmailcf",
697 "could not open file \"%s\"\n", sendmailcf_fn);
702 * initializes the standard mailers, which aren't necessarily mentioned in the sendmail.cf file
704 strcpy(mailernames[0], "prog");
705 strcpy(mailernames[1], "*file*");
706 strcpy(mailernames[2], "*include*");
714 while (fgets(line, sizeof line, sendmailcf_fp) != NULL) {
715 linelen = strlen(line);
717 if (line[linelen - 1] != '\n') {
718 print_error(LOG_WARNING, config, FALSE,
719 "mibII/mta_sendmail.c:read_sendmailcf",
720 "line %d in config file \"%s\" is too long\n",
721 linenr, sendmailcf_fn);
722 while (fgets(line, sizeof line, sendmailcf_fp) != NULL && line[strlen(line) - 1] != '\n') { /* skip rest of the line */
731 line[--linelen] = '\0';
737 if (mailers < MAXMAILERS) {
739 line[i] != ',' && !isspace(line[i]) && line[i] != '\0'
740 && i <= MNAMELEN; i++) {
741 mailernames[mailers][i - 1] = line[i];
743 mailernames[mailers][i - 1] = '\0';
745 DEBUGMSGTL(("mibII/mta_sendmail.c:read_sendmailcf",
746 "found mailer \"%s\"\n",
747 mailernames[mailers]));
751 && strcmp(mailernames[mailers], mailernames[i]) != 0;
762 DEBUGMSGTL(("mibII/mta_sendmail.c:read_sendmailcf",
763 "mailer \"%s\" already existed, but since it's one of the predefined mailers, that's probably nothing to worry about\n",
764 mailernames[mailers]));
766 DEBUGMSGTL(("mibII/mta_sendmail.c:read_sendmailcf",
767 "mailer \"%s\" already existed\n",
768 mailernames[mailers]));
770 mailernames[mailers][0] = '\0';
773 print_error(LOG_WARNING, config, FALSE,
774 "mibII/mta_sendmail.c:read_sendmailcf",
775 "found too many mailers in config file \"%s\"\n",
788 if (strncasecmp(line + 2, "StatusFile", 10) == 0) {
789 filename = line + 12;
790 } else if (strncasecmp(line + 2, "QueueDirectory", 14) ==
792 filename = line + 16;
795 * not an option we care about
801 * make sure it's the end of the option
803 if (*filename != ' ' && *filename != '=')
809 while (*filename == ' ')
813 * must be O <option> = <file>
815 if (*filename++ != '=') {
816 print_error(LOG_WARNING, config, FALSE,
817 "mibII/mta_sendmail.c:read_sendmailcf",
818 "line %d in config file \"%s\" ist missing an '='\n",
819 linenr, sendmailcf_fn);
826 while (*filename == ' ')
829 if (strlen(filename) > FILENAMELEN) {
830 print_error(LOG_WARNING, config, FALSE,
831 "mibII/mta_sendmail.c:read_sendmailcf",
832 "line %d config file \"%s\" contains a filename that's too long\n",
833 linenr, sendmailcf_fn);
837 if (strncasecmp(line + 2, "StatusFile", 10) == 0) {
838 strncpy(sendmailst_fn, filename, sizeof(sendmailst_fn));
839 sendmailst_fn[ sizeof(sendmailst_fn)-1 ] = 0;
840 found_sendmailst = TRUE;
841 DEBUGMSGTL(("mibII/mta_sendmail.c:read_sendmailcf",
842 "found statatistics file \"%s\"\n",
844 } else if (strncasecmp(line + 2, "QueueDirectory", 14) ==
846 add_queuegroup("mqueue", filename);
848 print_error(LOG_CRIT, config, FALSE,
849 "mibII/mta_sendmail.c:read_sendmailcf",
850 "This shouldn't happen.\n");
856 if (strlen(line + 2) > FILENAMELEN) {
857 print_error(LOG_WARNING, config, FALSE,
858 "mibII/mta_sendmail.c:read_sendmailcf",
859 "line %d config file \"%s\" contains a filename that's too long\n",
860 linenr, sendmailcf_fn);
863 strcpy(sendmailst_fn, line + 2);
864 found_sendmailst = TRUE;
865 DEBUGMSGTL(("mibII/mta_sendmail.c:read_sendmailcf",
866 "found statatistics file \"%s\"\n",
871 if (strlen(line + 2) > FILENAMELEN) {
872 print_error(LOG_WARNING, config, FALSE,
873 "mibII/mta_sendmail.c:read_sendmailcf",
874 "line %d config file \"%s\" contains a filename that's too long\n",
875 linenr, sendmailcf_fn);
879 add_queuegroup("mqueue", line + 2);
886 * found a queue group
888 p = qgname = line + 1;
889 while (*p && *p != ',') {
893 print_error(LOG_WARNING, config, FALSE,
894 "mibII/mta_sendmail.c:read_sendmailcf",
895 "line %d config file \"%s\" contains a weird queuegroup\n",
896 linenr, sendmailcf_fn);
901 * look for the directory
909 while (*p && *p == ' ')
912 if (*p == 'P') { /* found path */
913 while (*p && *p != '=')
916 print_error(LOG_WARNING, config, FALSE,
917 "mibII/mta_sendmail.c:read_sendmailcf",
918 "line %d config file \"%s\" contains a weird queuegroup\n",
919 linenr, sendmailcf_fn);
925 * find next ',', turn into \0
927 while (*p && *p != ',')
935 while (*p && *p != ',')
940 * we found a directory
943 add_queuegroup(qgname, filename);
945 print_error(LOG_WARNING, config, FALSE,
946 "mibII/mta_sendmail.c:read_sendmailcf",
947 "line %d config file \"%s\" contains a weird queuegroup: no directory\n",
948 linenr, sendmailcf_fn);
957 for (i = 0; i < 10 && fclose(sendmailcf_fp) != 0; i++) {
963 for (i = mailers; i < MAXMAILERS; i++) {
964 mailernames[i][0] = '\0';
967 if (found_sendmailst) {
968 open_sendmailst(config);
975 /** static void mta_sendmail_parse_config(const char* token, char *line)
979 * Called by the agent for each configuration line that belongs to this module.
980 * The possible tokens are:
982 * sendmail_config - filename of the sendmail configutarion file
983 * sendmail_stats - filename of the sendmail statistics file
984 * sendmail_queue - name of the sendmail mailqueue directory
985 * sendmail_index - the ApplIndex to use for the table
986 * sendmail_stats_t - the time (in seconds) to cache statistics
987 * sendmail_queue_t - the time (in seconds) to cache the directory scanning results
989 * For "sendmail_config", "sendmail_stats" and "sendmail_queue", the copy_nword
990 * function is used to copy the filename.
994 * token: first word of the line
996 * line: rest of the line
1004 mta_sendmail_parse_config(const char *token, char *line)
1006 if (strlen(line) > FILENAMELEN) { /* Might give some false alarm, but better to be safe than sorry */
1007 config_perror("line too long");
1011 if (strcasecmp(token, "sendmail_stats") == 0) {
1012 while (isspace(*line)) {
1015 copy_nword(line, sendmailst_fn, sizeof(sendmailst_fn));
1017 open_sendmailst(TRUE);
1019 if (sendmailst_fh == -1) {
1020 char str[FILENAMELEN + 50];
1021 sprintf(str, "couldn't open file \"%s\"", sendmailst_fn);
1026 DEBUGMSGTL(("mibII/mta_sendmail.c:mta_sendmail_parse_config",
1027 "opened statistics file \"%s\"\n", sendmailst_fn));
1029 } else if (strcasecmp(token, "sendmail_config") == 0) {
1030 while (isspace(*line)) {
1033 copy_nword(line, sendmailcf_fn, sizeof(sendmailcf_fn));
1035 read_sendmailcf(TRUE);
1037 DEBUGMSGTL(("mibII/mta_sendmail.c:mta_sendmail_parse_config",
1038 "read config file \"%s\"\n", sendmailcf_fn));
1040 } else if (strcasecmp(token, "sendmail_queue") == 0) {
1041 while (isspace(*line)) {
1044 add_queuegroup("mqueue", line);
1047 } else if (strcasecmp(token, "sendmail_index") == 0) {
1048 while (isspace(*line)) {
1051 applindex = atol(line);
1052 if (applindex < 1) {
1053 config_perror("invalid index number");
1056 } else if (strcasecmp(token, "sendmail_stats_t") == 0) {
1057 while (isspace(*line)) {
1060 stat_cache_time = atol(line);
1061 if (stat_cache_time < 1) {
1062 config_perror("invalid cache time");
1065 } else if (strcasecmp(token, "sendmail_queue_t") == 0) {
1066 while (isspace(*line)) {
1069 dir_cache_time = atol(line);
1070 if (dir_cache_time < 1) {
1071 config_perror("invalid cache time");
1076 ("mibII/mta_sendmail.c says: What should I do with that token? Did you ./configure the agent properly?");
1083 /** void init_mta_sendmail(void)
1087 * Called by the agent to initialize the module. The function will register
1088 * the OID tree and the config handler and try some default values for the
1089 * sendmail.cf and sendmail.st files and for the mailqueue directory.
1101 init_mta_sendmail(void)
1103 REGISTER_MIB("mibII/mta_sendmail", mta_variables, variable3,
1106 snmpd_register_config_handler("sendmail_config",
1107 mta_sendmail_parse_config, NULL, "file");
1108 snmpd_register_config_handler("sendmail_stats",
1109 mta_sendmail_parse_config, NULL, "file");
1110 snmpd_register_config_handler("sendmail_queue",
1111 mta_sendmail_parse_config, NULL,
1113 snmpd_register_config_handler("sendmail_index",
1114 mta_sendmail_parse_config, NULL,
1116 snmpd_register_config_handler("sendmail_stats_t",
1117 mta_sendmail_parse_config, NULL,
1119 snmpd_register_config_handler("sendmail_queue_t",
1120 mta_sendmail_parse_config, NULL,
1123 strcpy(sendmailcf_fn, "/etc/mail/sendmail.cf");
1124 if (read_sendmailcf(FALSE) == FALSE) {
1125 strcpy(sendmailcf_fn, "/etc/sendmail.cf");
1126 read_sendmailcf(FALSE);
1129 if (sendmailst_fh == -1) {
1130 strcpy(sendmailst_fn, "/etc/mail/statistics");
1131 open_sendmailst(FALSE);
1132 if (sendmailst_fh == -1) {
1133 strcpy(sendmailst_fn, "/etc/mail/sendmail.st");
1134 open_sendmailst(FALSE);
1141 /** unsigned char *var_mtaEntry(struct variable *vp, oid *name, size_t *length, int exact, size_t *var_len, WriteMethod **write_method)
1145 * Called by the agent in order to get the values for the mtaTable.
1149 * see agent documentation
1153 * see agent documentation
1157 var_mtaEntry(struct variable *vp,
1160 int exact, size_t * var_len, WriteMethod ** write_method)
1164 static long long_ret;
1167 auto time_t current_time;
1168 int global_count = 0;
1169 int global_size = 0;
1172 if (*length != vp->namelen + 1) {
1176 snmp_oid_compare(name, *length - 1, vp->name, vp->namelen);
1177 if (result != 0 || name[*length - 1] != applindex) {
1181 if (*length <= vp->namelen) {
1185 snmp_oid_compare(name, *length - 1, vp->name, vp->namelen);
1190 if (result == 0 && name[*length - 1] >= applindex) {
1194 memcpy(name, vp->name, (int) vp->namelen * (int) sizeof *name);
1195 *length = vp->namelen + 1;
1197 name[vp->namelen] = applindex;
1200 *write_method = (WriteMethod *) NULL;
1201 *var_len = sizeof(long); /* default to 'long' results */
1203 if (vp->magic & NEEDS_STATS) {
1204 if (sendmailst_fh == -1)
1206 current_time = time(NULL);
1207 if (current_time == (time_t) - 1
1208 || current_time > lastreadstats + stat_cache_time) {
1209 if (lseek(sendmailst_fh, 0, SEEK_SET) == -1) {
1211 "mibII/mta_sendmail.c:var_mtaEntry: could not rewind to the beginning of file \"%s\"\n",
1215 if (read(sendmailst_fh, (void *) &stats, stats_size) !=
1218 "mibII/mta_sendmail.c:var_mtaEntry: could not read from statistics file \"%s\"\n",
1222 if (current_time != (time_t) - 1) {
1223 lastreadstats = current_time;
1228 if (vp->magic & NEEDS_DIR) {
1232 * count all queue group messages
1234 for (i = 0; i < nqgrps; i++) {
1235 count_queuegroup(&qgrps[i]);
1236 global_count += qgrps[i].count;
1237 global_size += qgrps[i].size;
1241 switch (vp->magic) {
1243 case MTARECEIVEDMESSAGES:
1246 for (i = 0; i < MAXMAILERS; i++) {
1247 long_ret += stat_nf[i];
1249 return (unsigned char *) &long_ret;
1251 case MTASTOREDMESSAGES:
1253 long_ret = global_count;
1254 return (unsigned char *) &long_ret;
1256 case MTATRANSMITTEDMESSAGES:
1259 for (i = 0; i < MAXMAILERS; i++) {
1260 long_ret += stat_nt[i];
1262 return (unsigned char *) &long_ret;
1264 case MTARECEIVEDVOLUME:
1267 for (i = 0; i < MAXMAILERS; i++) {
1268 long_ret += stat_bf[i];
1270 return (unsigned char *) &long_ret;
1272 case MTASTOREDVOLUME:
1274 long_ret = global_size;
1275 return (unsigned char *) &long_ret;
1277 case MTATRANSMITTEDVOLUME:
1280 for (i = 0; i < MAXMAILERS; i++) {
1281 long_ret += stat_bt[i];
1283 return (unsigned char *) &long_ret;
1287 "mibII/mta_sendmail.c:mtaEntry: unknown magic value\n");
1293 /** unsigned char *var_mtaGroupEntry(struct variable *vp, oid *name, size_t *length, int exact, size_t *var_len, WriteMethod **write_method)
1297 * Called by the agent in order to get the values for the mtaGroupTable.
1301 * see agent documentation
1305 * see agent documentation
1309 var_mtaGroupEntry(struct variable *vp,
1312 int exact, size_t * var_len, WriteMethod ** write_method)
1314 static long long_ret;
1317 auto time_t current_time;
1321 if (*length != vp->namelen + 2) {
1325 snmp_oid_compare(name, *length - 2, vp->name, vp->namelen);
1326 if (result != 0 || name[*length - 2] != applindex
1327 || name[*length - 1] <= 0
1328 || name[*length - 1] > mailers + nqgrps) {
1332 if (*length < vp->namelen) {
1336 snmp_oid_compare(name, vp->namelen, vp->name, vp->namelen);
1341 * OID prefix too large
1348 * OID prefix matches exactly,...
1350 if (*length > vp->namelen && name[vp->namelen] > applindex) {
1352 * ... but ApplIndex too large
1356 if (*length > vp->namelen && name[vp->namelen] == applindex) {
1358 * ... ApplIndex ok,...
1360 if (*length > vp->namelen + 1
1361 && name[vp->namelen + 1] >= 1) {
1362 if (name[vp->namelen + 1] >= mailers + nqgrps) {
1364 * ... but mailernr too large
1368 name[vp->namelen + 1]++;
1371 name[vp->namelen + 1] = 1;
1374 name[vp->namelen] = applindex;
1375 name[vp->namelen + 1] = 1;
1377 } else { /* OID prefix too small */
1378 memcpy(name, vp->name, (int) vp->namelen * (int) sizeof *name);
1379 name[vp->namelen] = applindex;
1380 name[vp->namelen + 1] = 1;
1382 *length = vp->namelen + 2;
1386 *var_len = sizeof(long); /* default to 'long' results */
1388 if (vp->magic & NEEDS_STATS) {
1389 if (sendmailst_fh == -1)
1391 current_time = time(NULL);
1392 if (current_time == (time_t) - 1 ||
1393 current_time > lastreadstats + stat_cache_time) {
1394 if (lseek(sendmailst_fh, 0, SEEK_SET) == -1) {
1396 "mibII/mta_sendmail.c:var_mtaGroupEntry: could not rewind to beginning of file \"%s\"\n",
1400 if (read(sendmailst_fh, (void *) &stats, stats_size) !=
1403 "mibII/mta_sendmail.c:var_mtaGroupEntry: could not read statistics file \"%s\"\n",
1407 if (current_time != (time_t) - 1) {
1408 lastreadstats = current_time;
1413 row = name[*length - 1] - 1;
1416 * if this is a mailer but we're asking for queue-group only info,
1419 if (!exact && row < mailers && (vp->magic == MTAGROUPSTOREDMESSAGES ||
1420 vp->magic == MTAGROUPSTOREDVOLUME)) {
1422 name[*length - 1] = row + 1;
1425 if (row < mailers) {
1426 switch (vp->magic) {
1427 case MTAGROUPRECEIVEDMESSAGES:
1428 long_ret = (long) stat_nf[row];
1429 return (unsigned char *) &long_ret;
1431 case MTAGROUPREJECTEDMESSAGES:
1432 if (stat_nr != NULL && stat_nd != NULL) {
1433 long_ret = (long) (stat_nr[row] + stat_nd[row]); /* Number of rejected plus number of discarded messages */
1434 return (unsigned char *) &long_ret;
1439 case MTAGROUPTRANSMITTEDMESSAGES:
1440 long_ret = (long) stat_nt[row];
1441 return (unsigned char *) &long_ret;
1443 case MTAGROUPRECEIVEDVOLUME:
1444 long_ret = (long) stat_bf[row];
1445 return (unsigned char *) &long_ret;
1447 case MTAGROUPTRANSMITTEDVOLUME:
1448 long_ret = (long) stat_bt[row];
1449 return (unsigned char *) &long_ret;
1452 *var_len = strlen(mailernames[row]);
1453 return (unsigned char *) (*var_len >
1454 0 ? mailernames[row] : NULL);
1456 case MTAGROUPHIERARCHY:
1457 long_ret = (long) -1;
1458 return (unsigned char *) &long_ret;
1465 * this is the queue group part of the table
1468 switch (vp->magic) {
1469 case MTAGROUPSTOREDMESSAGES:
1470 count_queuegroup(&qgrps[row]);
1471 long_ret = (long) qgrps[row].count;
1472 return (unsigned char *) &long_ret;
1474 case MTAGROUPSTOREDVOLUME:
1475 count_queuegroup(&qgrps[row]);
1476 long_ret = (long) qgrps[row].size;
1477 return (unsigned char *) &long_ret;
1480 *var_len = strlen(qgrps[row].name);
1481 return (unsigned char *) (*var_len >
1482 0 ? qgrps[row].name : NULL);
1484 case MTAGROUPHIERARCHY:
1485 long_ret = (long) -2;
1486 return (unsigned char *) &long_ret;