Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 2 Jan 2000 02:59:34 +0100 (CET)
From:      Christian Weisgerber <naddy@mips.rhein-neckar.de>
To:        FreeBSD-gnats-submit@freebsd.org
Subject:   bin/15830: PATCH: rdump over ssh
Message-ID:  <200001020159.CAA88226@bigeye.rhein-neckar.de>

next in thread | raw e-mail | index | archive | help

>Number:         15830
>Category:       bin
>Synopsis:       PATCH: rdump over ssh
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          change-request
>Submitter-Id:   current-users
>Arrival-Date:   Sat Jan  1 18:10:01 PST 2000
>Closed-Date:
>Last-Modified:
>Originator:     Christian Weisgerber
>Release:        FreeBSD 4.0-CURRENT i386
>Organization:
>Environment:

>Description:

The included patch adds to dump/restore the capability to access
tape devices on remote hosts over an arbitrary rsh-like program.
In particular, this is intended to allow the use of ssh.

Currently, dump/restore offer remote tape access using rcmd(3) to
call rmt on the remote host. This patch adds a flag "-P <rshcmd>"
to spawn a coprocess using <rshcmd>, in lieu of rcmd(3). "-P" was
chosen because it is used for the same purpose by rdist(1). Most
of the actual code has been taken from rdist, too.

Issues:

* The biggest chunk of the patch is the addition of a dump/rshrcmd.c
  module, which is almost literally copied from rdist/rshrcmd.c.
  Alas, the latter can't be used directly. The module adds the
  function rshrcmd(), which is mostly a drop-in replacement for
  rcmd(), transparently calling a rsh-like program.

  - rdist uses a local function error() to display error messages,
    dump uses msg(). This could be handled by compiling with
    -Derror=msg or by adding error() as wrapper for msg(). Both
    solutions appear questionable to me.

  - If the operator presses the interrupt character (^C), SIGINT
    is delivered to all processes in the foreground process group.
    The five processes spawned by the dump command variously catch
    or ignore SIGINT. The operator is offered a choice of aborting
    or continuing the dump run. Alas, the coprocess also receives
    the SIGINT, and ssh apparently installs a handler and terminates
    on SIGINT, so the whole dump run would always abort on interrupt.

    Diverging from the rdist code, I solved this by putting the
    coprocess in its own process group. I'm not sure I fully
    understand all the consequences of this, but it works. An
    interrupt doesn't kill the dump run, and if I forcefully
    terminate dump, the coprocess dies along with it.

* rshrcmd() doesn't really handle rcmd()'s final "fd2p" argument.
  Adding this appears to be rather complex, judging by the rcmd
  code. Considering the limited use (added post 4.4Lite) this sees
  in dump, I think it is a negligible omission.

* I didn't add "#ifdef RDUMP" around the changes, since I couldn't
  decide whether this is appropriate.

>How-To-Repeat:

Usage example:
$ dump 0aPf ssh host:/dev/nrsa0 /

>Fix:

diff -u -uNr /usr/src/sbin/dump/Makefile dump/Makefile
--- /usr/src/sbin/dump/Makefile	Tue Oct 26 21:47:56 1999
+++ dump/Makefile	Sat Jan  1 20:06:13 2000
@@ -17,7 +17,8 @@
 LINKS=	${BINDIR}/dump ${BINDIR}/rdump
 CFLAGS+=-DRDUMP
 CFLAGS+=-I${.CURDIR}/../../libexec/rlogind
-SRCS=	itime.c main.c optr.c dumprmt.c tape.c traverse.c unctime.c
+SRCS=	itime.c main.c optr.c dumprmt.c tape.c traverse.c unctime.c \
+	rshrcmd.c
 BINGRP=	tty
 BINMODE=2555
 MAN8=	dump.8
diff -u -uNr /usr/src/sbin/dump/dump.8 dump/dump.8
--- /usr/src/sbin/dump/dump.8	Sat Sep 11 03:51:55 1999
+++ dump/dump.8	Sat Jan  1 22:18:54 2000
@@ -47,6 +47,7 @@
 .Op Fl d Ar density
 .Op Fl f Ar file
 .Op Fl h Ar level
+.Op Fl P Ar rshcmd
 .Op Fl s Ar feet
 .Op Fl T Ar date
 .Ar filesystem
@@ -177,6 +178,13 @@
 .Dq operator
 by means similar to a
 .Xr wall 1 .
+.It Fl P Ar rshcmd
+Program to provide
+.Xr rsh 1 -like Ns
+transport to the remote tape server.
+It must provide a binary-transparent path to the remote host
+and must have a command argument syntax that is compatible with
+.Xr rsh 1 .
 .It Fl s Ar feet
 Attempt to calculate the amount of tape needed
 at a particular density.
diff -u -uNr /usr/src/sbin/dump/dump.h dump/dump.h
--- /usr/src/sbin/dump/dump.h	Tue Jul 14 11:19:45 1998
+++ dump/dump.h	Sat Jan  1 20:42:34 2000
@@ -102,7 +102,7 @@
 void	timeest __P((void));
 time_t	unctime __P((char *str));
 
-/* mapping rouintes */
+/* mapping routines */
 struct	dinode;
 long	blockest __P((struct dinode *dp));
 int	mapfiles __P((ino_t maxino, long *tapesize));
@@ -137,6 +137,8 @@
 int	rmtopen __P((char *tape, int mode));
 int	rmtwrite __P((char *buf, int count));
 #endif /* RDUMP */
+int	rshrcmd __P((char **ahost, u_short port, char *luser, char *ruser,
+		     char *cmd, int *fd2p));
 
 void	interrupt __P((int signo));	/* in case operator bangs on console */
 
diff -u -uNr /usr/src/sbin/dump/dumprmt.c dump/dumprmt.c
--- /usr/src/sbin/dump/dumprmt.c	Sat Sep 11 03:51:55 1999
+++ dump/dumprmt.c	Sat Jan  1 20:36:52 2000
@@ -92,6 +92,7 @@
 static	int errfd = -1;
 extern	int dokerberos;
 extern	int ntrec;		/* blocking factor on tape */
+extern	char *path_rsh;
 
 int
 rmthost(host)
@@ -141,7 +142,7 @@
 rmtgetconn()
 {
 	register char *cp;
-	register const char *rmt;
+	register char *rmt;
 	static struct servent *sp = NULL;
 	static struct passwd *pwd = NULL;
 	char *tuser;
@@ -173,6 +174,10 @@
 	if ((rmt = getenv("RMT")) == NULL)
 		rmt = _PATH_RMT;
 	msg("");
+	if (path_rsh)
+		rmtape = rshrcmd(&rmtpeer, (u_short)sp->s_port, pwd->pw_name,
+				 tuser, rmt, 0);
+	else
 #ifdef KERBEROS
 	if (dokerberos)
 		rmtape = krcmd(&rmtpeer, sp->s_port, tuser, rmt, &errfd,
@@ -186,6 +191,8 @@
 		return;
 	}
 	(void)fprintf(stderr, "Connection to %s established.\n", rmtpeer);
+	if (path_rsh)
+		return;
 	size = ntrec * TP_BSIZE;
 	if (size > 60 * 1024)		/* XXX */
 		size = 60 * 1024;
diff -u -uNr /usr/src/sbin/dump/main.c dump/main.c
--- /usr/src/sbin/dump/main.c	Sat Sep 11 03:51:55 1999
+++ dump/main.c	Sat Jan  1 22:11:40 2000
@@ -86,6 +86,7 @@
 long	dev_bsize = 1;	/* recalculated below */
 long	blocksperfile;	/* output blocks per file */
 char	*host = NULL;	/* remote host (if any) */
+char	*path_rsh = NULL;	/* rsh (or equiv command) path */
 
 static long numarg __P((char *, long, long));
 static void obsolete __P((int *, char **[]));
@@ -122,9 +123,9 @@
 
 	obsolete(&argc, &argv);
 #ifdef KERBEROS
-#define optstring "0123456789aB:b:cd:f:h:kns:T:uWw"
+#define optstring "0123456789aB:b:cd:f:h:knP:s:T:uWw"
 #else
-#define optstring "0123456789aB:b:cd:f:h:ns:T:uWw"
+#define optstring "0123456789aB:b:cd:f:h:nP:s:T:uWw"
 #endif
 	while ((ch = getopt(argc, argv, optstring)) != -1)
 #undef optstring
@@ -177,6 +178,10 @@
 			notify = 1;
 			break;
 
+		case 'P':
+			path_rsh = optarg;
+			break;
+
 		case 's':		/* tape size, feet */
 			tsize = numarg("tape size", 1L, 0L) * 12 * 10;
 			break;
@@ -491,7 +496,8 @@
 		"k"
 #endif
 		"nu] [-B records] [-b blocksize] [-d density] [-f file]\n"
-		"            [-h level] [-s feet] [-T date] filesystem\n"
+		"            [-h level] [-P rshcmd] [-s feet] [-T date] "
+		"filesystem\n"
 		"       dump [-W | -w]\n");
 	exit(X_STARTUP);
 }
@@ -598,6 +604,7 @@
 		case 'd':
 		case 'f':
 		case 'h':
+		case 'P':
 		case 's':
 		case 'T':
 			if (*argv == NULL) {
diff -u -uNr /usr/src/sbin/dump/rshrcmd.c dump/rshrcmd.c
--- /usr/src/sbin/dump/rshrcmd.c	Thu Jan  1 01:00:00 1970
+++ dump/rshrcmd.c	Sat Jan  1 22:05:35 2000
@@ -0,0 +1,110 @@
+
+/*
+ * This is an rcmd() replacement originally by 
+ * Chris Siebenmann <cks@utcc.utoronto.ca>.
+ */
+
+#ifndef lint
+static const char rcsid[] =
+  "$FreeBSD$";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <errno.h>
+#include <netdb.h>
+#include <signal.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "dump.h"
+
+extern	char *path_rsh;
+
+static char *
+xbasename(s)
+	char *s;
+{
+	char *ret;
+
+	ret = strrchr(s, '/');
+	if (ret && ret[1])
+		return (ret + 1);
+	return s;
+}
+
+
+/*
+ * This is a replacement rcmd() function that uses the rsh(1c)
+ * program in place of a direct rcmd() function call so as to
+ * avoid having to be root.
+ */
+int
+rshrcmd(ahost, port, luser, ruser, cmd, fd2p)
+	char  	**ahost;
+	u_short	port;
+	char	*luser, *ruser, *cmd;
+	int	*fd2p;
+{
+	int             cpid;
+	struct hostent  *hp;
+	int             sp[2];
+
+	/* insure that we are indeed being used as we thought. */
+	if (fd2p != 0)
+		return -1;
+	/* validate remote hostname. */
+	hp = gethostbyname(*ahost);
+	if (hp == 0) {
+		msg("%s: unknown host", *ahost);
+		return -1;
+	}
+	*ahost = hp->h_name;	/* This makes me nervous. */
+
+	/* get a socketpair we'll use for stdin and stdout. */
+	if (socketpair(AF_UNIX, SOCK_STREAM, 0, sp) < 0) {
+		msg("socketpair(AF_UNIX, SOCK_STREAM, 0) failed: %s.", 
+		    strerror(errno));
+		return -1;
+	}
+
+	cpid = fork();
+	if (cpid < 0) {
+		msg("fork failed: %s.", strerror(errno));
+		return -1;      /* error. */
+	}
+	if (cpid == 0) {
+		/* child. we use sp[1] to be stdin/stdout, and close
+		   sp[0]. */
+		(void) close(sp[0]);
+		if (dup2(sp[1], 0) < 0 || dup2(0,1) < 0) {
+			msg("dup2 failed: %s.", strerror(errno));
+			_exit(255);
+		}
+		/* fork again to lose parent. */
+		cpid = fork();
+		if (cpid < 0) {
+			msg("fork to lose parent failed: %s.", strerror(errno));
+			_exit(255);
+		}
+		if (cpid > 0)
+			_exit(0);
+		/* in grandchild here. */
+		setpgid(0, getpid());	/* run in background */
+		execlp(path_rsh, xbasename(path_rsh), 
+		       *ahost, "-l", ruser, cmd, (char *) NULL);
+		msg("execlp %s failed: %s.", path_rsh, strerror(errno));
+		_exit(255);
+	}
+	if (cpid > 0) {
+		/* parent. close sp[1], return sp[0]. */
+		(void) close(sp[1]);
+		/* reap child. */
+		(void) wait(0);
+		return sp[0];
+	}
+	/*NOTREACHED*/
+	return (-1);
+}
diff -u -uNr /usr/src/sbin/restore/Makefile restore/Makefile
--- /usr/src/sbin/restore/Makefile	Tue Oct 26 21:48:16 1999
+++ restore/Makefile	Sat Jan  1 22:06:28 2000
@@ -6,7 +6,7 @@
 CFLAGS+=-DRRESTORE
 CFLAGS+=-I${.CURDIR}/../../libexec/rlogind
 SRCS=	main.c interactive.c restore.c dirs.c symtab.c tape.c utilities.c \
-	dumprmt.c
+	dumprmt.c rshrcmd.c
 BINGRP=	tty
 BINMODE=2555
 MAN8=	restore.8
diff -u -uNr /usr/src/sbin/restore/main.c restore/main.c
--- /usr/src/sbin/restore/main.c	Sat Sep 11 03:52:25 1999
+++ restore/main.c	Sat Jan  1 22:12:13 2000
@@ -74,6 +74,7 @@
 time_t	dumptime;
 time_t	dumpdate;
 FILE 	*terminal;
+char	*path_rsh = NULL;
 
 static void obsolete __P((int *, char **[]));
 static void usage __P((void));
@@ -99,9 +100,9 @@
 		inputdev = _PATH_DEFTAPE;
 	obsolete(&argc, &argv);
 #ifdef KERBEROS
-#define	optlist "b:cdf:hikmNRrs:tuvxy"
+#define	optlist "b:cdf:hikmNP:Rrs:tuvxy"
 #else
-#define	optlist "b:cdf:himNRrs:tuvxy"
+#define	optlist "b:cdf:himNP:Rrs:tuvxy"
 #endif
 	while ((ch = getopt(argc, argv, optlist)) != -1)
 		switch(ch) {
@@ -148,6 +149,9 @@
 		case 'N':
 			Nflag = 1;
 			break;
+		case 'P':
+			path_rsh = optarg;
+			break;
 		case 's':
 			/* Dumpnum (skip to) for multifile dump tapes. */
 			dumpnum = strtol(optarg, &p, 10);
@@ -292,12 +296,14 @@
 static void
 usage()
 {
-	(void)fprintf(stderr, "usage:\t%s\n\t%s\n\t%s\n\t%s\n\t%s\n",
-	  "restore -i [-chkmuvy] [-b blocksize] [-f file] [-s fileno]",
-	  "restore -r [-ckuvy] [-b blocksize] [-f file] [-s fileno]",
-	  "restore -R [-ckuvy] [-b blocksize] [-f file] [-s fileno]",
-	  "restore -x [-chkmuvy] [-b blocksize] [-f file] [-s fileno] [file ...]",
-	  "restore -t [-chkuvy] [-b blocksize] [-f file] [-s fileno] [file ...]");
+	(void)fprintf(stderr, "usage:\t%s\n\t%s\n\t%s\n\t%s\n\t%s\n\t%s\n\t%s\n",
+	  "restore -i [-chkmuvy] [-b blocksize] [-f file] [-P rshcmd] [-s fileno]",
+	  "restore -r [-ckuvy] [-b blocksize] [-f file] [-P rshcmd] [-s fileno]",
+	  "restore -R [-ckuvy] [-b blocksize] [-f file] [-P rshcmd] [-s fileno]",
+	  "restore -x [-chkmuvy] [-b blocksize] [-f file] [-P rshcmd] [-s fileno]",
+          "        [file ...]",
+	  "restore -t [-chkuvy] [-b blocksize] [-f file] [-P rshcmd] [-s fileno]",
+          "        [file ...]");
 	done(1);
 }
 
@@ -335,6 +341,7 @@
 		switch (*ap) {
 		case 'b':
 		case 'f':
+		case 'P':
 		case 's':
 			if (*argv == NULL) {
 				warnx("option requires an argument -- %c", *ap);
diff -u -uNr /usr/src/sbin/restore/restore.8 restore/restore.8
--- /usr/src/sbin/restore/restore.8	Sat Sep 11 03:52:25 1999
+++ restore/restore.8	Sat Jan  1 22:19:10 2000
@@ -44,24 +44,28 @@
 .Op Fl chkmuvy
 .Op Fl b Ar blocksize
 .Op Fl f Ar file
+.Op Fl P Ar rshcmd
 .Op Fl s Ar fileno
 .Nm restore
 .Fl R
 .Op Fl ckuvy
 .Op Fl b Ar blocksize
 .Op Fl f Ar file
+.Op Fl P Ar rshcmd
 .Op Fl s Ar fileno
 .Nm restore
 .Fl r
 .Op Fl ckuvy
 .Op Fl b Ar blocksize
 .Op Fl f Ar file
+.Op Fl P Ar rshcmd
 .Op Fl s Ar fileno
 .Nm restore
 .Fl t
 .Op Fl chkuvy
 .Op Fl b Ar blocksize
 .Op Fl f Ar file
+.Op Fl P Ar rshcmd
 .Op Fl s Ar fileno
 .Op file ...
 .Nm restore
@@ -69,6 +73,7 @@
 .Op Fl chkmuvy
 .Op Fl b Ar blocksize
 .Op Fl f Ar file
+.Op Fl P Ar rshcmd
 .Op Fl s Ar fileno
 .Op file ...
 .Pp
@@ -311,6 +316,13 @@
 This is useful if only a few files are being extracted,
 and one wants to avoid regenerating the complete pathname
 to the file.
+.It Fl P Ar rshcmd
+Program to provide
+.Xr rsh 1 -like Ns
+transport to the remote tape server.
+It must provide a binary-transparent path to the remote host
+and must have a command argument syntax that is compatible with
+.Xr rsh 1 .
 .It Fl s Ar fileno
 Read from the specified
 .Ar fileno

>Release-Note:
>Audit-Trail:
>Unformatted:


To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-bugs" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200001020159.CAA88226>