11558Srgrimes/*-
21558Srgrimes * Copyright (c) 1980, 1993
31558Srgrimes *	The Regents of the University of California.  All rights reserved.
41558Srgrimes *
51558Srgrimes * Redistribution and use in source and binary forms, with or without
61558Srgrimes * modification, are permitted provided that the following conditions
71558Srgrimes * are met:
81558Srgrimes * 1. Redistributions of source code must retain the above copyright
91558Srgrimes *    notice, this list of conditions and the following disclaimer.
101558Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
111558Srgrimes *    notice, this list of conditions and the following disclaimer in the
121558Srgrimes *    documentation and/or other materials provided with the distribution.
13128085Sbde * 4. Neither the name of the University nor the names of its contributors
141558Srgrimes *    may be used to endorse or promote products derived from this software
151558Srgrimes *    without specific prior written permission.
161558Srgrimes *
171558Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
181558Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
191558Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
201558Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
211558Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
221558Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
231558Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
241558Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
251558Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
261558Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
271558Srgrimes * SUCH DAMAGE.
281558Srgrimes */
291558Srgrimes
301558Srgrimes#ifndef lint
3136997Scharnier#if 0
3223672Speterstatic char sccsid[] = "@(#)dumprmt.c	8.3 (Berkeley) 4/28/95";
3336997Scharnier#endif
3436997Scharnierstatic const char rcsid[] =
3550476Speter  "$FreeBSD$";
361558Srgrimes#endif /* not lint */
371558Srgrimes
381558Srgrimes#include <sys/param.h>
391558Srgrimes#include <sys/mtio.h>
401558Srgrimes#include <sys/socket.h>
411558Srgrimes#include <sys/time.h>
421558Srgrimes
431558Srgrimes#include <ufs/ufs/dinode.h>
441558Srgrimes
451558Srgrimes#include <netinet/in.h>
4619239Sfenner#include <netinet/in_systm.h>
4719239Sfenner#include <netinet/ip.h>
4836115Sfenner#include <netinet/tcp.h>
491558Srgrimes
501558Srgrimes#include <protocols/dumprestore.h>
511558Srgrimes
521558Srgrimes#include <ctype.h>
531558Srgrimes#include <netdb.h>
541558Srgrimes#include <pwd.h>
551558Srgrimes#include <stdio.h>
56103949Smike#include <limits.h>
5759216Simp#include <errno.h>
581558Srgrimes#include <stdlib.h>
591558Srgrimes#include <string.h>
601558Srgrimes#include <unistd.h>
611558Srgrimes
621558Srgrimes#include "pathnames.h"
631558Srgrimes#include "dump.h"
641558Srgrimes
651558Srgrimes#define	TS_CLOSED	0
661558Srgrimes#define	TS_OPEN		1
671558Srgrimes
681558Srgrimesstatic	int rmtstate = TS_CLOSED;
691558Srgrimesstatic	int rmtape;
701558Srgrimesstatic	char *rmtpeer;
711558Srgrimes
7292837Simpstatic	int okname(const char *);
7392837Simpstatic	int rmtcall(const char *, const char *);
7492837Simpstatic	void rmtconnaborted(int);
7592837Simpstatic	int rmtgetb(void);
7692837Simpstatic	void rmtgetconn(void);
7792837Simpstatic	void rmtgets(char *, int);
7892837Simpstatic	int rmtreply(const char *);
791558Srgrimes
8019300Sfennerstatic	int errfd = -1;
811558Srgrimesextern	int ntrec;		/* blocking factor on tape */
821558Srgrimes
831558Srgrimesint
8492837Simprmthost(const char *host)
851558Srgrimes{
861558Srgrimes
8792837Simp	rmtpeer = strdup(host);
8892837Simp	if (rmtpeer == NULL)
8992837Simp		return (0);
901558Srgrimes	signal(SIGPIPE, rmtconnaborted);
911558Srgrimes	rmtgetconn();
921558Srgrimes	if (rmtape < 0)
931558Srgrimes		return (0);
941558Srgrimes	return (1);
951558Srgrimes}
961558Srgrimes
971558Srgrimesstatic void
9892837Simprmtconnaborted(int sig __unused)
991558Srgrimes{
10019300Sfenner	msg("Lost connection to remote host.\n");
10119300Sfenner	if (errfd != -1) {
10219300Sfenner		fd_set r;
10319300Sfenner		struct timeval t;
1041558Srgrimes
10519300Sfenner		FD_ZERO(&r);
10619300Sfenner		FD_SET(errfd, &r);
10719300Sfenner		t.tv_sec = 0;
10819300Sfenner		t.tv_usec = 0;
10919300Sfenner		if (select(errfd + 1, &r, NULL, NULL, &t)) {
11019300Sfenner			int i;
11119300Sfenner			char buf[2048];
11219300Sfenner
11319300Sfenner			if ((i = read(errfd, buf, sizeof(buf) - 1)) > 0) {
11419300Sfenner				buf[i] = '\0';
11519300Sfenner				msg("on %s: %s%s", rmtpeer, buf,
11619300Sfenner					buf[i - 1] == '\n' ? "" : "\n");
11719300Sfenner			}
11819300Sfenner		}
11919300Sfenner	}
12019300Sfenner
12119300Sfenner	exit(X_ABORT);
1221558Srgrimes}
1231558Srgrimes
1241558Srgrimesvoid
12592837Simprmtgetconn(void)
1261558Srgrimes{
12786473Siedowse	char *cp;
12886473Siedowse	const char *rmt;
1291558Srgrimes	static struct servent *sp = NULL;
1301558Srgrimes	static struct passwd *pwd = NULL;
1311558Srgrimes	char *tuser;
1321558Srgrimes	int size;
13319239Sfenner	int throughput;
13436115Sfenner	int on;
1351558Srgrimes
1361558Srgrimes	if (sp == NULL) {
137114452Smarkm		sp = getservbyname("shell", "tcp");
1381558Srgrimes		if (sp == NULL) {
139114452Smarkm			msg("shell/tcp: unknown service\n");
14037635Sjkoshy			exit(X_STARTUP);
1411558Srgrimes		}
1421558Srgrimes		pwd = getpwuid(getuid());
1431558Srgrimes		if (pwd == NULL) {
14419300Sfenner			msg("who are you?\n");
14537635Sjkoshy			exit(X_STARTUP);
1461558Srgrimes		}
1471558Srgrimes	}
14823672Speter	if ((cp = strchr(rmtpeer, '@')) != NULL) {
1491558Srgrimes		tuser = rmtpeer;
1501558Srgrimes		*cp = '\0';
1511558Srgrimes		if (!okname(tuser))
15237635Sjkoshy			exit(X_STARTUP);
1531558Srgrimes		rmtpeer = ++cp;
1541558Srgrimes	} else
1551558Srgrimes		tuser = pwd->pw_name;
15612377Sjoerg	if ((rmt = getenv("RMT")) == NULL)
15712377Sjoerg		rmt = _PATH_RMT;
158122669Sjohan	msg("%s", "");
159114452Smarkm	rmtape = rcmd(&rmtpeer, (u_short)sp->s_port, pwd->pw_name,
160114452Smarkm		      tuser, rmt, &errfd);
16119300Sfenner	if (rmtape < 0) {
16219300Sfenner		msg("login to %s as %s failed.\n", rmtpeer, tuser);
16319239Sfenner		return;
16419300Sfenner	}
16519317Sfenner	(void)fprintf(stderr, "Connection to %s established.\n", rmtpeer);
1661558Srgrimes	size = ntrec * TP_BSIZE;
1671558Srgrimes	if (size > 60 * 1024)		/* XXX */
1681558Srgrimes		size = 60 * 1024;
1691558Srgrimes	/* Leave some space for rmt request/response protocol */
1701558Srgrimes	size += 2 * 1024;
1711558Srgrimes	while (size > TP_BSIZE &&
1721558Srgrimes	    setsockopt(rmtape, SOL_SOCKET, SO_SNDBUF, &size, sizeof (size)) < 0)
1731558Srgrimes		    size -= TP_BSIZE;
1741558Srgrimes	(void)setsockopt(rmtape, SOL_SOCKET, SO_RCVBUF, &size, sizeof (size));
17519239Sfenner	throughput = IPTOS_THROUGHPUT;
17619239Sfenner	if (setsockopt(rmtape, IPPROTO_IP, IP_TOS,
17719239Sfenner	    &throughput, sizeof(throughput)) < 0)
17819239Sfenner		perror("IP_TOS:IPTOS_THROUGHPUT setsockopt");
17936115Sfenner	on = 1;
1801558Srgrimes	if (setsockopt(rmtape, IPPROTO_TCP, TCP_NODELAY, &on, sizeof (on)) < 0)
1811558Srgrimes		perror("TCP_NODELAY setsockopt");
1821558Srgrimes}
1831558Srgrimes
1841558Srgrimesstatic int
18592837Simpokname(const char *cp0)
1861558Srgrimes{
18792837Simp	const char *cp;
18886473Siedowse	int c;
1891558Srgrimes
1901558Srgrimes	for (cp = cp0; *cp; cp++) {
1911558Srgrimes		c = *cp;
1921558Srgrimes		if (!isascii(c) || !(isalnum(c) || c == '_' || c == '-')) {
19319300Sfenner			msg("invalid user name %s\n", cp0);
1941558Srgrimes			return (0);
1951558Srgrimes		}
1961558Srgrimes	}
1971558Srgrimes	return (1);
1981558Srgrimes}
1991558Srgrimes
2001558Srgrimesint
20192837Simprmtopen(const char *tape, int mode)
2021558Srgrimes{
2031558Srgrimes	char buf[256];
2041558Srgrimes
20521409Simp	(void)snprintf(buf, sizeof (buf), "O%.226s\n%d\n", tape, mode);
2061558Srgrimes	rmtstate = TS_OPEN;
2071558Srgrimes	return (rmtcall(tape, buf));
2081558Srgrimes}
2091558Srgrimes
2101558Srgrimesvoid
21192837Simprmtclose(void)
2121558Srgrimes{
2131558Srgrimes
2141558Srgrimes	if (rmtstate != TS_OPEN)
2151558Srgrimes		return;
2161558Srgrimes	rmtcall("close", "C\n");
2171558Srgrimes	rmtstate = TS_CLOSED;
2181558Srgrimes}
2191558Srgrimes
2201558Srgrimesint
22192837Simprmtread(char *buf, int count)
2221558Srgrimes{
2231558Srgrimes	char line[30];
2241558Srgrimes	int n, i, cc;
2251558Srgrimes
22621409Simp	(void)snprintf(line, sizeof (line), "R%d\n", count);
2271558Srgrimes	n = rmtcall("read", line);
22839256Sgibbs	if (n < 0)
22939256Sgibbs		/* rmtcall() properly sets errno for us on errors. */
23039256Sgibbs		return (n);
2311558Srgrimes	for (i = 0; i < n; i += cc) {
2321558Srgrimes		cc = read(rmtape, buf+i, n - i);
23339256Sgibbs		if (cc <= 0)
23492837Simp			rmtconnaborted(0);
2351558Srgrimes	}
2361558Srgrimes	return (n);
2371558Srgrimes}
2381558Srgrimes
2391558Srgrimesint
24092837Simprmtwrite(const char *buf, int count)
2411558Srgrimes{
2421558Srgrimes	char line[30];
2431558Srgrimes
24421409Simp	(void)snprintf(line, sizeof (line), "W%d\n", count);
2451558Srgrimes	write(rmtape, line, strlen(line));
2461558Srgrimes	write(rmtape, buf, count);
2471558Srgrimes	return (rmtreply("write"));
2481558Srgrimes}
2491558Srgrimes
2501558Srgrimesvoid
25192837Simprmtwrite0(int count)
2521558Srgrimes{
2531558Srgrimes	char line[30];
2541558Srgrimes
25521409Simp	(void)snprintf(line, sizeof (line), "W%d\n", count);
2561558Srgrimes	write(rmtape, line, strlen(line));
2571558Srgrimes}
2581558Srgrimes
2591558Srgrimesvoid
26092837Simprmtwrite1(const char *buf, int count)
2611558Srgrimes{
2621558Srgrimes
2631558Srgrimes	write(rmtape, buf, count);
2641558Srgrimes}
2651558Srgrimes
2661558Srgrimesint
26792837Simprmtwrite2(void)
2681558Srgrimes{
2691558Srgrimes
2701558Srgrimes	return (rmtreply("write"));
2711558Srgrimes}
2721558Srgrimes
2731558Srgrimesint
27492837Simprmtseek(int offset, int pos)	/* XXX off_t ? */
2751558Srgrimes{
2761558Srgrimes	char line[80];
2771558Srgrimes
27821409Simp	(void)snprintf(line, sizeof (line), "L%d\n%d\n", offset, pos);
2791558Srgrimes	return (rmtcall("seek", line));
2801558Srgrimes}
2811558Srgrimes
2821558Srgrimesstruct	mtget mts;
2831558Srgrimes
2841558Srgrimesstruct mtget *
28592837Simprmtstatus(void)
2861558Srgrimes{
28786473Siedowse	int i;
28886473Siedowse	char *cp;
2891558Srgrimes
2901558Srgrimes	if (rmtstate != TS_OPEN)
2911558Srgrimes		return (NULL);
2921558Srgrimes	rmtcall("status", "S\n");
2931558Srgrimes	for (i = 0, cp = (char *)&mts; i < sizeof(mts); i++)
2941558Srgrimes		*cp++ = rmtgetb();
2951558Srgrimes	return (&mts);
2961558Srgrimes}
2971558Srgrimes
2981558Srgrimesint
29992837Simprmtioctl(int cmd, int count)
3001558Srgrimes{
3011558Srgrimes	char buf[256];
3021558Srgrimes
3031558Srgrimes	if (count < 0)
3041558Srgrimes		return (-1);
30521409Simp	(void)snprintf(buf, sizeof (buf), "I%d\n%d\n", cmd, count);
3061558Srgrimes	return (rmtcall("ioctl", buf));
3071558Srgrimes}
3081558Srgrimes
3091558Srgrimesstatic int
31092837Simprmtcall(const char *cmd, const char *buf)
3111558Srgrimes{
3121558Srgrimes
3131558Srgrimes	if (write(rmtape, buf, strlen(buf)) != strlen(buf))
31492837Simp		rmtconnaborted(0);
3151558Srgrimes	return (rmtreply(cmd));
3161558Srgrimes}
3171558Srgrimes
3181558Srgrimesstatic int
31992837Simprmtreply(const char *cmd)
3201558Srgrimes{
32186473Siedowse	char *cp;
3221558Srgrimes	char code[30], emsg[BUFSIZ];
3231558Srgrimes
3241558Srgrimes	rmtgets(code, sizeof (code));
3251558Srgrimes	if (*code == 'E' || *code == 'F') {
3261558Srgrimes		rmtgets(emsg, sizeof (emsg));
3271558Srgrimes		msg("%s: %s", cmd, emsg);
32839256Sgibbs		errno = atoi(code + 1);
32939256Sgibbs		if (*code == 'F')
3301558Srgrimes			rmtstate = TS_CLOSED;
3311558Srgrimes		return (-1);
3321558Srgrimes	}
3331558Srgrimes	if (*code != 'A') {
3341558Srgrimes		/* Kill trailing newline */
3351558Srgrimes		cp = code + strlen(code);
3361558Srgrimes		if (cp > code && *--cp == '\n')
3371558Srgrimes			*cp = '\0';
3381558Srgrimes
3391558Srgrimes		msg("Protocol to remote tape server botched (code \"%s\").\n",
3401558Srgrimes		    code);
34192837Simp		rmtconnaborted(0);
3421558Srgrimes	}
3431558Srgrimes	return (atoi(code + 1));
3441558Srgrimes}
3451558Srgrimes
3461558Srgrimesint
34792837Simprmtgetb(void)
3481558Srgrimes{
3491558Srgrimes	char c;
3501558Srgrimes
3511558Srgrimes	if (read(rmtape, &c, 1) != 1)
35292837Simp		rmtconnaborted(0);
3531558Srgrimes	return (c);
3541558Srgrimes}
3551558Srgrimes
3561558Srgrimes/* Get a line (guaranteed to have a trailing newline). */
3571558Srgrimesvoid
35892837Simprmtgets(char *line, int len)
3591558Srgrimes{
36086473Siedowse	char *cp = line;
3611558Srgrimes
3621558Srgrimes	while (len > 1) {
3631558Srgrimes		*cp = rmtgetb();
3641558Srgrimes		if (*cp == '\n') {
3651558Srgrimes			cp[1] = '\0';
3661558Srgrimes			return;
3671558Srgrimes		}
3681558Srgrimes		cp++;
3691558Srgrimes		len--;
3701558Srgrimes	}
3711558Srgrimes	*cp = '\0';
3721558Srgrimes	msg("Protocol to remote tape server botched.\n");
3731558Srgrimes	msg("(rmtgets got \"%s\").\n", line);
37492837Simp	rmtconnaborted(0);
3751558Srgrimes}
376