/* * MTA-MIB implementation for sendmail - mibII/mta_sendmail.c * Christoph Mammitzsch * * todo: put queue directory into description? * * 13.02.2002: * - support sendmail 8.12 queue groups * * * 05.04.2000: * * - supports sendmail 8.10.0 statistics files now * - function read_option has been removed * * 12.04.2000: * * - renamed configuration tokens: * sendmail config -> sendmail_config * sendmail stats -> sendmail_stats * sendmail queue -> sendmail_queue * sendmail index -> sendmail_index * sendmail statcachetime -> sendmail_stats_t * sendmail dircacetime -> sendmail_queue_t * * - now using snmpd_register_config_handler instead of config_parse_dot_conf * * 15.04.2000: * * - introduced new function print_error * - changed open_sendmailst and read_sendmailcf to use the new function * - changed calls to open_sendmailst and read_sendmailcf * - added some error handling to calls to chdir(), close() and closedir() * */ /** "include files" */ #ifdef __lint # define NETSNMP_NO_DEBUGGING 1 /* keeps lint from complaining about the DEBUGMSG* macros */ #endif #include #include #include #include "mta_sendmail.h" #include #include #include #ifdef HAVE_STRING_H # include #else # include #endif #if HAVE_STDLIB_H #include #endif #ifdef HAVE_UNISTD_H # include #endif #ifdef HAVE_FCNTL_H # include #endif #if HAVE_DIRENT_H #include #else # define dirent direct # if HAVE_SYS_NDIR_H # include # endif # if HAVE_SYS_DIR_H # include # endif # if HAVE_NDIR_H # include # endif #endif #ifdef HAVE_SYS_STAT_H # include #endif #if TIME_WITH_SYS_TIME # include # include #else # if HAVE_SYS_TIME_H # include # else # include # endif #endif #include #include /**/ /** "macros and variables for registering the OID tree" */ /* * prefix for all OIDs */ static FindVarMethod var_mtaEntry; static FindVarMethod var_mtaGroupEntry; static oid mta_variables_oid[] = { 1, 3, 6, 1, 2, 1, 28 }; /* * bits that indicate what's needed to compute the value */ #define NEEDS_STATS (1 << 6) #define NEEDS_DIR (1 << 7) #define NEEDS (NEEDS_STATS | NEEDS_DIR) /* * symbolic names for the magic values */ enum { MTARECEIVEDMESSAGES = 3 | NEEDS_STATS, MTASTOREDMESSAGES = 4 | NEEDS_DIR, MTATRANSMITTEDMESSAGES = 5 | NEEDS_STATS, MTARECEIVEDVOLUME = 6 | NEEDS_STATS, MTASTOREDVOLUME = 7 | NEEDS_DIR, MTATRANSMITTEDVOLUME = 8 | NEEDS_STATS, MTAGROUPSTOREDMESSAGES = 17 | NEEDS_DIR, MTAGROUPSTOREDVOLUME = 18 | NEEDS_DIR, MTAGROUPRECEIVEDMESSAGES = 19 | NEEDS_STATS, MTAGROUPREJECTEDMESSAGES = 20 | NEEDS_STATS, MTAGROUPTRANSMITTEDMESSAGES = 22 | NEEDS_STATS, MTAGROUPRECEIVEDVOLUME = 23 | NEEDS_STATS, MTAGROUPTRANSMITTEDVOLUME = 25 | NEEDS_STATS, MTAGROUPNAME = 43, MTAGROUPHIERARCHY = 49 }; /* * structure that tells the agent, which function returns what values */ static struct variable3 mta_variables[] = { {MTARECEIVEDMESSAGES, ASN_COUNTER, NETSNMP_OLDAPI_RONLY, var_mtaEntry, 3, {1, 1, 1}}, {MTASTOREDMESSAGES, ASN_GAUGE, NETSNMP_OLDAPI_RONLY, var_mtaEntry, 3, {1, 1, 2}}, {MTATRANSMITTEDMESSAGES, ASN_COUNTER, NETSNMP_OLDAPI_RONLY, var_mtaEntry, 3, {1, 1, 3}}, {MTARECEIVEDVOLUME, ASN_COUNTER, NETSNMP_OLDAPI_RONLY, var_mtaEntry, 3, {1, 1, 4}}, {MTASTOREDVOLUME, ASN_GAUGE, NETSNMP_OLDAPI_RONLY, var_mtaEntry, 3, {1, 1, 5}}, {MTATRANSMITTEDVOLUME, ASN_COUNTER, NETSNMP_OLDAPI_RONLY, var_mtaEntry, 3, {1, 1, 6}}, {MTAGROUPRECEIVEDMESSAGES, ASN_COUNTER, NETSNMP_OLDAPI_RONLY, var_mtaGroupEntry, 3, {2, 1, 2}}, {MTAGROUPREJECTEDMESSAGES, ASN_COUNTER, NETSNMP_OLDAPI_RONLY, var_mtaGroupEntry, 3, {2, 1, 3}}, {MTAGROUPSTOREDMESSAGES, ASN_GAUGE, NETSNMP_OLDAPI_RONLY, var_mtaGroupEntry, 3, {2, 1, 4}}, {MTAGROUPTRANSMITTEDMESSAGES, ASN_COUNTER, NETSNMP_OLDAPI_RONLY, var_mtaGroupEntry, 3, {2, 1, 5}}, {MTAGROUPRECEIVEDVOLUME, ASN_COUNTER, NETSNMP_OLDAPI_RONLY, var_mtaGroupEntry, 3, {2, 1, 6}}, {MTAGROUPSTOREDVOLUME, ASN_GAUGE, NETSNMP_OLDAPI_RONLY, var_mtaGroupEntry, 3, {2, 1, 7}}, {MTAGROUPTRANSMITTEDVOLUME, ASN_COUNTER, NETSNMP_OLDAPI_RONLY, var_mtaGroupEntry, 3, {2, 1, 8}}, {MTAGROUPNAME, ASN_OCTET_STR, NETSNMP_OLDAPI_RONLY, var_mtaGroupEntry, 3, {2, 1, 25}}, {MTAGROUPHIERARCHY, ASN_INTEGER, NETSNMP_OLDAPI_RONLY, var_mtaGroupEntry, 3, {2, 1, 31}} }; /**/ /** "other macros and structures" */ /* * for boolean values */ #ifndef FALSE #define FALSE 0 #endif #ifndef TRUE #define TRUE 1 #endif #ifndef BOOL #define BOOL short #endif /* * important constants */ #define FILENAMELEN 200 /* maximum length for filenames */ #define MAXMAILERS 25 /* maximum number of mailers (copied from the sendmail sources) */ #define MAXQUEUEGROUPS 50 /* maximum # of queue groups (copied from sendmail) */ #define MNAMELEN 20 /* maximum length of mailernames (copied from the sendmail sources) */ #define STAT_VERSION_8_9 2 /* version of sendmail V8.9.x statistics files (copied from the sendmail sources) */ #define STAT_VERSION_8_10 3 /* version of sendmail V8.10.x statistics files (copied from the sendmail sources) */ #define STAT_VERSION_8_12_QUAR 4 /* version of sendmail V8.12.x statistics files using -D_FFR_QUARANTINE (commercial and edge-living opensource*/ #define STAT_MAGIC 0x1B1DE /* magic value to identify statistics files from sendmail V8.9.x or higher (copied from the sendmail sources) */ /* * structure of sendmail.st file from sendmail V8.10.x (copied from the sendmail sources) */ struct statisticsV8_12_QUAR { 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_cf; /* # from connections */ long stat_ct; /* # to connections */ long stat_cr; /* # rejected connections */ 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 */ long stat_nq[MAXMAILERS]; /* # quarantines by each mailer*/ }; struct statisticsV8_10 { 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_cf; /* # from connections */ long stat_ct; /* # to connections */ long stat_cr; /* # rejected connections */ 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 */ }; /* * structure of sendmail.st file from sendmail V8.9.x (copied from the sendmail sources) */ struct statisticsV8_9 { 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 */ }; /* * structure of sendmail.st file from sendmail V8.8.x (copied from the sendmail sources) */ struct statisticsV8_8 { 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 */ }; /**/ /* * queue groups (strictly a sendmail 8.12+ thing */ struct QDir { char *dir; struct QDir *next; }; struct QGrp { char *name; /* name of queuegroup */ time_t last; /* last time we counted */ int count; /* # of files */ int size; /* size of files */ struct QDir *dirs; /* directories in queue group */ }; /** "static variables" */ /* * a list of all the queue groups, NULL terminated */ static struct QGrp qgrps[MAXQUEUEGROUPS]; static int nqgrps = 0; static char sendmailst_fn[FILENAMELEN + 1]; /* name of statistics file */ static int sendmailst_fh = -1; /* filehandle for statistics file */ static char sendmailcf_fn[FILENAMELEN + 1]; /* name of sendmails config file */ static char mailernames[MAXMAILERS][MNAMELEN + 1]; /* array of mailer names */ static int mailers = MAXMAILERS; /* number of mailer names in array */ static long *stat_nf; /* pointer to stat_nf array within the statistics structure */ static long *stat_bf; /* pointer to stat_bf array within the statistics structure */ static long *stat_nt; /* pointer to stat_nt array within the statistics structure */ static long *stat_bt; /* pointer to stat_bt array within the statistics structure */ static long *stat_nr; /* pointer to stat_nr array within the statistics structure, * only valid for statistics files from sendmail >=V8.9.0 */ static long *stat_nd; /* pointer to stat_nd array within the statistics structure, * only valid for statistics files from sendmail >=V8.9.0 */ static int stats_size; /* size of statistics structure */ static long stats[sizeof(struct statisticsV8_12_QUAR) / sizeof(long) + 1]; /* buffer for statistics structure */ static time_t lastreadstats; /* time stats file has been read */ static long applindex = 1; /* ApplIndex value for OIDs */ static long stat_cache_time = 5; /* time (in seconds) to wait before reading stats file again */ static long dir_cache_time = 10; /* time (in seconds) to wait before scanning queue directoy again */ /**/ /** static void print_error(int priority, BOOL config, BOOL config_only, char *function, char *format, ...) * * Description: * * Called to print errors. It uses the config_perror or the snmp_log function * depending on whether the config parameter is TRUE or FALSE. * * Parameters: * * priority: priority to be used when calling the snmp_log function * * config: indicates whether this function has been called during the * configuration process or not. If set to TRUE, the function * config_perror will be used to report the error. * * config_only: if set to TRUE, the error will only be printed when function * has been called during the configuration process. * * function: name of the calling function. Used when printing via snmp_log. * * format: format string for the error message * * ...: additional parameters to insert into the error message string * */ static void print_error(int priority, BOOL config, BOOL config_only, const char *function, const char *format, ...) { va_list ap; char buffer[2 * FILENAMELEN + 200]; /* I know, that's not perfectly safe, but since I don't use more * than two filenames in one error message, that should be enough */ va_start(ap, format); vsnprintf(buffer, sizeof(buffer), format, ap); if (config) { config_perror(buffer); } else if (!config_only) { snmp_log(priority, "%s: %s\n", function, buffer); } va_end(ap); } /**/ /** static void open_sendmailst(BOOL config) * * Description: * * Closes old sendmail.st file, then tries to open the new sendmail.st file * and guess it's version. If it succeeds, it initializes the stat_* * pointers and the stats_size variable. * * Parameters: * * config: TRUE if function has been called during the configuration process * * Returns: * * nothing * */ static void open_sendmailst(BOOL config) { int filelen; if (sendmailst_fh != -1) { while (close(sendmailst_fh) == -1 && errno == EINTR) { /* * do nothing */ } } sendmailst_fh = open(sendmailst_fn, O_RDONLY); if (sendmailst_fh == -1) { print_error(LOG_ERR, config, TRUE, "mibII/mta_sendmail.c:open_sendmailst", "could not open file \"%s\"", sendmailst_fn); return; } filelen = read(sendmailst_fh, (void *) &stats, sizeof stats); if (((struct statisticsV8_10 *) stats)->stat_magic == STAT_MAGIC) { if (((struct statisticsV8_12_QUAR *) stats)->stat_version == STAT_VERSION_8_12_QUAR && ((struct statisticsV8_12_QUAR *) stats)->stat_size == sizeof(struct statisticsV8_12_QUAR) && filelen == sizeof(struct statisticsV8_12_QUAR)) { DEBUGMSGTL(("mibII/mta_sendmail.c:open_sendmailst", "looks like file \"%s\" has been created by sendmail V8.10.0 or newer\n", sendmailst_fn)); stat_nf = (((struct statisticsV8_12_QUAR *) stats)->stat_nf); stat_bf = (((struct statisticsV8_12_QUAR *) stats)->stat_bf); stat_nt = (((struct statisticsV8_12_QUAR *) stats)->stat_nt); stat_bt = (((struct statisticsV8_12_QUAR *) stats)->stat_bt); stat_nr = (((struct statisticsV8_12_QUAR *) stats)->stat_nr); stat_nd = (((struct statisticsV8_12_QUAR *) stats)->stat_nd); stats_size = sizeof(struct statisticsV8_12_QUAR); } else if (((struct statisticsV8_10 *) stats)->stat_version == STAT_VERSION_8_10 && ((struct statisticsV8_10 *) stats)->stat_size == sizeof(struct statisticsV8_10) && filelen == sizeof(struct statisticsV8_10)) { DEBUGMSGTL(("mibII/mta_sendmail.c:open_sendmailst", "looks like file \"%s\" has been created by sendmail V8.10.0 or newer\n", sendmailst_fn)); stat_nf = (((struct statisticsV8_10 *) stats)->stat_nf); stat_bf = (((struct statisticsV8_10 *) stats)->stat_bf); stat_nt = (((struct statisticsV8_10 *) stats)->stat_nt); stat_bt = (((struct statisticsV8_10 *) stats)->stat_bt); stat_nr = (((struct statisticsV8_10 *) stats)->stat_nr); stat_nd = (((struct statisticsV8_10 *) stats)->stat_nd); stats_size = sizeof(struct statisticsV8_10); } else if (((struct statisticsV8_9 *) stats)->stat_version == STAT_VERSION_8_9 && ((struct statisticsV8_9 *) stats)->stat_size == sizeof(struct statisticsV8_9) && filelen == sizeof(struct statisticsV8_9)) { DEBUGMSGTL(("mibII/mta_sendmail.c:open_sendmailst", "looks like file \"%s\" has been created by sendmail V8.9.x\n", sendmailst_fn)); stat_nf = (((struct statisticsV8_9 *) stats)->stat_nf); stat_bf = (((struct statisticsV8_9 *) stats)->stat_bf); stat_nt = (((struct statisticsV8_9 *) stats)->stat_nt); stat_bt = (((struct statisticsV8_9 *) stats)->stat_bt); stat_nr = (((struct statisticsV8_9 *) stats)->stat_nr); stat_nd = (((struct statisticsV8_9 *) stats)->stat_nd); stats_size = sizeof(struct statisticsV8_9); } else { print_error(LOG_WARNING, config, FALSE, "mibII/mta_sendmail.c:open_sendmailst", "could not guess version of statistics file \"%s\"", sendmailst_fn); while (close(sendmailst_fh) == -1 && errno == EINTR) { /* * do nothing */ } sendmailst_fh = -1; } } else { if (((struct statisticsV8_8 *) stats)->stat_size == sizeof(struct statisticsV8_8) && filelen == sizeof(struct statisticsV8_8)) { DEBUGMSGTL(("mibII/mta_sendmail.c:open_sendmailst", "looks like file \"%s\" has been created by sendmail V8.8.x\n", sendmailst_fn)); stat_nf = (((struct statisticsV8_8 *) stats)->stat_nf); stat_bf = (((struct statisticsV8_8 *) stats)->stat_bf); stat_nt = (((struct statisticsV8_8 *) stats)->stat_nt); stat_bt = (((struct statisticsV8_8 *) stats)->stat_bt); stat_nr = (long *) NULL; stat_nd = (long *) NULL; stats_size = sizeof(struct statisticsV8_8); } else { print_error(LOG_WARNING, config, FALSE, "mibII/mta_sendmail.c:open_sendmailst", "could not guess version of statistics file \"%s\"", sendmailst_fn); while (close(sendmailst_fh) == -1 && errno == EINTR) { /* * do nothing */ } sendmailst_fh = -1; } } } /**/ static void count_queuegroup(struct QGrp *qg) { struct QDir *d; char cwd[SNMP_MAXPATH]; time_t current_time = time(NULL); if (current_time <= (qg->last + dir_cache_time)) { return; } if (getcwd(cwd, sizeof cwd) == NULL) { snmp_log(LOG_ERR, "mibII/mta_sendmail.c:count_queuegroup: could not get current working directory\n"); return; } qg->count = 0; qg->size = 0; for (d = qg->dirs; d != NULL; d = d->next) { DIR *dp; struct dirent *dirp; struct stat filestat; if (chdir(d->dir) != 0) continue; dp = opendir("."); if (dp == NULL) continue; while ((dirp = readdir(dp)) != NULL) { if (dirp->d_name[0] == 'd' && dirp->d_name[1] == 'f') { if (stat(dirp->d_name, &filestat) == 0) { qg->size += (filestat.st_size + 999) / 1000; } } else if (dirp->d_name[0] == 'q' && dirp->d_name[1] == 'f') { qg->count++; } } closedir(dp); } qg->last = current_time; NETSNMP_IGNORE_RESULT(chdir(cwd)); } /** static void add_queuegroup(const char *name, const char *path) * * Description: * * Adds a queuegroup of 'name' with root path 'path' to the static * list of queue groups. if 'path' ends in a *, we expand it out to * all matching subdirs. also look for 'qf' subdirectories. * * Parameters: * * qgname: name of the queuegroup discovered * path: path of queuegroup discovered */ static void add_queuegroup(const char *name, char *path) { char parentdir[FILENAMELEN]; char *p; struct QDir *new = NULL; struct QDir *subdir = NULL; DIR *dp; struct dirent *dirp; if (nqgrps == MAXQUEUEGROUPS) { /* * xxx error */ return; } if (strlen(path) > FILENAMELEN - 10) { /* * xxx error */ return; } p = path + strlen(path) - 1; if (*p == '*') { /* multiple queue dirs */ /* * remove * */ *p = '\0'; strlcpy(parentdir, path, sizeof(parentdir)); /* * remove last directory component from parentdir */ for (p = parentdir + strlen(parentdir) - 1; p >= parentdir; p--) { if (*p == '/') { *p = '\0'; break; } } if (p < parentdir) { /* * no trailing / ?!? */ /* * xxx error */ return; } p++; /* * p is now the prefix we need to match */ if ((dp = opendir(parentdir)) == NULL) { /* * xxx can't open parentdir */ return; } while ((dirp = readdir(dp)) != NULL) { if (!strncmp(dirp->d_name, p, strlen(p)) && dirp->d_name[0] != '.') { /* * match, add it to the list */ /* * single queue directory */ if ((subdir = calloc(1, sizeof(*subdir))) != NULL && asprintf(&subdir->dir, "%s/%s", parentdir, dirp->d_name) >= 0) { subdir->next = new; new = subdir; } else { free(subdir); } } } closedir(dp); } else { /* * single queue directory */ new = malloc(sizeof(*new)); new->dir = strdup(path); new->next = NULL; } /* * check 'new' for /qf directories */ for (subdir = new; subdir != NULL; subdir = subdir->next) { char *qf = NULL; if (asprintf(&qf, "%s/qf", subdir->dir) >= 0 && (dp = opendir(qf)) != NULL) { /* * it exists ! */ free(subdir->dir); subdir->dir = qf; qf = NULL; closedir(dp); } free(qf); } /* * we now have the list of directories in 'new'; create the queuegroup * object */ qgrps[nqgrps].name = strdup(name); qgrps[nqgrps].last = 0; qgrps[nqgrps].count = 0; qgrps[nqgrps].size = 0; qgrps[nqgrps].dirs = new; nqgrps++; } /** static BOOL read_sendmailcf(BOOL config) * * Description: * * Tries to open the file named in sendmailcf_fn and to get the names of * the mailers, the status file and the mailqueue directories. * * Parameters: * * config: TRUE if function has been called during the configuration process * * Returns: * * TRUE : config file has been successfully opened * * FALSE : could not open config file * */ static BOOL read_sendmailcf(BOOL config) { FILE *sendmailcf_fp; char line[500]; char *filename; char *qgname, *p; int linenr; int linelen; int found_sendmailst = FALSE; int i; sendmailcf_fp = fopen(sendmailcf_fn, "r"); if (sendmailcf_fp == NULL) { print_error(LOG_ERR, config, TRUE, "mibII/mta_sendmail.c:read_sendmailcf", "could not open file \"%s\"", sendmailcf_fn); return FALSE; } /* * initializes the standard mailers, which aren't necessarily mentioned in the sendmail.cf file */ strcpy(mailernames[0], "prog"); strcpy(mailernames[1], "*file*"); strcpy(mailernames[2], "*include*"); mailers = 3; /* * reset queuegroups */ linenr = 1; while (fgets(line, sizeof line, sendmailcf_fp) != NULL) { linelen = strlen(line); if (line[linelen - 1] != '\n') { print_error(LOG_WARNING, config, FALSE, "mibII/mta_sendmail.c:read_sendmailcf", "line %d in config file \"%s is too long\n", linenr, sendmailcf_fn); while (fgets(line, sizeof line, sendmailcf_fp) != NULL && line[strlen(line) - 1] != '\n') { /* skip rest of the line */ /* * nothing to do */ } linenr++; continue; } line[--linelen] = '\0'; switch (line[0]) { case 'M': if (mailers < MAXMAILERS) { for (i = 1; line[i] != ',' && !isspace(line[i] & 0xFF) && line[i] != '\0' && i <= MNAMELEN; i++) { mailernames[mailers][i - 1] = line[i]; } mailernames[mailers][i - 1] = '\0'; DEBUGMSGTL(("mibII/mta_sendmail.c:read_sendmailcf", "found mailer \"%s\"\n", mailernames[mailers])); for (i = 0; i < mailers && strcmp(mailernames[mailers], mailernames[i]) != 0; i++) { /* * nothing to do */ } if (i == mailers) { mailers++; } else { if (i < 3) { DEBUGMSGTL(("mibII/mta_sendmail.c:read_sendmailcf", "mailer \"%s\" already existed, but since it's one of the predefined mailers, that's probably nothing to worry about\n", mailernames[mailers])); } else { DEBUGMSGTL(("mibII/mta_sendmail.c:read_sendmailcf", "mailer \"%s\" already existed\n", mailernames[mailers])); } mailernames[mailers][0] = '\0'; } } else { print_error(LOG_WARNING, config, FALSE, "mibII/mta_sendmail.c:read_sendmailcf", "found too many mailers in config file \"%s\"", sendmailcf_fn); } break; case 'O': switch (line[1]) { case ' ': /* * long option */ if (strncasecmp(line + 2, "StatusFile", 10) == 0) { filename = line + 12; } else if (strncasecmp(line + 2, "QueueDirectory", 14) == 0) { filename = line + 16; } else { /* * not an option we care about */ break; } /* * make sure it's the end of the option */ if (*filename != ' ' && *filename != '=') break; /* * skip WS */ while (*filename == ' ') filename++; /* * must be O