summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Faurot <eric@cvs.openbsd.org>2012-08-26 17:08:42 +0000
committerEric Faurot <eric@cvs.openbsd.org>2012-08-26 17:08:42 +0000
commite9ecc4fb9961a0dad05b7014e0f6c4b8fc8b4745 (patch)
tree825449151dea1e154df99a86120d189ae61b78ed
parent50253e5fb8651091511f245c3df2248abff80bf6 (diff)
sane rewrite of the disk-queue traversal code, and log bogus files found
in there. fixes issues reported by many. ok gilles@
-rw-r--r--usr.sbin/smtpd/queue_fsqueue.c193
1 files changed, 68 insertions, 125 deletions
diff --git a/usr.sbin/smtpd/queue_fsqueue.c b/usr.sbin/smtpd/queue_fsqueue.c
index 1b5503b0da0..625418c8f99 100644
--- a/usr.sbin/smtpd/queue_fsqueue.c
+++ b/usr.sbin/smtpd/queue_fsqueue.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: queue_fsqueue.c,v 1.51 2012/08/24 13:13:13 chl Exp $ */
+/* $OpenBSD: queue_fsqueue.c,v 1.52 2012/08/26 17:08:41 eric Exp $ */
/*
* Copyright (c) 2011 Gilles Chehade <gilles@openbsd.org>
@@ -24,11 +24,11 @@
#include <sys/stat.h>
#include <ctype.h>
-#include <dirent.h>
#include <err.h>
#include <errno.h>
#include <event.h>
#include <fcntl.h>
+#include <fts.h>
#include <imsg.h>
#include <inttypes.h>
#include <libgen.h>
@@ -438,154 +438,97 @@ fsqueue_envelope(enum queue_op qop, uint64_t *evpid, char *buf, size_t len)
return 0;
}
-#define QWALK_AGAIN 0x1
-#define QWALK_RECURSE 0x2
-#define QWALK_RETURN 0x3
-
struct qwalk {
- char path[MAXPATHLEN];
- DIR *dirs[3];
- int (*filefn)(struct qwalk *, char *);
- int bucket;
- int level;
+ FTS *fts;
uint32_t msgid;
+ int depth;
};
-static int walk_queue(struct qwalk *, char *);
-
static void *
fsqueue_qwalk_new(uint32_t msgid)
{
- struct qwalk *q;
-
- q = calloc(1, sizeof(struct qwalk));
- if (q == NULL)
- fatal("qwalk_new: calloc");
-
- strlcpy(q->path, PATH_QUEUE, sizeof(q->path));
+ char path[MAXPATHLEN];
+ char * const path_argv[] = { path, NULL };
+ struct qwalk *q;
- q->level = 0;
+ q = xcalloc(1, sizeof(*q), "fsqueue_qwalk_new");
q->msgid = msgid;
+ strlcpy(path, PATH_QUEUE, sizeof(path));
+ q->fts = fts_open(path_argv,
+ FTS_PHYSICAL | FTS_NOCHDIR, NULL);
- if (q->msgid) {
- /* force level and bucket */
- q->bucket = q->msgid & 0xff;
- q->level = 2;
- if (! bsnprintf(q->path, sizeof(q->path), "%s/%02x/%08x%s",
- PATH_QUEUE, q->bucket, q->msgid, PATH_ENVELOPES))
- fatalx("walk_queue: snprintf");
- }
- q->filefn = walk_queue;
- q->dirs[q->level] = opendir(q->path);
- if (q->dirs[q->level] == NULL)
- fatal("qwalk_new: opendir");
+ if (q->fts == NULL)
+ err(1, "fsqueue_qwalk_new: fts_open: %s", path);
return (q);
}
-static int
-fsqueue_qwalk(void *hdl, uint64_t *evpid)
-{
- struct qwalk *q = hdl;
- struct dirent *dp;
-
-again:
- errno = 0;
- dp = readdir(q->dirs[q->level]);
- if (errno)
- fatal("qwalk: readdir");
- if (dp == NULL) {
- closedir(q->dirs[q->level]);
- q->dirs[q->level] = NULL;
- if (q->level == 0 || q->msgid)
- return (0);
- q->level--;
- goto again;
- }
-
- if (strcmp(dp->d_name, ".") == 0 || strcmp(dp->d_name, "..") == 0)
- goto again;
-
- switch (q->filefn(q, dp->d_name)) {
- case QWALK_AGAIN:
- goto again;
- case QWALK_RECURSE:
- goto recurse;
- case QWALK_RETURN: {
- char *endptr;
-
- errno = 0;
- *evpid = (uint64_t)strtoull(dp->d_name, &endptr, 16);
- if (q->path[0] == '\0' || *endptr != '\0')
- goto again;
- if (errno == ERANGE && *evpid == ULLONG_MAX)
- goto again;
- if (q->msgid)
- if (evpid_to_msgid(*evpid) != q->msgid)
- return 0;
-
- return (1);
- }
- default:
- fatalx("qwalk: callback failed");
- }
-
-recurse:
- q->level++;
- q->dirs[q->level] = opendir(q->path);
- if (q->dirs[q->level] == NULL) {
- if (errno == ENOENT) {
- q->level--;
- goto again;
- }
- fatal("qwalk: opendir");
- }
- goto again;
-}
-
static void
fsqueue_qwalk_close(void *hdl)
{
- int i;
- struct qwalk *q = hdl;
+ struct qwalk *q = hdl;
- for (i = 0; i <= q->level; i++)
- if (q->dirs[i])
- closedir(q->dirs[i]);
+ fts_close(q->fts);
- bzero(q, sizeof(struct qwalk));
free(q);
}
static int
-walk_queue(struct qwalk *q, char *fname)
+fsqueue_qwalk(void *hdl, uint64_t *evpid)
{
- char *ep;
-
- switch (q->level) {
- case 0:
- q->bucket = strtoul(fname, &ep, 16);
- if (fname[0] == '\0' || *ep != '\0') {
- log_warnx("walk_queue: invalid bucket: %s", fname);
- return (QWALK_AGAIN);
- }
- if (errno == ERANGE || q->bucket >= DIRHASH_BUCKETS) {
- log_warnx("walk_queue: invalid bucket: %s", fname);
- return (QWALK_AGAIN);
+ struct qwalk *q = hdl;
+ FTSENT *e;
+ char *tmp;
+ uint32_t msgid;
+
+ while ((e = fts_read(q->fts)) != NULL) {
+
+ switch(e->fts_info) {
+ case FTS_D:
+ q->depth += 1;
+ if (q->depth == 2 && e->fts_namelen != 2) {
+ log_debug("fsqueue: bogus directory %s",
+ e->fts_path);
+ fts_set(q->fts, e, FTS_SKIP);
+ break;
+ }
+ if (q->depth == 3 && e->fts_namelen != 8) {
+ log_debug("fsqueue: bogus directory %s",
+ e->fts_path);
+ fts_set(q->fts, e, FTS_SKIP);
+ break;
+ }
+ if (q->msgid && (q->depth == 2 || q->depth == 3)) {
+ msgid = strtoull(e->fts_name, &tmp, 16);
+ if (msgid != (q->depth == 1) ?
+ (q->msgid & 0xff) : q->msgid) {
+ fts_set(q->fts, e, FTS_SKIP);
+ break;
+ }
+ }
+ break;
+
+ case FTS_DP:
+ q->depth -= 1;
+ break;
+
+ case FTS_F:
+ if (q->depth != 4)
+ break;
+ if (e->fts_namelen != 16)
+ break;
+ tmp = NULL;
+ *evpid = strtoull(e->fts_name, &tmp, 16);
+ if (tmp && *tmp != '\0') {
+ log_debug("fsqueue: bogus file %s",
+ e->fts_path);
+ break;
+ }
+ return (1);
+ default:
+ break;
}
- if (! bsnprintf(q->path, sizeof(q->path), "%s/%02x",
- PATH_QUEUE, q->bucket & 0xff))
- fatalx("walk_queue: snprintf");
- return (QWALK_RECURSE);
- case 1:
- if (! bsnprintf(q->path, sizeof(q->path), "%s/%02x/%s%s",
- PATH_QUEUE, q->bucket & 0xff, fname,
- PATH_ENVELOPES))
- fatalx("walk_queue: snprintf");
- return (QWALK_RECURSE);
- case 2:
- return (QWALK_RETURN);
}
- return (-1);
+ return (0);
}