dumprmt.c revision 50476
1224106Snwhitehorn/*-
2224106Snwhitehorn * Copyright (c) 1980, 1993
3224106Snwhitehorn *	The Regents of the University of California.  All rights reserved.
4224106Snwhitehorn *
5224106Snwhitehorn * Redistribution and use in source and binary forms, with or without
6224106Snwhitehorn * modification, are permitted provided that the following conditions
7224106Snwhitehorn * are met:
8224106Snwhitehorn * 1. Redistributions of source code must retain the above copyright
9224106Snwhitehorn *    notice, this list of conditions and the following disclaimer.
10224106Snwhitehorn * 2. Redistributions in binary form must reproduce the above copyright
11224106Snwhitehorn *    notice, this list of conditions and the following disclaimer in the
12224106Snwhitehorn *    documentation and/or other materials provided with the distribution.
13224106Snwhitehorn * 3. All advertising materials mentioning features or use of this software
14224106Snwhitehorn *    must display the following acknowledgement:
15224106Snwhitehorn *	This product includes software developed by the University of
16224106Snwhitehorn *	California, Berkeley and its contributors.
17224106Snwhitehorn * 4. Neither the name of the University nor the names of its contributors
18224106Snwhitehorn *    may be used to endorse or promote products derived from this software
19224106Snwhitehorn *    without specific prior written permission.
20224106Snwhitehorn *
21224106Snwhitehorn * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22224106Snwhitehorn * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23224106Snwhitehorn * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24224106Snwhitehorn * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25224106Snwhitehorn * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26224106Snwhitehorn * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27224106Snwhitehorn * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28224106Snwhitehorn * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29224106Snwhitehorn * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30224106Snwhitehorn * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31224106Snwhitehorn * SUCH DAMAGE.
32224106Snwhitehorn */
33224106Snwhitehorn
34224106Snwhitehorn#ifndef lint
35224106Snwhitehorn#if 0
36224106Snwhitehornstatic char sccsid[] = "@(#)dumprmt.c	8.3 (Berkeley) 4/28/95";
37224106Snwhitehorn#endif
38224106Snwhitehornstatic const char rcsid[] =
39224106Snwhitehorn  "$FreeBSD: head/sbin/dump/dumprmt.c 50476 1999-08-28 00:22:10Z peter $";
40224106Snwhitehorn#endif /* not lint */
41224106Snwhitehorn
42#include <sys/param.h>
43#include <sys/mtio.h>
44#include <sys/socket.h>
45#include <sys/time.h>
46#ifdef sunos
47#include <sys/vnode.h>
48
49#include <ufs/inode.h>
50#else
51#include <ufs/ufs/dinode.h>
52#endif
53
54#include <netinet/in.h>
55#include <netinet/in_systm.h>
56#include <netinet/ip.h>
57#include <netinet/tcp.h>
58
59#include <protocols/dumprestore.h>
60
61#include <ctype.h>
62#include <netdb.h>
63#include <pwd.h>
64#include <stdio.h>
65#ifdef __STDC__
66#include <stdlib.h>
67#include <string.h>
68#include <unistd.h>
69#endif
70
71#include "pathnames.h"
72#include "dump.h"
73
74#define	TS_CLOSED	0
75#define	TS_OPEN		1
76
77static	int rmtstate = TS_CLOSED;
78static	int rmtape;
79static	char *rmtpeer;
80
81static	int okname __P((char *));
82static	int rmtcall __P((char *, char *));
83static	void rmtconnaborted __P((/* int, int */));
84static	int rmtgetb __P((void));
85static	void rmtgetconn __P((void));
86static	void rmtgets __P((char *, int));
87static	int rmtreply __P((char *));
88#ifdef KERBEROS
89int	krcmd __P((char **, int /*u_short*/, char *, char *, int *, char *));
90#endif
91
92static	int errfd = -1;
93extern	int dokerberos;
94extern	int ntrec;		/* blocking factor on tape */
95
96int
97rmthost(host)
98	char *host;
99{
100
101	rmtpeer = malloc(strlen(host) + 1);
102	if (rmtpeer)
103		strcpy(rmtpeer, host);
104	else
105		rmtpeer = host;
106	signal(SIGPIPE, rmtconnaborted);
107	rmtgetconn();
108	if (rmtape < 0)
109		return (0);
110	return (1);
111}
112
113static void
114rmtconnaborted()
115{
116	msg("Lost connection to remote host.\n");
117	if (errfd != -1) {
118		fd_set r;
119		struct timeval t;
120
121		FD_ZERO(&r);
122		FD_SET(errfd, &r);
123		t.tv_sec = 0;
124		t.tv_usec = 0;
125		if (select(errfd + 1, &r, NULL, NULL, &t)) {
126			int i;
127			char buf[2048];
128
129			if ((i = read(errfd, buf, sizeof(buf) - 1)) > 0) {
130				buf[i] = '\0';
131				msg("on %s: %s%s", rmtpeer, buf,
132					buf[i - 1] == '\n' ? "" : "\n");
133			}
134		}
135	}
136
137	exit(X_ABORT);
138}
139
140void
141rmtgetconn()
142{
143	register char *cp;
144	register const char *rmt;
145	static struct servent *sp = NULL;
146	static struct passwd *pwd = NULL;
147	char *tuser;
148	int size;
149	int throughput;
150	int on;
151
152	if (sp == NULL) {
153		sp = getservbyname(dokerberos ? "kshell" : "shell", "tcp");
154		if (sp == NULL) {
155			msg("%s/tcp: unknown service\n",
156			    dokerberos ? "kshell" : "shell");
157			exit(X_STARTUP);
158		}
159		pwd = getpwuid(getuid());
160		if (pwd == NULL) {
161			msg("who are you?\n");
162			exit(X_STARTUP);
163		}
164	}
165	if ((cp = strchr(rmtpeer, '@')) != NULL) {
166		tuser = rmtpeer;
167		*cp = '\0';
168		if (!okname(tuser))
169			exit(X_STARTUP);
170		rmtpeer = ++cp;
171	} else
172		tuser = pwd->pw_name;
173	if ((rmt = getenv("RMT")) == NULL)
174		rmt = _PATH_RMT;
175	msg("");
176#ifdef KERBEROS
177	if (dokerberos)
178		rmtape = krcmd(&rmtpeer, sp->s_port, tuser, rmt, &errfd,
179			       (char *)0);
180	else
181#endif
182		rmtape = rcmd(&rmtpeer, (u_short)sp->s_port, pwd->pw_name,
183			      tuser, rmt, &errfd);
184	if (rmtape < 0) {
185		msg("login to %s as %s failed.\n", rmtpeer, tuser);
186		return;
187	}
188	(void)fprintf(stderr, "Connection to %s established.\n", rmtpeer);
189	size = ntrec * TP_BSIZE;
190	if (size > 60 * 1024)		/* XXX */
191		size = 60 * 1024;
192	/* Leave some space for rmt request/response protocol */
193	size += 2 * 1024;
194	while (size > TP_BSIZE &&
195	    setsockopt(rmtape, SOL_SOCKET, SO_SNDBUF, &size, sizeof (size)) < 0)
196		    size -= TP_BSIZE;
197	(void)setsockopt(rmtape, SOL_SOCKET, SO_RCVBUF, &size, sizeof (size));
198	throughput = IPTOS_THROUGHPUT;
199	if (setsockopt(rmtape, IPPROTO_IP, IP_TOS,
200	    &throughput, sizeof(throughput)) < 0)
201		perror("IP_TOS:IPTOS_THROUGHPUT setsockopt");
202	on = 1;
203	if (setsockopt(rmtape, IPPROTO_TCP, TCP_NODELAY, &on, sizeof (on)) < 0)
204		perror("TCP_NODELAY setsockopt");
205}
206
207static int
208okname(cp0)
209	char *cp0;
210{
211	register char *cp;
212	register int c;
213
214	for (cp = cp0; *cp; cp++) {
215		c = *cp;
216		if (!isascii(c) || !(isalnum(c) || c == '_' || c == '-')) {
217			msg("invalid user name %s\n", cp0);
218			return (0);
219		}
220	}
221	return (1);
222}
223
224int
225rmtopen(tape, mode)
226	char *tape;
227	int mode;
228{
229	char buf[256];
230
231	(void)snprintf(buf, sizeof (buf), "O%.226s\n%d\n", tape, mode);
232	rmtstate = TS_OPEN;
233	return (rmtcall(tape, buf));
234}
235
236void
237rmtclose()
238{
239
240	if (rmtstate != TS_OPEN)
241		return;
242	rmtcall("close", "C\n");
243	rmtstate = TS_CLOSED;
244}
245
246int
247rmtread(buf, count)
248	char *buf;
249	int count;
250{
251	char line[30];
252	int n, i, cc;
253
254	(void)snprintf(line, sizeof (line), "R%d\n", count);
255	n = rmtcall("read", line);
256	if (n < 0)
257		/* rmtcall() properly sets errno for us on errors. */
258		return (n);
259	for (i = 0; i < n; i += cc) {
260		cc = read(rmtape, buf+i, n - i);
261		if (cc <= 0)
262			rmtconnaborted();
263	}
264	return (n);
265}
266
267int
268rmtwrite(buf, count)
269	char *buf;
270	int count;
271{
272	char line[30];
273
274	(void)snprintf(line, sizeof (line), "W%d\n", count);
275	write(rmtape, line, strlen(line));
276	write(rmtape, buf, count);
277	return (rmtreply("write"));
278}
279
280void
281rmtwrite0(count)
282	int count;
283{
284	char line[30];
285
286	(void)snprintf(line, sizeof (line), "W%d\n", count);
287	write(rmtape, line, strlen(line));
288}
289
290void
291rmtwrite1(buf, count)
292	char *buf;
293	int count;
294{
295
296	write(rmtape, buf, count);
297}
298
299int
300rmtwrite2()
301{
302
303	return (rmtreply("write"));
304}
305
306int
307rmtseek(offset, pos)
308	int offset, pos;
309{
310	char line[80];
311
312	(void)snprintf(line, sizeof (line), "L%d\n%d\n", offset, pos);
313	return (rmtcall("seek", line));
314}
315
316struct	mtget mts;
317
318struct mtget *
319rmtstatus()
320{
321	register int i;
322	register char *cp;
323
324	if (rmtstate != TS_OPEN)
325		return (NULL);
326	rmtcall("status", "S\n");
327	for (i = 0, cp = (char *)&mts; i < sizeof(mts); i++)
328		*cp++ = rmtgetb();
329	return (&mts);
330}
331
332int
333rmtioctl(cmd, count)
334	int cmd, count;
335{
336	char buf[256];
337
338	if (count < 0)
339		return (-1);
340	(void)snprintf(buf, sizeof (buf), "I%d\n%d\n", cmd, count);
341	return (rmtcall("ioctl", buf));
342}
343
344static int
345rmtcall(cmd, buf)
346	char *cmd, *buf;
347{
348
349	if (write(rmtape, buf, strlen(buf)) != strlen(buf))
350		rmtconnaborted();
351	return (rmtreply(cmd));
352}
353
354static int
355rmtreply(cmd)
356	char *cmd;
357{
358	register char *cp;
359	char code[30], emsg[BUFSIZ];
360	extern int errno;
361
362	rmtgets(code, sizeof (code));
363	if (*code == 'E' || *code == 'F') {
364		rmtgets(emsg, sizeof (emsg));
365		msg("%s: %s", cmd, emsg);
366		errno = atoi(code + 1);
367		if (*code == 'F')
368			rmtstate = TS_CLOSED;
369		return (-1);
370	}
371	if (*code != 'A') {
372		/* Kill trailing newline */
373		cp = code + strlen(code);
374		if (cp > code && *--cp == '\n')
375			*cp = '\0';
376
377		msg("Protocol to remote tape server botched (code \"%s\").\n",
378		    code);
379		rmtconnaborted();
380	}
381	return (atoi(code + 1));
382}
383
384int
385rmtgetb()
386{
387	char c;
388
389	if (read(rmtape, &c, 1) != 1)
390		rmtconnaborted();
391	return (c);
392}
393
394/* Get a line (guaranteed to have a trailing newline). */
395void
396rmtgets(line, len)
397	char *line;
398	int len;
399{
400	register char *cp = line;
401
402	while (len > 1) {
403		*cp = rmtgetb();
404		if (*cp == '\n') {
405			cp[1] = '\0';
406			return;
407		}
408		cp++;
409		len--;
410	}
411	*cp = '\0';
412	msg("Protocol to remote tape server botched.\n");
413	msg("(rmtgets got \"%s\").\n", line);
414	rmtconnaborted();
415}
416