1a9e8641dSBaptiste Daroussin /* 2e56bad4aSBaptiste Daroussin * Copyright (c) 2008-2014, Simon Schubert <2@0x2c.org>. 3a9e8641dSBaptiste Daroussin * Copyright (c) 2008 The DragonFly Project. All rights reserved. 4a9e8641dSBaptiste Daroussin * 5a9e8641dSBaptiste Daroussin * This code is derived from software contributed to The DragonFly Project 6e56bad4aSBaptiste Daroussin * by Simon Schubert <2@0x2c.org>. 7a9e8641dSBaptiste Daroussin * 8a9e8641dSBaptiste Daroussin * Redistribution and use in source and binary forms, with or without 9a9e8641dSBaptiste Daroussin * modification, are permitted provided that the following conditions 10a9e8641dSBaptiste Daroussin * are met: 11a9e8641dSBaptiste Daroussin * 12a9e8641dSBaptiste Daroussin * 1. Redistributions of source code must retain the above copyright 13a9e8641dSBaptiste Daroussin * notice, this list of conditions and the following disclaimer. 14a9e8641dSBaptiste Daroussin * 2. Redistributions in binary form must reproduce the above copyright 15a9e8641dSBaptiste Daroussin * notice, this list of conditions and the following disclaimer in 16a9e8641dSBaptiste Daroussin * the documentation and/or other materials provided with the 17a9e8641dSBaptiste Daroussin * distribution. 18a9e8641dSBaptiste Daroussin * 3. Neither the name of The DragonFly Project nor the names of its 19a9e8641dSBaptiste Daroussin * contributors may be used to endorse or promote products derived 20a9e8641dSBaptiste Daroussin * from this software without specific, prior written permission. 21a9e8641dSBaptiste Daroussin * 22a9e8641dSBaptiste Daroussin * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23a9e8641dSBaptiste Daroussin * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24a9e8641dSBaptiste Daroussin * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 25a9e8641dSBaptiste Daroussin * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 26a9e8641dSBaptiste Daroussin * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 27a9e8641dSBaptiste Daroussin * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 28a9e8641dSBaptiste Daroussin * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 29a9e8641dSBaptiste Daroussin * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 30a9e8641dSBaptiste Daroussin * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 31a9e8641dSBaptiste Daroussin * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 32a9e8641dSBaptiste Daroussin * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33a9e8641dSBaptiste Daroussin * SUCH DAMAGE. 34a9e8641dSBaptiste Daroussin */ 35a9e8641dSBaptiste Daroussin 36a9e8641dSBaptiste Daroussin #include "dfcompat.h" 37a9e8641dSBaptiste Daroussin 38a9e8641dSBaptiste Daroussin #include <sys/file.h> 39a9e8641dSBaptiste Daroussin #include <sys/stat.h> 40a9e8641dSBaptiste Daroussin 41a9e8641dSBaptiste Daroussin #include <ctype.h> 42a9e8641dSBaptiste Daroussin #include <dirent.h> 43a9e8641dSBaptiste Daroussin #include <err.h> 44a9e8641dSBaptiste Daroussin #include <errno.h> 45a9e8641dSBaptiste Daroussin #include <fcntl.h> 46a9e8641dSBaptiste Daroussin #include <inttypes.h> 47a9e8641dSBaptiste Daroussin #include <unistd.h> 48a9e8641dSBaptiste Daroussin #include <syslog.h> 49a9e8641dSBaptiste Daroussin 50a9e8641dSBaptiste Daroussin #include "dma.h" 51a9e8641dSBaptiste Daroussin 52a9e8641dSBaptiste Daroussin /* 53a9e8641dSBaptiste Daroussin * Spool file format: 54a9e8641dSBaptiste Daroussin * 55a9e8641dSBaptiste Daroussin * 'Q'id files (queue): 56a9e8641dSBaptiste Daroussin * Organized like an RFC822 header, field: value. Ignores unknown fields. 57a9e8641dSBaptiste Daroussin * ID: id 58a9e8641dSBaptiste Daroussin * Sender: envelope-from 59a9e8641dSBaptiste Daroussin * Recipient: envelope-to 60a9e8641dSBaptiste Daroussin * 61a9e8641dSBaptiste Daroussin * 'M'id files (data): 62a9e8641dSBaptiste Daroussin * mail data 63a9e8641dSBaptiste Daroussin * 64a9e8641dSBaptiste Daroussin * Each queue file needs to have a corresponding data file. 65a9e8641dSBaptiste Daroussin * One data file might be shared by linking it several times. 66a9e8641dSBaptiste Daroussin * 67a9e8641dSBaptiste Daroussin * Queue ids are unique, formed from the inode of the data file 68a9e8641dSBaptiste Daroussin * and a unique identifier. 69a9e8641dSBaptiste Daroussin */ 70a9e8641dSBaptiste Daroussin 71a9e8641dSBaptiste Daroussin int 72a9e8641dSBaptiste Daroussin newspoolf(struct queue *queue) 73a9e8641dSBaptiste Daroussin { 74a9e8641dSBaptiste Daroussin char fn[PATH_MAX+1]; 75a9e8641dSBaptiste Daroussin struct stat st; 76a9e8641dSBaptiste Daroussin struct stritem *t; 77a9e8641dSBaptiste Daroussin int fd; 78a9e8641dSBaptiste Daroussin 79a9e8641dSBaptiste Daroussin if (snprintf(fn, sizeof(fn), "%s/%s", config.spooldir, "tmp_XXXXXXXXXX") <= 0) 80a9e8641dSBaptiste Daroussin return (-1); 81a9e8641dSBaptiste Daroussin 82a9e8641dSBaptiste Daroussin fd = mkstemp(fn); 83a9e8641dSBaptiste Daroussin if (fd < 0) 84a9e8641dSBaptiste Daroussin return (-1); 85a9e8641dSBaptiste Daroussin /* XXX group rights */ 86a9e8641dSBaptiste Daroussin if (fchmod(fd, 0660) < 0) 87a9e8641dSBaptiste Daroussin goto fail; 88a9e8641dSBaptiste Daroussin if (flock(fd, LOCK_EX) == -1) 89a9e8641dSBaptiste Daroussin goto fail; 90a9e8641dSBaptiste Daroussin queue->tmpf = strdup(fn); 91a9e8641dSBaptiste Daroussin if (queue->tmpf == NULL) 92a9e8641dSBaptiste Daroussin goto fail; 93a9e8641dSBaptiste Daroussin 94a9e8641dSBaptiste Daroussin /* 95a9e8641dSBaptiste Daroussin * Assign queue id 96a9e8641dSBaptiste Daroussin */ 97a9e8641dSBaptiste Daroussin if (fstat(fd, &st) != 0) 98a9e8641dSBaptiste Daroussin goto fail; 99a9e8641dSBaptiste Daroussin if (asprintf(&queue->id, "%"PRIxMAX, (uintmax_t)st.st_ino) < 0) 100a9e8641dSBaptiste Daroussin goto fail; 101a9e8641dSBaptiste Daroussin 102a9e8641dSBaptiste Daroussin queue->mailf = fdopen(fd, "r+"); 103a9e8641dSBaptiste Daroussin if (queue->mailf == NULL) 104a9e8641dSBaptiste Daroussin goto fail; 105a9e8641dSBaptiste Daroussin 106a9e8641dSBaptiste Daroussin t = malloc(sizeof(*t)); 107a9e8641dSBaptiste Daroussin if (t != NULL) { 108a9e8641dSBaptiste Daroussin t->str = queue->tmpf; 109a9e8641dSBaptiste Daroussin SLIST_INSERT_HEAD(&tmpfs, t, next); 110a9e8641dSBaptiste Daroussin } 111a9e8641dSBaptiste Daroussin return (0); 112a9e8641dSBaptiste Daroussin 113a9e8641dSBaptiste Daroussin fail: 114a9e8641dSBaptiste Daroussin if (queue->mailf != NULL) 115a9e8641dSBaptiste Daroussin fclose(queue->mailf); 116a9e8641dSBaptiste Daroussin close(fd); 117a9e8641dSBaptiste Daroussin unlink(fn); 118a9e8641dSBaptiste Daroussin return (-1); 119a9e8641dSBaptiste Daroussin } 120a9e8641dSBaptiste Daroussin 121a9e8641dSBaptiste Daroussin static int 122a9e8641dSBaptiste Daroussin writequeuef(struct qitem *it) 123a9e8641dSBaptiste Daroussin { 124a9e8641dSBaptiste Daroussin int error; 125a9e8641dSBaptiste Daroussin int queuefd; 126a9e8641dSBaptiste Daroussin 127a9e8641dSBaptiste Daroussin queuefd = open_locked(it->queuefn, O_CREAT|O_EXCL|O_RDWR, 0660); 128a9e8641dSBaptiste Daroussin if (queuefd == -1) 129a9e8641dSBaptiste Daroussin return (-1); 130a9e8641dSBaptiste Daroussin if (fchmod(queuefd, 0660) < 0) 131a9e8641dSBaptiste Daroussin return (-1); 132a9e8641dSBaptiste Daroussin it->queuef = fdopen(queuefd, "w+"); 133a9e8641dSBaptiste Daroussin if (it->queuef == NULL) 134a9e8641dSBaptiste Daroussin return (-1); 135a9e8641dSBaptiste Daroussin 136a9e8641dSBaptiste Daroussin error = fprintf(it->queuef, 137a9e8641dSBaptiste Daroussin "ID: %s\n" 138a9e8641dSBaptiste Daroussin "Sender: %s\n" 139a9e8641dSBaptiste Daroussin "Recipient: %s\n", 140a9e8641dSBaptiste Daroussin it->queueid, 141a9e8641dSBaptiste Daroussin it->sender, 142a9e8641dSBaptiste Daroussin it->addr); 143a9e8641dSBaptiste Daroussin 144a9e8641dSBaptiste Daroussin if (error <= 0) 145a9e8641dSBaptiste Daroussin return (-1); 146a9e8641dSBaptiste Daroussin 147a9e8641dSBaptiste Daroussin if (fflush(it->queuef) != 0 || fsync(fileno(it->queuef)) != 0) 148a9e8641dSBaptiste Daroussin return (-1); 149a9e8641dSBaptiste Daroussin 150a9e8641dSBaptiste Daroussin return (0); 151a9e8641dSBaptiste Daroussin } 152a9e8641dSBaptiste Daroussin 153a9e8641dSBaptiste Daroussin static struct qitem * 154a9e8641dSBaptiste Daroussin readqueuef(struct queue *queue, char *queuefn) 155a9e8641dSBaptiste Daroussin { 156a9e8641dSBaptiste Daroussin char line[1000]; 157a9e8641dSBaptiste Daroussin struct queue itmqueue; 158a9e8641dSBaptiste Daroussin FILE *queuef = NULL; 159a9e8641dSBaptiste Daroussin char *s; 160a9e8641dSBaptiste Daroussin char *queueid = NULL, *sender = NULL, *addr = NULL; 161a9e8641dSBaptiste Daroussin struct qitem *it = NULL; 162a9e8641dSBaptiste Daroussin 163a9e8641dSBaptiste Daroussin bzero(&itmqueue, sizeof(itmqueue)); 164a9e8641dSBaptiste Daroussin LIST_INIT(&itmqueue.queue); 165a9e8641dSBaptiste Daroussin 166a9e8641dSBaptiste Daroussin queuef = fopen(queuefn, "r"); 167a9e8641dSBaptiste Daroussin if (queuef == NULL) 168a9e8641dSBaptiste Daroussin goto out; 169a9e8641dSBaptiste Daroussin 170a9e8641dSBaptiste Daroussin while (!feof(queuef)) { 171a9e8641dSBaptiste Daroussin if (fgets(line, sizeof(line), queuef) == NULL || line[0] == 0) 172a9e8641dSBaptiste Daroussin break; 173a9e8641dSBaptiste Daroussin line[strlen(line) - 1] = 0; /* chop newline */ 174a9e8641dSBaptiste Daroussin 175a9e8641dSBaptiste Daroussin s = strchr(line, ':'); 176a9e8641dSBaptiste Daroussin if (s == NULL) 177a9e8641dSBaptiste Daroussin goto malformed; 178a9e8641dSBaptiste Daroussin *s = 0; 179a9e8641dSBaptiste Daroussin 180a9e8641dSBaptiste Daroussin s++; 181a9e8641dSBaptiste Daroussin while (isspace(*s)) 182a9e8641dSBaptiste Daroussin s++; 183a9e8641dSBaptiste Daroussin 184a9e8641dSBaptiste Daroussin s = strdup(s); 185a9e8641dSBaptiste Daroussin if (s == NULL) 186a9e8641dSBaptiste Daroussin goto malformed; 187a9e8641dSBaptiste Daroussin 188a9e8641dSBaptiste Daroussin if (strcmp(line, "ID") == 0) { 189a9e8641dSBaptiste Daroussin queueid = s; 190a9e8641dSBaptiste Daroussin } else if (strcmp(line, "Sender") == 0) { 191a9e8641dSBaptiste Daroussin sender = s; 192a9e8641dSBaptiste Daroussin } else if (strcmp(line, "Recipient") == 0) { 193a9e8641dSBaptiste Daroussin addr = s; 194a9e8641dSBaptiste Daroussin } else { 195a9e8641dSBaptiste Daroussin syslog(LOG_DEBUG, "ignoring unknown queue info `%s' in `%s'", 196a9e8641dSBaptiste Daroussin line, queuefn); 197a9e8641dSBaptiste Daroussin free(s); 198a9e8641dSBaptiste Daroussin } 199a9e8641dSBaptiste Daroussin } 200a9e8641dSBaptiste Daroussin 201a9e8641dSBaptiste Daroussin if (queueid == NULL || sender == NULL || addr == NULL || 202a9e8641dSBaptiste Daroussin *queueid == 0 || *addr == 0) { 203a9e8641dSBaptiste Daroussin malformed: 204a9e8641dSBaptiste Daroussin errno = EINVAL; 205a9e8641dSBaptiste Daroussin syslog(LOG_ERR, "malformed queue file `%s'", queuefn); 206a9e8641dSBaptiste Daroussin goto out; 207a9e8641dSBaptiste Daroussin } 208a9e8641dSBaptiste Daroussin 209a9e8641dSBaptiste Daroussin if (add_recp(&itmqueue, addr, 0) != 0) 210a9e8641dSBaptiste Daroussin goto out; 211a9e8641dSBaptiste Daroussin 212a9e8641dSBaptiste Daroussin it = LIST_FIRST(&itmqueue.queue); 213a9e8641dSBaptiste Daroussin it->sender = sender; sender = NULL; 214a9e8641dSBaptiste Daroussin it->queueid = queueid; queueid = NULL; 215a9e8641dSBaptiste Daroussin it->queuefn = queuefn; queuefn = NULL; 216a9e8641dSBaptiste Daroussin LIST_INSERT_HEAD(&queue->queue, it, next); 217a9e8641dSBaptiste Daroussin 218a9e8641dSBaptiste Daroussin out: 219a9e8641dSBaptiste Daroussin if (sender != NULL) 220a9e8641dSBaptiste Daroussin free(sender); 221a9e8641dSBaptiste Daroussin if (queueid != NULL) 222a9e8641dSBaptiste Daroussin free(queueid); 223a9e8641dSBaptiste Daroussin if (addr != NULL) 224a9e8641dSBaptiste Daroussin free(addr); 225a9e8641dSBaptiste Daroussin if (queuef != NULL) 226a9e8641dSBaptiste Daroussin fclose(queuef); 227a9e8641dSBaptiste Daroussin 228a9e8641dSBaptiste Daroussin return (it); 229a9e8641dSBaptiste Daroussin } 230a9e8641dSBaptiste Daroussin 231a9e8641dSBaptiste Daroussin int 232a9e8641dSBaptiste Daroussin linkspool(struct queue *queue) 233a9e8641dSBaptiste Daroussin { 234a9e8641dSBaptiste Daroussin struct stat st; 235a9e8641dSBaptiste Daroussin struct qitem *it; 236a9e8641dSBaptiste Daroussin 237a9e8641dSBaptiste Daroussin if (fflush(queue->mailf) != 0 || fsync(fileno(queue->mailf)) != 0) 238a9e8641dSBaptiste Daroussin goto delfiles; 239a9e8641dSBaptiste Daroussin 240a9e8641dSBaptiste Daroussin syslog(LOG_INFO, "new mail from user=%s uid=%d envelope_from=<%s>", 241a9e8641dSBaptiste Daroussin username, getuid(), queue->sender); 242a9e8641dSBaptiste Daroussin 243a9e8641dSBaptiste Daroussin LIST_FOREACH(it, &queue->queue, next) { 244a9e8641dSBaptiste Daroussin if (asprintf(&it->queueid, "%s.%"PRIxPTR, queue->id, (uintptr_t)it) <= 0) 245a9e8641dSBaptiste Daroussin goto delfiles; 246a9e8641dSBaptiste Daroussin if (asprintf(&it->queuefn, "%s/Q%s", config.spooldir, it->queueid) <= 0) 247a9e8641dSBaptiste Daroussin goto delfiles; 248a9e8641dSBaptiste Daroussin if (asprintf(&it->mailfn, "%s/M%s", config.spooldir, it->queueid) <= 0) 249a9e8641dSBaptiste Daroussin goto delfiles; 250a9e8641dSBaptiste Daroussin 251a9e8641dSBaptiste Daroussin /* Neither file may not exist yet */ 252a9e8641dSBaptiste Daroussin if (stat(it->queuefn, &st) == 0 || stat(it->mailfn, &st) == 0) 253a9e8641dSBaptiste Daroussin goto delfiles; 254a9e8641dSBaptiste Daroussin 255a9e8641dSBaptiste Daroussin if (writequeuef(it) != 0) 256a9e8641dSBaptiste Daroussin goto delfiles; 257a9e8641dSBaptiste Daroussin 258a9e8641dSBaptiste Daroussin if (link(queue->tmpf, it->mailfn) != 0) 259a9e8641dSBaptiste Daroussin goto delfiles; 260a9e8641dSBaptiste Daroussin } 261a9e8641dSBaptiste Daroussin 262a9e8641dSBaptiste Daroussin LIST_FOREACH(it, &queue->queue, next) { 263a9e8641dSBaptiste Daroussin syslog(LOG_INFO, "mail to=<%s> queued as %s", 264a9e8641dSBaptiste Daroussin it->addr, it->queueid); 265a9e8641dSBaptiste Daroussin } 266a9e8641dSBaptiste Daroussin 267a9e8641dSBaptiste Daroussin unlink(queue->tmpf); 268a9e8641dSBaptiste Daroussin return (0); 269a9e8641dSBaptiste Daroussin 270a9e8641dSBaptiste Daroussin delfiles: 271a9e8641dSBaptiste Daroussin LIST_FOREACH(it, &queue->queue, next) { 272a9e8641dSBaptiste Daroussin unlink(it->mailfn); 273a9e8641dSBaptiste Daroussin unlink(it->queuefn); 274a9e8641dSBaptiste Daroussin } 275a9e8641dSBaptiste Daroussin return (-1); 276a9e8641dSBaptiste Daroussin } 277a9e8641dSBaptiste Daroussin 278a9e8641dSBaptiste Daroussin int 279a9e8641dSBaptiste Daroussin load_queue(struct queue *queue) 280a9e8641dSBaptiste Daroussin { 281a9e8641dSBaptiste Daroussin struct stat sb; 282a9e8641dSBaptiste Daroussin struct qitem *it; 283a9e8641dSBaptiste Daroussin DIR *spooldir; 284a9e8641dSBaptiste Daroussin struct dirent *de; 285a9e8641dSBaptiste Daroussin char *queuefn; 286a9e8641dSBaptiste Daroussin char *mailfn; 287a9e8641dSBaptiste Daroussin 288a9e8641dSBaptiste Daroussin bzero(queue, sizeof(*queue)); 289a9e8641dSBaptiste Daroussin LIST_INIT(&queue->queue); 290a9e8641dSBaptiste Daroussin 291a9e8641dSBaptiste Daroussin spooldir = opendir(config.spooldir); 292a9e8641dSBaptiste Daroussin if (spooldir == NULL) 293e56bad4aSBaptiste Daroussin err(EX_NOINPUT, "reading queue"); 294a9e8641dSBaptiste Daroussin 295a9e8641dSBaptiste Daroussin while ((de = readdir(spooldir)) != NULL) { 296a9e8641dSBaptiste Daroussin queuefn = NULL; 297a9e8641dSBaptiste Daroussin mailfn = NULL; 298a9e8641dSBaptiste Daroussin 299a9e8641dSBaptiste Daroussin /* ignore non-queue files */ 300a9e8641dSBaptiste Daroussin if (de->d_name[0] != 'Q') 301a9e8641dSBaptiste Daroussin continue; 302a9e8641dSBaptiste Daroussin if (asprintf(&queuefn, "%s/Q%s", config.spooldir, de->d_name + 1) < 0) 303a9e8641dSBaptiste Daroussin goto fail; 304a9e8641dSBaptiste Daroussin if (asprintf(&mailfn, "%s/M%s", config.spooldir, de->d_name + 1) < 0) 305a9e8641dSBaptiste Daroussin goto fail; 306a9e8641dSBaptiste Daroussin 307a9e8641dSBaptiste Daroussin /* 308a9e8641dSBaptiste Daroussin * Some file systems don't provide a de->d_type, so we have to 309a9e8641dSBaptiste Daroussin * do an explicit stat on the queue file. 310a9e8641dSBaptiste Daroussin * Move on if it turns out to be something else than a file. 311a9e8641dSBaptiste Daroussin */ 312a9e8641dSBaptiste Daroussin if (stat(queuefn, &sb) != 0) 313a9e8641dSBaptiste Daroussin goto skip_item; 314a9e8641dSBaptiste Daroussin if (!S_ISREG(sb.st_mode)) { 315a9e8641dSBaptiste Daroussin errno = EINVAL; 316a9e8641dSBaptiste Daroussin goto skip_item; 317a9e8641dSBaptiste Daroussin } 318a9e8641dSBaptiste Daroussin 319a9e8641dSBaptiste Daroussin if (stat(mailfn, &sb) != 0) 320a9e8641dSBaptiste Daroussin goto skip_item; 321a9e8641dSBaptiste Daroussin 322a9e8641dSBaptiste Daroussin it = readqueuef(queue, queuefn); 323a9e8641dSBaptiste Daroussin if (it == NULL) 324a9e8641dSBaptiste Daroussin goto skip_item; 325a9e8641dSBaptiste Daroussin 326a9e8641dSBaptiste Daroussin it->mailfn = mailfn; 327a9e8641dSBaptiste Daroussin continue; 328a9e8641dSBaptiste Daroussin 329a9e8641dSBaptiste Daroussin skip_item: 330a9e8641dSBaptiste Daroussin syslog(LOG_INFO, "could not pick up queue file: `%s'/`%s': %m", queuefn, mailfn); 331a9e8641dSBaptiste Daroussin if (queuefn != NULL) 332a9e8641dSBaptiste Daroussin free(queuefn); 333a9e8641dSBaptiste Daroussin if (mailfn != NULL) 334a9e8641dSBaptiste Daroussin free(mailfn); 335a9e8641dSBaptiste Daroussin } 336a9e8641dSBaptiste Daroussin closedir(spooldir); 337a9e8641dSBaptiste Daroussin return (0); 338a9e8641dSBaptiste Daroussin 339a9e8641dSBaptiste Daroussin fail: 340a9e8641dSBaptiste Daroussin return (-1); 341a9e8641dSBaptiste Daroussin } 342a9e8641dSBaptiste Daroussin 343a9e8641dSBaptiste Daroussin void 344a9e8641dSBaptiste Daroussin delqueue(struct qitem *it) 345a9e8641dSBaptiste Daroussin { 346a9e8641dSBaptiste Daroussin unlink(it->mailfn); 347a9e8641dSBaptiste Daroussin unlink(it->queuefn); 348a9e8641dSBaptiste Daroussin if (it->queuef != NULL) 349a9e8641dSBaptiste Daroussin fclose(it->queuef); 350a9e8641dSBaptiste Daroussin if (it->mailf != NULL) 351a9e8641dSBaptiste Daroussin fclose(it->mailf); 352a9e8641dSBaptiste Daroussin free(it); 353a9e8641dSBaptiste Daroussin } 354a9e8641dSBaptiste Daroussin 355a9e8641dSBaptiste Daroussin int 356a9e8641dSBaptiste Daroussin acquirespool(struct qitem *it) 357a9e8641dSBaptiste Daroussin { 358a9e8641dSBaptiste Daroussin int queuefd; 359a9e8641dSBaptiste Daroussin 360a9e8641dSBaptiste Daroussin if (it->queuef == NULL) { 361a9e8641dSBaptiste Daroussin queuefd = open_locked(it->queuefn, O_RDWR|O_NONBLOCK); 362a9e8641dSBaptiste Daroussin if (queuefd < 0) 363a9e8641dSBaptiste Daroussin goto fail; 364a9e8641dSBaptiste Daroussin it->queuef = fdopen(queuefd, "r+"); 365a9e8641dSBaptiste Daroussin if (it->queuef == NULL) 366a9e8641dSBaptiste Daroussin goto fail; 367a9e8641dSBaptiste Daroussin } 368a9e8641dSBaptiste Daroussin 369a9e8641dSBaptiste Daroussin if (it->mailf == NULL) { 370a9e8641dSBaptiste Daroussin it->mailf = fopen(it->mailfn, "r"); 371a9e8641dSBaptiste Daroussin if (it->mailf == NULL) 372a9e8641dSBaptiste Daroussin goto fail; 373a9e8641dSBaptiste Daroussin } 374a9e8641dSBaptiste Daroussin 375a9e8641dSBaptiste Daroussin return (0); 376a9e8641dSBaptiste Daroussin 377a9e8641dSBaptiste Daroussin fail: 378a9e8641dSBaptiste Daroussin if (errno == EWOULDBLOCK) 379a9e8641dSBaptiste Daroussin return (1); 380a9e8641dSBaptiste Daroussin syslog(LOG_INFO, "could not acquire queue file: %m"); 381a9e8641dSBaptiste Daroussin return (-1); 382a9e8641dSBaptiste Daroussin } 383a9e8641dSBaptiste Daroussin 384a9e8641dSBaptiste Daroussin void 385a9e8641dSBaptiste Daroussin dropspool(struct queue *queue, struct qitem *keep) 386a9e8641dSBaptiste Daroussin { 387a9e8641dSBaptiste Daroussin struct qitem *it; 388a9e8641dSBaptiste Daroussin 389a9e8641dSBaptiste Daroussin LIST_FOREACH(it, &queue->queue, next) { 390a9e8641dSBaptiste Daroussin if (it == keep) 391a9e8641dSBaptiste Daroussin continue; 392a9e8641dSBaptiste Daroussin 393a9e8641dSBaptiste Daroussin if (it->queuef != NULL) 394a9e8641dSBaptiste Daroussin fclose(it->queuef); 395a9e8641dSBaptiste Daroussin if (it->mailf != NULL) 396a9e8641dSBaptiste Daroussin fclose(it->mailf); 397a9e8641dSBaptiste Daroussin } 398a9e8641dSBaptiste Daroussin } 399a9e8641dSBaptiste Daroussin 400a9e8641dSBaptiste Daroussin int 401a9e8641dSBaptiste Daroussin flushqueue_since(unsigned int period) 402a9e8641dSBaptiste Daroussin { 403a9e8641dSBaptiste Daroussin struct stat st; 404a9e8641dSBaptiste Daroussin struct timeval now; 405a9e8641dSBaptiste Daroussin char *flushfn = NULL; 406a9e8641dSBaptiste Daroussin 407a9e8641dSBaptiste Daroussin if (asprintf(&flushfn, "%s/%s", config.spooldir, SPOOL_FLUSHFILE) < 0) 408a9e8641dSBaptiste Daroussin return (0); 409a9e8641dSBaptiste Daroussin if (stat(flushfn, &st) < 0) { 410a9e8641dSBaptiste Daroussin free(flushfn); 411a9e8641dSBaptiste Daroussin return (0); 412a9e8641dSBaptiste Daroussin } 413a9e8641dSBaptiste Daroussin free(flushfn); 414a9e8641dSBaptiste Daroussin flushfn = NULL; 415a9e8641dSBaptiste Daroussin if (gettimeofday(&now, 0) != 0) 416a9e8641dSBaptiste Daroussin return (0); 417a9e8641dSBaptiste Daroussin 418a9e8641dSBaptiste Daroussin /* Did the flush file get touched within the last period seconds? */ 419461918e2SBaptiste Daroussin if (st.st_mtim.tv_sec + (int)period >= now.tv_sec) 420a9e8641dSBaptiste Daroussin return (1); 421a9e8641dSBaptiste Daroussin else 422a9e8641dSBaptiste Daroussin return (0); 423a9e8641dSBaptiste Daroussin } 424a9e8641dSBaptiste Daroussin 425a9e8641dSBaptiste Daroussin int 426a9e8641dSBaptiste Daroussin flushqueue_signal(void) 427a9e8641dSBaptiste Daroussin { 428a9e8641dSBaptiste Daroussin char *flushfn = NULL; 429a9e8641dSBaptiste Daroussin int fd; 430a9e8641dSBaptiste Daroussin 431a9e8641dSBaptiste Daroussin if (asprintf(&flushfn, "%s/%s", config.spooldir, SPOOL_FLUSHFILE) < 0) 432a9e8641dSBaptiste Daroussin return (-1); 433a9e8641dSBaptiste Daroussin fd = open(flushfn, O_CREAT|O_WRONLY|O_TRUNC, 0660); 434a9e8641dSBaptiste Daroussin free(flushfn); 435a9e8641dSBaptiste Daroussin if (fd < 0) { 436a9e8641dSBaptiste Daroussin syslog(LOG_ERR, "could not open flush file: %m"); 437a9e8641dSBaptiste Daroussin return (-1); 438a9e8641dSBaptiste Daroussin } 439a9e8641dSBaptiste Daroussin close(fd); 440a9e8641dSBaptiste Daroussin return (0); 441a9e8641dSBaptiste Daroussin } 442