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