[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Bug-tar] [patch v3] Bug / question in tar
From: |
Sergey Poznyakoff |
Subject: |
Re: [Bug-tar] [patch v3] Bug / question in tar |
Date: |
Thu, 20 Mar 2014 16:51:24 +0200 |
Hello,
As a follow-up to our discussion, here is a patch that refuses
to read archives from or write them to a tty (that latter doesn't
seem to have much sense either) and uses a "tty emulator" instead of
script for testing.
Opinions?
Regards,
Sergey
>From ab6173ea602709551545bfa02d1253dfb2416c81 Mon Sep 17 00:00:00 2001
From: Sergey Poznyakoff <address@hidden>
Date: Thu, 20 Mar 2014 16:28:25 +0200
Subject: [PATCH] Fail if archive comes from or is written to a terminal.
Based on patch from Pavel Raiskup <address@hidden>.
* gnulib.modules: Add new modules.
* src/buffer.c (_open_archive): Refuse to read and write archive to
a tty.
* tests/Makefile.am (TESTSUITE_AT): Add iotty.at
(check_PROGRAMS): New program ttyemu
* tests/testsuite.at: Include iotty.at
* tests/iotty.at: New file.
* tests/ttyemu.c: New file.
---
gnulib.modules | 4 +
src/buffer.c | 9 +-
tests/Makefile.am | 5 +-
tests/iotty.at | 49 ++++++
tests/testsuite.at | 1 +
tests/ttyemu.c | 449 +++++++++++++++++++++++++++++++++++++++++++++++++++++
6 files changed, 515 insertions(+), 2 deletions(-)
create mode 100644 tests/iotty.at
create mode 100644 tests/ttyemu.c
diff --git a/gnulib.modules b/gnulib.modules
index 25e8ab3..3ba06b6 100644
--- a/gnulib.modules
+++ b/gnulib.modules
@@ -49,6 +49,7 @@ getpagesize
gettext
gettime
gitlog-to-changelog
+grantpt
hash
human
inttostr
@@ -64,6 +65,8 @@ modechange
obstack
openat
parse-datetime
+posix_openpt
+ptsname
priv-set
progname
quote
@@ -92,6 +95,7 @@ timespec
unlinkat
unlinkdir
unlocked-io
+unlockpt
utimensat
version-etc-fsf
xalloc
diff --git a/src/buffer.c b/src/buffer.c
index 95e8a26..cbde29f 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -723,6 +723,14 @@ _open_archive (enum access_mode wanted_access)
if (verify_option)
FATAL_ERROR ((0, 0, _("Cannot verify stdin/stdout archive")));
+ if (isatty (archive))
+ FATAL_ERROR ((0, 0,
+ wanted_access == ACCESS_WRITE
+ ? _("Writing archive contents to terminal "
+ "output is not possible (missing -f option?)")
+ : _("Reading archive contents from terminal "
+ "input is not possible (missing -f option?)")));
+
switch (wanted_access)
{
case ACCESS_READ:
@@ -731,7 +739,6 @@ _open_archive (enum access_mode wanted_access)
enum compress_type type;
archive = STDIN_FILENO;
-
type = check_compressed_archive (&shortfile);
if (type != ct_tar && type != ct_none)
FATAL_ERROR ((0, 0,
diff --git a/tests/Makefile.am b/tests/Makefile.am
index d4c9362..3896b72 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -116,6 +116,7 @@ TESTSUITE_AT = \
incr09.at\
indexfile.at\
ignfail.at\
+ iotty.at\
label01.at\
label02.at\
label03.at\
@@ -261,10 +262,12 @@ installcheck-local:
## genfile ##
## ------------ ##
-check_PROGRAMS = genfile
+check_PROGRAMS = genfile ttyemu
genfile_SOURCES = genfile.c argcv.c argcv.h
+ttyemu_SOURCES = ttyemu.c
+
localedir = $(datadir)/locale
AM_CPPFLAGS = \
-I$(top_srcdir)/gnu\
diff --git a/tests/iotty.at b/tests/iotty.at
new file mode 100644
index 0000000..21cd71a
--- /dev/null
+++ b/tests/iotty.at
@@ -0,0 +1,49 @@
+# Process this file with autom4te to create testsuite. -*- Autotest -*-
+
+# Test suite for GNU tar.
+# Copyright 2014 Free Software Foundation, Inc.
+
+# This file is part of GNU tar.
+
+# GNU tar is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+
+# GNU tar is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# Ensure that we may not put/read archive contents to/from terminal
+# output/input.
+#
+# Original report:
+# http://lists.gnu.org/archive/html/bug-tar/2014-03/msg00033.html
+
+AT_SETUP([terminal input/output])
+AT_KEYWORDS([options iotty])
+
+AT_TAR_CHECK([
+genfile --file file
+TAPE=-
+export TAPE
+ttyemu -t5 -i/dev/null tar -c f
+echo $?
+ttyemu -t5 -i/dev/null tar -x
+echo $?
+],
+[0],
+[tar: Writing archive contents to terminal output is not possible (missing -f
option?)
+tar: Error is not recoverable: exiting now
+2
+tar: Reading archive contents from terminal input is not possible (missing -f
option?)
+tar: Error is not recoverable: exiting now
+2
+],
+[],[],[],[posix, gnu, oldgnu])
+
+AT_CLEANUP
diff --git a/tests/testsuite.at b/tests/testsuite.at
index c52890b..3096e0d 100644
--- a/tests/testsuite.at
+++ b/tests/testsuite.at
@@ -213,6 +213,7 @@ m4_include([gzip.at])
m4_include([recurse.at])
m4_include([recurs02.at])
m4_include([shortrec.at])
+m4_include([iotty.at])
AT_BANNER([The --same-order option])
m4_include([same-order01.at])
diff --git a/tests/ttyemu.c b/tests/ttyemu.c
new file mode 100644
index 0000000..c904f78
--- /dev/null
+++ b/tests/ttyemu.c
@@ -0,0 +1,449 @@
+/* Run program with its first three file descriptors attached to a tty.
+
+ Copyright 2014 Free Software Foundation, Inc.
+
+ This file is part of GNU tar.
+
+ GNU tar is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ GNU tar is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#define _XOPEN_SOURCE 600
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <signal.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/select.h>
+#include <termios.h>
+#include <sys/ioctl.h>
+
+#ifndef TCSASOFT
+# define TCSASOFT 0
+#endif
+
+#define C_EOT 4
+
+#define EX_OK 0
+#define EX_USAGE 125
+#define EX_ERR 126
+#define EX_EXEC 127
+
+#define BUF_SIZE 1024
+
+#if 0
+# define DEBUG(c) fprintf (stderr, "%s\n", c)
+#else
+# define DEBUG(c)
+#endif
+
+struct buffer
+{
+ char buf[BUF_SIZE];
+ int avail;
+ int written;
+ int cr;
+ time_t ts;
+};
+
+#define shut(fildes) \
+ do \
+ { \
+ DEBUG (("closing " #fildes)); \
+ close(fildes); \
+ fildes = -1; \
+ } \
+ while(0)
+
+#define bufinit(buffer,all) \
+ do \
+ { \
+ (buffer).avail = (buffer).written = 0; \
+ (buffer).ts = time (NULL); \
+ if (all) \
+ (buffer).cr = 0; \
+ } \
+ while(0)
+
+#define bufisempty(buffer) ((buffer).avail == (buffer).written)
+#define bufavail(buffer) (BUF_SIZE - (buffer).avail)
+
+#define bufread(buffer,fildes,tty) \
+ do \
+ { \
+ int r = read (fildes, (buffer).buf + (buffer).avail, \
+ BUF_SIZE - (buffer).avail); \
+ (buffer).ts = time (NULL); \
+ if (r < 0) \
+ { \
+ if (errno == EINTR) \
+ continue; \
+ if (tty && errno == EIO) \
+ shut (fildes); \
+ else \
+ { \
+ fprintf (stderr, "%s:%d: reading from %s: %s", \
+ __FILE__,__LINE__,#fildes, strerror (errno)); \
+ exit (EX_ERR); \
+ } \
+ } \
+ else if (r == 0) \
+ shut (fildes); \
+ else \
+ (buffer).avail += r; \
+ } \
+ while(0)
+
+#define bufwrite(buffer,fildes)
\
+ do \
+ { \
+ int r = write (fildes, (buffer).buf + (buffer).written, \
+ (buffer).avail - (buffer).written); \
+ (buffer).ts = time (NULL); \
+ if (r < 0) \
+ { \
+ if (errno == EINTR) \
+ continue; \
+ if (stop) \
+ shut (fildes); \
+ else \
+ { \
+ perror ("writing"); \
+ exit (EX_ERR); \
+ } \
+ } \
+ else if (r == 0) \
+ /*shut (fildes)*/; \
+ else \
+ (buffer).written += r; \
+ } \
+ while(0)
+
+void
+tr (struct buffer *bp)
+{
+ int i, j;
+
+ for (i = j = bp->written; i < bp->avail;)
+ {
+ if (bp->buf[i] == '\r')
+ {
+ bp->cr = 1;
+ i++;
+ }
+ else
+ {
+ if (bp->cr)
+ {
+ bp->cr = 0;
+ if (bp->buf[i] != '\n')
+ bp->buf[j++] = '\r';
+ }
+ bp->buf[j++] = bp->buf[i++];
+ }
+ }
+ bp->avail = j;
+}
+
+int stop;
+int status;
+
+void
+sigchld (int sig)
+{
+ DEBUG (("child exited"));
+ wait (&status);
+ stop = 1;
+}
+
+void
+noecho (int fd)
+{
+ struct termios to;
+
+ if (tcgetattr (fd, &to))
+ {
+ perror ("tcgetattr");
+ exit (EX_ERR);
+ }
+ to.c_lflag |= ICANON;
+ to.c_lflag &= ~(ECHO | ISIG);
+ to.c_cc[VEOF] = C_EOT;
+ if (tcsetattr (fd, TCSAFLUSH | TCSASOFT, &to))
+ {
+ perror ("tcgetattr");
+ exit (EX_ERR);
+ }
+}
+
+char *usage_text[] = {
+ "usage: ttyemu [-ah] [-i infile] [-o outfile] PROGRAM [ARGS...]",
+ "",
+ "Report bugs and suggestions to <address@hidden>.",
+ NULL
+};
+
+static void
+usage (void)
+{
+ int i;
+
+ for (i = 0; usage_text[i]; i++)
+ {
+ fputs (usage_text[i], stderr);
+ fputc ('\n', stderr);
+ }
+}
+
+int
+main (int argc, char **argv)
+{
+ int i;
+ int master, slave;
+ pid_t pid;
+ fd_set rdset, wrset;
+ struct buffer ibuf, obuf;
+ int in = 0, out = 1;
+ char *infile = NULL, *outfile = NULL;
+ int outflags = O_TRUNC;
+ int maxfd;
+ int eot = C_EOT;
+ int timeout = 0;
+
+ while ((i = getopt (argc, argv, "ai:o:t:h")) != EOF)
+ {
+ switch (i)
+ {
+ case 'a':
+ outflags &= ~O_TRUNC;
+ break;
+
+ case 'i':
+ infile = optarg;
+ break;
+
+ case 'o':
+ outfile = optarg;
+ break;
+
+ case 't':
+ timeout = atoi (optarg);
+ break;
+
+ case 'h':
+ usage ();
+ return EX_OK;
+
+ default:
+ return EX_USAGE;
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (argc == 0)
+ {
+ usage ();
+ return EX_USAGE;
+ }
+
+ if (infile)
+ {
+ in = open (infile, O_RDONLY);
+ if (in == -1)
+ {
+ perror (infile);
+ return EX_ERR;
+ }
+ }
+
+ if (outfile)
+ {
+ out = open (outfile, O_RDWR|O_CREAT|outflags, 0666);
+ if (out == -1)
+ {
+ perror (outfile);
+ return EX_ERR;
+ }
+ }
+
+ master = posix_openpt (O_RDWR);
+ if (master == -1)
+ {
+ perror ("posix_openpty");
+ return EX_ERR;
+ }
+
+ if (grantpt (master))
+ {
+ perror ("grantpt");
+ return EX_ERR;
+ }
+
+ if (unlockpt (master))
+ {
+ perror ("unlockpt");
+ return EX_ERR;
+ }
+
+ signal (SIGCHLD, sigchld);
+
+ pid = fork ();
+ if (pid == -1)
+ {
+ perror ("fork");
+ return EX_ERR;
+ }
+
+ if (pid == 0)
+ {
+ slave = open (ptsname (master), O_RDWR);
+ if (slave < 0)
+ {
+ perror ("open");
+ return EX_ERR;
+ }
+
+ noecho (slave);
+ for (i = 0; i < 3; i++)
+ {
+ if (slave != i)
+ {
+ close (i);
+ if (dup (slave) != i)
+ {
+ perror ("dup");
+ _exit (EX_EXEC);
+ }
+ }
+ }
+ for (i = sysconf (_SC_OPEN_MAX) - 1; i > 2; --i)
+ close (i);
+
+ setsid ();
+ ioctl (0, TIOCSCTTY, 1);
+
+ execvp (argv[0], argv);
+ perror (argv[0]);
+ _exit (EX_EXEC);
+ }
+ sleep (1);
+
+ bufinit (ibuf, 1);
+ bufinit (obuf, 1);
+ while (1)
+ {
+ FD_ZERO (&rdset);
+ FD_ZERO (&wrset);
+
+ maxfd = 0;
+
+ if (in != -1)
+ {
+ FD_SET (in, &rdset);
+ if (in > maxfd)
+ maxfd = in;
+ }
+
+ if (master != -1)
+ {
+ FD_SET (master, &rdset);
+ if (!stop)
+ FD_SET (master, &wrset);
+ if (master > maxfd)
+ maxfd = master;
+ }
+
+ if (maxfd == 0)
+ {
+ if (stop)
+ break;
+ pause ();
+ continue;
+ }
+
+ if (select (maxfd + 1, &rdset, &wrset, NULL, NULL) < 0)
+ {
+ if (errno == EINTR)
+ continue;
+ perror ("select");
+ return EX_ERR;
+ }
+
+ if (timeout)
+ {
+ time_t now = time (NULL);
+ if (now - ibuf.ts > timeout || now - obuf.ts > timeout)
+ {
+ fprintf (stderr, "ttyemu: I/O timeout\n");
+ return EX_ERR;
+ }
+ }
+
+ if (in >= 0)
+ {
+ if (bufavail (ibuf) && FD_ISSET (in, &rdset))
+ bufread (ibuf, in, 0);
+ }
+ else if (master == -1)
+ break;
+
+ if (master >= 0 && FD_ISSET (master, &wrset))
+ {
+ if (!bufisempty (ibuf))
+ bufwrite (ibuf, master);
+ else if (in == -1 && eot)
+ {
+ DEBUG (("sent EOT"));
+ if (write (master, &eot, 1) <= 0)
+ {
+ perror ("write");
+ return EX_ERR;
+ }
+ eot = 0;
+ }
+ }
+
+ if (master >= 0 && bufavail (obuf) && FD_ISSET (master, &rdset))
+ bufread (obuf, master, 1);
+
+ if (bufisempty (obuf))
+ bufinit (obuf, 0);
+ else
+ {
+ tr (&obuf);
+ bufwrite (obuf, out);
+ }
+
+ if (bufisempty (ibuf))
+ bufinit (ibuf, 0);
+ }
+
+ if (WIFEXITED (status))
+ return WEXITSTATUS (status);
+
+ if (WIFSIGNALED (status))
+ fprintf (stderr, "ttyemu: child process %s failed on signal %d\n",
+ argv[0], WTERMSIG (status));
+ else
+ fprintf (stderr, "ttyemu: child process %s failed\n", argv[0]);
+ return EX_EXEC;
+}
--
1.7.12.1
- Re: [Bug-tar] [patch v3] Bug / question in tar, (continued)
- Re: [Bug-tar] [patch v3] Bug / question in tar, Markus Steinborn, 2014/03/13
- Re: [Bug-tar] [patch v3] Bug / question in tar, Eric Blake, 2014/03/13
- Re: [Bug-tar] [patch v3] Bug / question in tar, Pavel Raiskup, 2014/03/13
- Re: [Bug-tar] [patch v3] Bug / question in tar, Paul Eggert, 2014/03/13
- Re: [Bug-tar] [patch v3] Bug / question in tar, Pavel Raiskup, 2014/03/13
- Re: [Bug-tar] [patch v3] Bug / question in tar, Paul Eggert, 2014/03/13
- Re: [Bug-tar] [patch v3] Bug / question in tar, Pavel Raiskup, 2014/03/13
- Re: [Bug-tar] [patch v3] Bug / question in tar, Sergey Poznyakoff, 2014/03/14
- Re: [Bug-tar] [patch v3] Bug / question in tar, Pavel Raiskup, 2014/03/14
- Re: [Bug-tar] [patch v3] Bug / question in tar, Markus Steinborn, 2014/03/13
- Re: [Bug-tar] [patch v3] Bug / question in tar,
Sergey Poznyakoff <=
- Re: [Bug-tar] [patch v3] Bug / question in tar, Pavel Raiskup, 2014/03/20
- Re: [Bug-tar] [patch v3] Bug / question in tar, Sergey Poznyakoff, 2014/03/20
- Re: [Bug-tar] [patch v3] Bug / question in tar, Sergey Poznyakoff, 2014/03/20
- Re: [Bug-tar] [patch v3] Bug / question in tar, Antonio Diaz Diaz, 2014/03/20
- Re: [Bug-tar] [patch v3] Bug / question in tar, Eric Blake, 2014/03/20
- Re: [Bug-tar] [patch v3] Bug / question in tar, Karl Berry, 2014/03/20
- Re: [Bug-tar] [patch v3] Bug / question in tar, Paul Eggert, 2014/03/20
- Re: [Bug-tar] [patch v3] Bug / question in tar, Karl Berry, 2014/03/20
- Re: [Bug-tar] [patch v3] Bug / question in tar, Karl Berry, 2014/03/25
- Re: [Bug-tar] [patch v3] Bug / question in tar, Pavel Raiskup, 2014/03/26