mirror of
https://github.com/opnsense/src.git
synced 2026-06-15 03:31:11 -04:00
mail: Don't trap signals we shouldn't.
When in interactive mode, trap SIGINT, SIGHUP, and tty-related signals. Otherwise, leave signals untouched as required by POSIX. MFC after: 1 week Sponsored by: Klara, Inc. Reviewed by: kevans Differential Revision: https://reviews.freebsd.org/D50011
This commit is contained in:
parent
873420ca1e
commit
59597032c9
5 changed files with 180 additions and 14 deletions
|
|
@ -1165,6 +1165,8 @@
|
|||
..
|
||||
m4
|
||||
..
|
||||
mail
|
||||
..
|
||||
mkimg
|
||||
..
|
||||
mktemp
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
.include <src.opts.mk>
|
||||
|
||||
CONFS= misc/mail.rc
|
||||
PROG= mail
|
||||
SRCS= version.c cmd1.c cmd2.c cmd3.c cmdtab.c collect.c edit.c fio.c \
|
||||
|
|
@ -17,4 +19,7 @@ etc-mailrc:
|
|||
cd ${.CURDIR}/misc; ${INSTALL} -o root -g wheel \
|
||||
-m 644 ${EFILES} ${DESTDIR}/etc
|
||||
|
||||
HAS_TESTS=
|
||||
SUBDIR.${MK_TESTS}= tests
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
|
|
|
|||
|
|
@ -79,16 +79,20 @@ collect(struct header *hp, int printheaders)
|
|||
* until we're in the main loop.
|
||||
*/
|
||||
(void)sigemptyset(&nset);
|
||||
(void)sigaddset(&nset, SIGINT);
|
||||
(void)sigaddset(&nset, SIGHUP);
|
||||
if (value("interactive") != NULL) {
|
||||
(void)sigaddset(&nset, SIGINT);
|
||||
(void)sigaddset(&nset, SIGHUP);
|
||||
}
|
||||
(void)sigprocmask(SIG_BLOCK, &nset, NULL);
|
||||
if ((saveint = signal(SIGINT, SIG_IGN)) != SIG_IGN)
|
||||
(void)signal(SIGINT, collint);
|
||||
if ((savehup = signal(SIGHUP, SIG_IGN)) != SIG_IGN)
|
||||
(void)signal(SIGHUP, collhup);
|
||||
savetstp = signal(SIGTSTP, collstop);
|
||||
savettou = signal(SIGTTOU, collstop);
|
||||
savettin = signal(SIGTTIN, collstop);
|
||||
if (value("interactive") != NULL) {
|
||||
if ((saveint = signal(SIGINT, SIG_IGN)) != SIG_IGN)
|
||||
(void)signal(SIGINT, collint);
|
||||
if ((savehup = signal(SIGHUP, SIG_IGN)) != SIG_IGN)
|
||||
(void)signal(SIGHUP, collhup);
|
||||
savetstp = signal(SIGTSTP, collstop);
|
||||
savettou = signal(SIGTTOU, collstop);
|
||||
savettin = signal(SIGTTIN, collstop);
|
||||
}
|
||||
if (setjmp(collabort) || setjmp(colljmp)) {
|
||||
(void)rm(tempname);
|
||||
goto err;
|
||||
|
|
@ -473,11 +477,13 @@ out:
|
|||
rewind(collf);
|
||||
noreset--;
|
||||
(void)sigprocmask(SIG_BLOCK, &nset, NULL);
|
||||
(void)signal(SIGINT, saveint);
|
||||
(void)signal(SIGHUP, savehup);
|
||||
(void)signal(SIGTSTP, savetstp);
|
||||
(void)signal(SIGTTOU, savettou);
|
||||
(void)signal(SIGTTIN, savettin);
|
||||
if (value("interactive") != NULL) {
|
||||
(void)signal(SIGINT, saveint);
|
||||
(void)signal(SIGHUP, savehup);
|
||||
(void)signal(SIGTSTP, savetstp);
|
||||
(void)signal(SIGTTOU, savettou);
|
||||
(void)signal(SIGTTIN, savettin);
|
||||
}
|
||||
(void)sigprocmask(SIG_UNBLOCK, &nset, NULL);
|
||||
return (collf);
|
||||
}
|
||||
|
|
|
|||
4
usr.bin/mail/tests/Makefile
Normal file
4
usr.bin/mail/tests/Makefile
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
PACKAGE= tests
|
||||
ATF_TESTS_C+= mail_sigint_test
|
||||
|
||||
.include <bsd.test.mk>
|
||||
149
usr.bin/mail/tests/mail_sigint_test.c
Normal file
149
usr.bin/mail/tests/mail_sigint_test.c
Normal file
|
|
@ -0,0 +1,149 @@
|
|||
/*-
|
||||
* Copyright (c) 2025 Klara, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <sys/poll.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <atf-c.h>
|
||||
|
||||
#define MAILX "mailx"
|
||||
#define BODY "hello\n"
|
||||
#define BODYLEN (sizeof(BODY) - 1)
|
||||
|
||||
/*
|
||||
* When interactive, mailx(1) should print a message on receipt of SIGINT,
|
||||
* then exit cleanly on receipt of a second.
|
||||
*
|
||||
* When not interactive, mailx(1) should terminate on receipt of SIGINT.
|
||||
*/
|
||||
static void
|
||||
mailx_sigint(bool interactive)
|
||||
{
|
||||
char obuf[1024] = "";
|
||||
char ebuf[1024] = "";
|
||||
struct pollfd fds[2];
|
||||
int ipd[2], opd[2], epd[2], spd[2];
|
||||
size_t olen = 0, elen = 0;
|
||||
ssize_t rlen;
|
||||
pid_t pid;
|
||||
int kc, status;
|
||||
|
||||
/* input, output, error, sync pipes */
|
||||
if (pipe(ipd) != 0 || pipe(opd) != 0 || pipe(epd) != 0 ||
|
||||
pipe2(spd, O_CLOEXEC) != 0)
|
||||
atf_tc_fail("failed to pipe");
|
||||
/* fork child */
|
||||
if ((pid = fork()) < 0)
|
||||
atf_tc_fail("failed to fork");
|
||||
if (pid == 0) {
|
||||
/* child */
|
||||
dup2(ipd[0], STDIN_FILENO);
|
||||
close(ipd[0]);
|
||||
close(ipd[1]);
|
||||
dup2(opd[1], STDOUT_FILENO);
|
||||
close(opd[0]);
|
||||
close(opd[1]);
|
||||
dup2(epd[1], STDERR_FILENO);
|
||||
close(epd[0]);
|
||||
close(epd[1]);
|
||||
/* force dead.letter to go to cwd */
|
||||
setenv("HOME", ".", 1);
|
||||
/* exec mailx */
|
||||
execlp(MAILX,
|
||||
MAILX,
|
||||
interactive ? "-Is" : "-s",
|
||||
"test",
|
||||
"test@example.com",
|
||||
NULL);
|
||||
_exit(2);
|
||||
}
|
||||
/* parent */
|
||||
close(ipd[0]);
|
||||
close(opd[1]);
|
||||
close(epd[1]);
|
||||
close(spd[1]);
|
||||
/* block until child execs or exits */
|
||||
(void)read(spd[0], &spd[1], sizeof(spd[1]));
|
||||
/* send one line of input */
|
||||
ATF_REQUIRE_INTEQ(BODYLEN, write(ipd[1], BODY, BODYLEN));
|
||||
/* give it a chance to process */
|
||||
poll(NULL, 0, 2000);
|
||||
/* send first SIGINT */
|
||||
ATF_CHECK_INTEQ(0, kill(pid, SIGINT));
|
||||
kc = 1;
|
||||
/* receive output until child terminates */
|
||||
fds[0].fd = opd[0];
|
||||
fds[0].events = POLLIN;
|
||||
fds[1].fd = epd[0];
|
||||
fds[1].events = POLLIN;
|
||||
for (;;) {
|
||||
if (poll(fds, 2, 1000) < 0)
|
||||
atf_tc_fail("failed to poll");
|
||||
if (fds[0].revents == POLLIN && olen < sizeof(obuf)) {
|
||||
rlen = read(opd[0], obuf + olen, sizeof(obuf) - olen - 1);
|
||||
if (rlen < 0)
|
||||
atf_tc_fail("failed to read");
|
||||
olen += rlen;
|
||||
}
|
||||
if (fds[1].revents == POLLIN && elen < sizeof(ebuf)) {
|
||||
rlen = read(epd[0], ebuf + elen, sizeof(ebuf) - elen - 1);
|
||||
if (rlen < 0)
|
||||
atf_tc_fail("failed to read");
|
||||
elen += rlen;
|
||||
}
|
||||
if (elen > 0 && kc == 1) {
|
||||
kill(pid, SIGINT);
|
||||
kc++;
|
||||
}
|
||||
if (waitpid(pid, &status, WNOHANG) == pid)
|
||||
break;
|
||||
}
|
||||
close(ipd[1]);
|
||||
close(opd[0]);
|
||||
close(epd[0]);
|
||||
close(spd[0]);
|
||||
if (interactive) {
|
||||
ATF_CHECK(WIFEXITED(status));
|
||||
ATF_CHECK_INTEQ(0, WEXITSTATUS(status));
|
||||
ATF_CHECK_INTEQ(2, kc);
|
||||
ATF_CHECK_STREQ("", obuf);
|
||||
ATF_CHECK_MATCH("Interrupt -- one more to kill letter", ebuf);
|
||||
atf_utils_compare_file("dead.letter", BODY);
|
||||
} else {
|
||||
ATF_CHECK(WIFSIGNALED(status));
|
||||
ATF_CHECK_INTEQ(SIGINT, WTERMSIG(status));
|
||||
ATF_CHECK_INTEQ(1, kc);
|
||||
ATF_CHECK_STREQ("", obuf);
|
||||
ATF_CHECK_STREQ("", ebuf);
|
||||
ATF_CHECK_INTEQ(-1, access("dead.letter", F_OK));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ATF_TC_WITHOUT_HEAD(mail_sigint_interactive);
|
||||
ATF_TC_BODY(mail_sigint_interactive, tc)
|
||||
{
|
||||
mailx_sigint(true);
|
||||
}
|
||||
|
||||
ATF_TC_WITHOUT_HEAD(mail_sigint_noninteractive);
|
||||
ATF_TC_BODY(mail_sigint_noninteractive, tc)
|
||||
{
|
||||
mailx_sigint(false);
|
||||
}
|
||||
|
||||
ATF_TP_ADD_TCS(tp)
|
||||
{
|
||||
ATF_TP_ADD_TC(tp, mail_sigint_interactive);
|
||||
ATF_TP_ADD_TC(tp, mail_sigint_noninteractive);
|
||||
return (atf_no_error());
|
||||
}
|
||||
Loading…
Reference in a new issue