1330449Seadler/*- 2330449Seadler * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3330449Seadler * 416880Sgpalmer * Copyright (c) 1996, Gary J. Palmer 516880Sgpalmer * All rights reserved. 616880Sgpalmer * 716880Sgpalmer * Redistribution and use in source and binary forms, with or without 816880Sgpalmer * modification, are permitted provided that the following conditions 916880Sgpalmer * are met: 1016880Sgpalmer * 1116880Sgpalmer * 1. Redistributions of source code must retain the above copyright 1216880Sgpalmer * notice, this list of conditions and the following disclaimer, 1316880Sgpalmer * verbatim and that no modifications are made prior to this 1416880Sgpalmer * point in the file. 1516880Sgpalmer * 2. Redistributions in binary form must reproduce the above copyright 1616880Sgpalmer * notice, this list of conditions and the following disclaimer in the 1716880Sgpalmer * documentation and/or other materials provided with the distribution. 1816880Sgpalmer * 1916880Sgpalmer * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 2016880Sgpalmer * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2116880Sgpalmer * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2216880Sgpalmer * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2316880Sgpalmer * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2416880Sgpalmer * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2516880Sgpalmer * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2616880Sgpalmer * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2716880Sgpalmer * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2816880Sgpalmer * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2916880Sgpalmer * SUCH DAMAGE. 3016880Sgpalmer * 3150479Speter * $FreeBSD: stable/11/usr.sbin/ctm/ctm_dequeue/ctm_dequeue.c 330449 2018-03-05 07:26:05Z eadler $ 3216880Sgpalmer */ 3316880Sgpalmer 3419984Smckay/* 3519984Smckay * ctm_dequeue: Dequeue queued delta pieces and mail them. 3619984Smckay * 3719984Smckay * The pieces have already been packaged up as mail messages by ctm_smail, 3819984Smckay * and will be simply passed to sendmail in alphabetical order. 3916880Sgpalmer */ 4016880Sgpalmer 4116880Sgpalmer#include <stdio.h> 4216880Sgpalmer#include <stdlib.h> 4316880Sgpalmer#include <string.h> 4416880Sgpalmer#include <unistd.h> 4516880Sgpalmer#include <fcntl.h> 4616880Sgpalmer#include <sys/types.h> 4716880Sgpalmer#include <sys/stat.h> 4819984Smckay#include <sys/wait.h> 4916880Sgpalmer#include <fts.h> 5019984Smckay#include <limits.h> 5116880Sgpalmer#include <errno.h> 5216880Sgpalmer#include <paths.h> 5316880Sgpalmer#include "error.h" 5416880Sgpalmer#include "options.h" 5516880Sgpalmer 5619984Smckay#define DEFAULT_NUM 1 /* Default number of pieces mailed per run. */ 5719984Smckay 58103726Swollmanint fts_sort(const FTSENT * const *, const FTSENT * const *); 5919984Smckayint run_sendmail(int ifd); 6016880Sgpalmer 6116880Sgpalmerint 6216880Sgpalmermain(int argc, char **argv) 6316880Sgpalmer{ 6416880Sgpalmer char *log_file = NULL; 6516880Sgpalmer char *queue_dir = NULL; 6616880Sgpalmer char *list[2]; 6719984Smckay int num_to_send = DEFAULT_NUM, chunk; 6819984Smckay int fd; 6916880Sgpalmer FTS *fts; 7016880Sgpalmer FTSENT *ftsent; 7119984Smckay int piece, npieces; 7219984Smckay char filename[PATH_MAX]; 7316880Sgpalmer 7416880Sgpalmer err_prog_name(argv[0]); 7516880Sgpalmer 7616880Sgpalmer OPTIONS("[-l log] [-n num] queuedir") 7716880Sgpalmer NUMBER('n', num_to_send) 7816880Sgpalmer STRING('l', log_file) 7919984Smckay ENDOPTS 8016880Sgpalmer 8116880Sgpalmer if (argc != 2) 8216880Sgpalmer usage(); 8316880Sgpalmer 8418119Speter if (log_file) 8518119Speter err_set_log(log_file); 8618119Speter 8716880Sgpalmer queue_dir = argv[1]; 8816880Sgpalmer list[0] = queue_dir; 8916880Sgpalmer list[1] = NULL; 9016880Sgpalmer 9119984Smckay fts = fts_open(list, FTS_PHYSICAL|FTS_COMFOLLOW, fts_sort); 9216880Sgpalmer if (fts == NULL) 9316880Sgpalmer { 9416880Sgpalmer err("fts failed on `%s'", queue_dir); 9516880Sgpalmer exit(1); 9616880Sgpalmer } 9716880Sgpalmer 9819984Smckay ftsent = fts_read(fts); 9919984Smckay if (ftsent == NULL || ftsent->fts_info != FTS_D) 10016880Sgpalmer { 10119984Smckay err("not a directory: %s", queue_dir); 10219984Smckay exit(1); 10316880Sgpalmer } 10416880Sgpalmer 10519984Smckay ftsent = fts_children(fts, 0); 10619984Smckay if (ftsent == NULL && errno) 10716880Sgpalmer { 10819984Smckay err("*ftschildren failed"); 10916880Sgpalmer exit(1); 11016880Sgpalmer } 11116880Sgpalmer 11219984Smckay for (chunk = 1; ftsent != NULL; ftsent = ftsent->fts_link) 11316880Sgpalmer { 11419984Smckay /* 11519984Smckay * Skip non-files and ctm_smail tmp files (ones starting with `.') 11619984Smckay */ 11719984Smckay if (ftsent->fts_info != FTS_F || ftsent->fts_name[0] == '.') 11819984Smckay continue; 11916880Sgpalmer 12019984Smckay sprintf(filename, "%s/%s", queue_dir, ftsent->fts_name); 12119984Smckay fd = open(filename, O_RDONLY); 12219984Smckay if (fd < 0) 12316880Sgpalmer { 12419984Smckay err("*open: %s", filename); 12516880Sgpalmer exit(1); 12616880Sgpalmer } 12716880Sgpalmer 12819984Smckay if (run_sendmail(fd)) 12916880Sgpalmer exit(1); 13016880Sgpalmer 13119984Smckay close(fd); 13216880Sgpalmer 13317131Sgpalmer if (unlink(filename) < 0) 13417131Sgpalmer { 13519984Smckay err("*unlink: %s", filename); 13617131Sgpalmer exit(1); 13717131Sgpalmer } 13816880Sgpalmer 13919984Smckay /* 14019984Smckay * Deduce the delta, piece number, and number of pieces from 14119984Smckay * the name of the file in the queue. Ideally, we should be 14219984Smckay * able to get the mail alias name too. 14319984Smckay * 14419984Smckay * NOTE: This depends intimately on the queue name used in ctm_smail. 14519984Smckay */ 14619984Smckay npieces = atoi(&ftsent->fts_name[ftsent->fts_namelen-3]); 14719984Smckay piece = atoi(&ftsent->fts_name[ftsent->fts_namelen-7]); 148228659Sdim err("%.*s %d/%d sent", (int)(ftsent->fts_namelen-8), ftsent->fts_name, 14919984Smckay piece, npieces); 15016880Sgpalmer 15119984Smckay if (chunk++ == num_to_send) 15217131Sgpalmer break; 15316880Sgpalmer } 15417131Sgpalmer 15519984Smckay fts_close(fts); 15619984Smckay 15716880Sgpalmer return(0); 15816880Sgpalmer} 15916880Sgpalmer 16016880Sgpalmerint 161103726Swollmanfts_sort(const FTSENT * const * a, const FTSENT * const * b) 16216880Sgpalmer{ 16319984Smckay if ((*a)->fts_info != FTS_F) 16419984Smckay return(0); 16519984Smckay if ((*a)->fts_info != FTS_F) 16619984Smckay return(0); 16716880Sgpalmer 16819984Smckay return (strcmp((*a)->fts_name, (*b)->fts_name)); 16916880Sgpalmer} 17016880Sgpalmer 17116880Sgpalmer/* 17219984Smckay * Run sendmail with the given file descriptor as standard input. 17319984Smckay * Sendmail will decode the destination from the message contents. 17419984Smckay * Returns 0 on success, 1 on failure. 17516880Sgpalmer */ 17616880Sgpalmerint 17719984Smckayrun_sendmail(int ifd) 17816880Sgpalmer{ 17919984Smckay pid_t child, pid; 18016880Sgpalmer int status; 18119984Smckay 18219984Smckay switch (child = fork()) 18316880Sgpalmer { 18419984Smckay case -1: 18519984Smckay err("*fork"); 18619984Smckay return(1); 18719984Smckay 18819984Smckay case 0: /* Child */ 18919984Smckay dup2(ifd, 0); 19079452Sbrian execl(_PATH_SENDMAIL, _PATH_SENDMAIL, "-odq", "-t", (char *)NULL); 19119984Smckay err("*exec: %s", _PATH_SENDMAIL); 19219984Smckay _exit(1); 19319984Smckay 19419984Smckay default: /* Parent */ 19519984Smckay while ((pid = wait(&status)) != child) 19619984Smckay { 19719984Smckay if (pid == -1 && errno != EINTR) 19819984Smckay { 19919984Smckay err("*wait"); 20019984Smckay return(1); 20119984Smckay } 20219984Smckay } 20319984Smckay if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) 20419984Smckay { 20519984Smckay err("sendmail failed"); 20619984Smckay return(1); 20719984Smckay } 20816880Sgpalmer } 20919984Smckay 21019984Smckay return(0); 21116880Sgpalmer} 212