From e774fb066c7e5e55bc5173ebf5a50e0a9b5e1673 Mon Sep 17 00:00:00 2001 From: Gilles Chehade Date: Sat, 6 Dec 2008 02:44:09 +0000 Subject: - teach smtpctl how to inspect queue and runqueue, it supports two commands `showqueue' which displays the content of the queue (all envelopes) `showrunqueue` which displays envelopes scheduled for delivery. The utility will be improved and extended, but for now we need at least this basic support to help debug queue-related issues. Output format is spamdb-alike: type|envelope uid|sender|recipient|last delivery date|retry count ok jacek@ --- usr.sbin/smtpd/parser.c | 4 +- usr.sbin/smtpd/parser.h | 6 +- usr.sbin/smtpd/showqueue.c | 221 ++++++++++++++++++++++++++++++++++++++++ usr.sbin/smtpd/smtpctl.c | 22 +++- usr.sbin/smtpd/smtpctl/Makefile | 4 +- 5 files changed, 251 insertions(+), 6 deletions(-) create mode 100644 usr.sbin/smtpd/showqueue.c diff --git a/usr.sbin/smtpd/parser.c b/usr.sbin/smtpd/parser.c index 8d2b5d07508..366c442ff0c 100644 --- a/usr.sbin/smtpd/parser.c +++ b/usr.sbin/smtpd/parser.c @@ -1,4 +1,4 @@ -/* $OpenBSD: parser.c,v 1.1 2008/12/05 03:28:37 gilles Exp $ */ +/* $OpenBSD: parser.c,v 1.2 2008/12/06 02:44:08 gilles Exp $ */ /* * Copyright (c) 2006 Pierre-Yves Ritschard @@ -64,6 +64,8 @@ static const struct token t_table_id[]; static const struct token t_host_id[]; static const struct token t_main[] = { + {KEYWORD, "showqueue", SHOWQUEUE, NULL}, + {KEYWORD, "showrunqueue", SHOWRUNQUEUE, NULL}, {KEYWORD, "monitor", MONITOR, NULL}, {KEYWORD, "reload", RELOAD, NULL}, {KEYWORD, "stop", SHUTDOWN, NULL}, diff --git a/usr.sbin/smtpd/parser.h b/usr.sbin/smtpd/parser.h index ff3e45b4c1d..78846c992bc 100644 --- a/usr.sbin/smtpd/parser.h +++ b/usr.sbin/smtpd/parser.h @@ -1,4 +1,4 @@ -/* $OpenBSD: parser.h,v 1.1 2008/12/05 03:28:37 gilles Exp $ */ +/* $OpenBSD: parser.h,v 1.2 2008/12/06 02:44:08 gilles Exp $ */ /* * Copyright (c) 2006 Pierre-Yves Ritschard @@ -20,7 +20,9 @@ enum actions { NONE, SHUTDOWN, RELOAD, - MONITOR + MONITOR, + SHOWQUEUE, + SHOWRUNQUEUE }; struct parse_result { diff --git a/usr.sbin/smtpd/showqueue.c b/usr.sbin/smtpd/showqueue.c new file mode 100644 index 00000000000..4e7c8241947 --- /dev/null +++ b/usr.sbin/smtpd/showqueue.c @@ -0,0 +1,221 @@ +/* $OpenBSD: showqueue.c,v 1.1 2008/12/06 02:44:08 gilles Exp $ */ + +/* + * Copyright (c) 2008 Gilles Chehade + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "smtpd.h" + +void show_queue(int); +void show_runqueue(int); +void list_bucket(char *, int); +void list_message(char *, char *, int); +void display_envelope(struct message *, int); + +void +show_queue(int flags) +{ + DIR *dirp; + struct dirent *dp; + u_int16_t bucket; + const char *errstr; + + dirp = opendir(PATH_SPOOL PATH_QUEUE); + if (dirp == NULL) + err(1, "%s", PATH_SPOOL PATH_QUEUE); + + while ((dp = readdir(dirp)) != NULL) { + if (strcmp(dp->d_name, ".") == 0 || + strcmp(dp->d_name, "..") == 0) + continue; + + bucket = strtonum(dp->d_name, 0, DIRHASH_BUCKETS - 1, &errstr); + if (errstr) { + warnx("warning: invalid bucket \"%s\" in queue.", + dp->d_name); + continue; + } + + list_bucket(dp->d_name, flags); + + } + + closedir(dirp); +} + +void +list_bucket(char *bucket, int flags) +{ + DIR *dirp; + struct dirent *dp; + char pathname[MAXPATHLEN]; + + snprintf(pathname, MAXPATHLEN, "%s/%s", PATH_SPOOL PATH_QUEUE, bucket); + + dirp = opendir(pathname); + if (dirp == NULL) + err(1, "%s", pathname); + + while ((dp = readdir(dirp)) != NULL) { + if (strcmp(dp->d_name, ".") == 0 || + strcmp(dp->d_name, "..") == 0) + continue; + + list_message(bucket, dp->d_name, flags); + } + + closedir(dirp); +} + +void +list_message(char *bucket, char *message, int flags) +{ + DIR *dirp; + struct dirent *dp; + char pathname[MAXPATHLEN]; + FILE *fp; + struct message envelope; + + snprintf(pathname, MAXPATHLEN, "%s/%s/%s%s", PATH_SPOOL PATH_QUEUE, + bucket, message, PATH_ENVELOPES); + + dirp = opendir(pathname); + if (dirp == NULL) + err(1, "%s", pathname); + + while ((dp = readdir(dirp)) != NULL) { + if (strcmp(dp->d_name, ".") == 0 || + strcmp(dp->d_name, "..") == 0) + continue; + + snprintf(pathname, MAXPATHLEN, "%s/%s/%s%s/%s", PATH_SPOOL PATH_QUEUE, + bucket, message, PATH_ENVELOPES, dp->d_name); + + fp = fopen(pathname, "r"); + if (fp == NULL) { + warn("%s", pathname); + continue; + } + + if (fread(&envelope, sizeof(struct message), 1, fp) != 1) { + warn("%s", pathname); + fclose(fp); + continue; + } + + fclose(fp); + + display_envelope(&envelope, flags); + } + + closedir(dirp); +} + +void +show_runqueue(int flags) +{ + DIR *dirp; + struct dirent *dp; + u_int16_t bucket; + const char *errstr; + char pathname[MAXPATHLEN]; + FILE *fp; + struct message envelope; + + dirp = opendir(PATH_SPOOL PATH_RUNQUEUE); + if (dirp == NULL) + err(1, "%s", PATH_SPOOL PATH_RUNQUEUE); + + while ((dp = readdir(dirp)) != NULL) { + if (strcmp(dp->d_name, ".") == 0 || + strcmp(dp->d_name, "..") == 0) + continue; + + snprintf(pathname, MAXPATHLEN, "%s/%s", PATH_SPOOL PATH_RUNQUEUE, + dp->d_name); + + fp = fopen(pathname, "r"); + if (fp == NULL) { + warn("%s", pathname); + continue; + } + + if (fread(&envelope, sizeof(struct message), 1, fp) != 1) { + warn("%s", pathname); + fclose(fp); + continue; + } + + fclose(fp); + + display_envelope(&envelope, flags); + + } + + closedir(dirp); +} + +void +display_envelope(struct message *envelope, int flags) +{ + switch (envelope->type) { + case T_MDA_MESSAGE: + printf("MDA"); + break; + case T_MTA_MESSAGE: + printf("MTA"); + break; + case T_MDA_MESSAGE|T_DAEMON_MESSAGE: + printf("MDA-DAEMON"); + break; + case T_MTA_MESSAGE|T_DAEMON_MESSAGE: + printf("MTA-DAEMON"); + break; + default: + printf("UNKNOWN"); + } + + printf("|%s|%s@%s|%s@%s|%llu|%u\n", + envelope->message_uid, + envelope->sender.user, envelope->sender.domain, + envelope->recipient.user, envelope->recipient.domain, + envelope->lasttry, + envelope->retry); +} diff --git a/usr.sbin/smtpd/smtpctl.c b/usr.sbin/smtpd/smtpctl.c index 287bb9399de..003ab999213 100644 --- a/usr.sbin/smtpd/smtpctl.c +++ b/usr.sbin/smtpd/smtpctl.c @@ -1,4 +1,4 @@ -/* $OpenBSD: smtpctl.c,v 1.1 2008/12/05 03:28:37 gilles Exp $ */ +/* $OpenBSD: smtpctl.c,v 1.2 2008/12/06 02:44:08 gilles Exp $ */ /* * Copyright (c) 2006 Pierre-Yves Ritschard @@ -44,6 +44,8 @@ __dead void usage(void); int show_command_output(struct imsg*); +void show_queue(int); +void show_runqueue(int); struct imsgname { int type; @@ -89,10 +91,28 @@ main(int argc, char *argv[]) int done = 0; int n; + /* check for root privileges */ + if (geteuid()) + errx(1, "need root privileges"); + /* parse options */ if ((res = parse(argc - 1, argv + 1)) == NULL) exit(1); + /* handle "disconnected" commands */ + switch (res->action) { + case SHOWQUEUE: + show_queue(0); + break; + case SHOWRUNQUEUE: + show_runqueue(0); + break; + default: + goto connected; + } + return 0; + +connected: /* connect to relayd control socket */ if ((ctl_sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) err(1, "socket"); diff --git a/usr.sbin/smtpd/smtpctl/Makefile b/usr.sbin/smtpd/smtpctl/Makefile index c8dba4072d6..3c3acf8c1d8 100644 --- a/usr.sbin/smtpd/smtpctl/Makefile +++ b/usr.sbin/smtpd/smtpctl/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.1 2008/12/05 03:28:37 gilles Exp $ +# $OpenBSD: Makefile,v 1.2 2008/12/06 02:44:08 gilles Exp $ .PATH: ${.CURDIR}/.. @@ -10,6 +10,6 @@ BINMODE?=555 BINDIR= /usr/bin MAN= smtpctl.8 -SRCS= smtpctl.c parser.c buffer.c imsg.c log.c +SRCS= smtpctl.c parser.c buffer.c imsg.c log.c showqueue.c LDFLAGS= -lutil .include -- cgit v1.2.3