dumprmt.c revision 59216
1230592Sken/*-
2237683Sken * Copyright (c) 1980, 1993
3230592Sken *	The Regents of the University of California.  All rights reserved.
4230592Sken *
5230592Sken * Redistribution and use in source and binary forms, with or without
6230592Sken * modification, are permitted provided that the following conditions
7230592Sken * are met:
8230592Sken * 1. Redistributions of source code must retain the above copyright
9230592Sken *    notice, this list of conditions and the following disclaimer.
10230592Sken * 2. Redistributions in binary form must reproduce the above copyright
11230592Sken *    notice, this list of conditions and the following disclaimer in the
12230592Sken *    documentation and/or other materials provided with the distribution.
13230592Sken * 3. All advertising materials mentioning features or use of this software
14230592Sken *    must display the following acknowledgement:
15230592Sken *	This product includes software developed by the University of
16230592Sken *	California, Berkeley and its contributors.
17230592Sken * 4. Neither the name of the University nor the names of its contributors
18230592Sken *    may be used to endorse or promote products derived from this software
19230592Sken *    without specific prior written permission.
20230592Sken *
21230592Sken * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22230592Sken * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23230592Sken * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24230592Sken * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25230592Sken * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26230592Sken * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27230592Sken * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28230592Sken * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29230592Sken * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30230592Sken * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31230592Sken * SUCH DAMAGE.
32230592Sken */
33230592Sken
34230592Sken#ifndef lint
35230592Sken#if 0
36230592Skenstatic char sccsid[] = "@(#)dumprmt.c	8.3 (Berkeley) 4/28/95";
37230592Sken#endif
38230592Skenstatic const char rcsid[] =
39230592Sken  "$FreeBSD: head/sbin/dump/dumprmt.c 59216 2000-04-14 06:15:01Z imp $";
40230592Sken#endif /* not lint */
41230592Sken
42230592Sken#include <sys/param.h>
43230592Sken#include <sys/mtio.h>
44230592Sken#include <sys/socket.h>
45230592Sken#include <sys/time.h>
46230592Sken#ifdef sunos
47230592Sken#include <sys/vnode.h>
48230592Sken
49230592Sken#include <ufs/inode.h>
50230592Sken#else
51230592Sken#include <ufs/ufs/dinode.h>
52231240Sken#endif
53231240Sken
54230592Sken#include <netinet/in.h>
55230592Sken#include <netinet/in_systm.h>
56231240Sken#include <netinet/ip.h>
57230592Sken#include <netinet/tcp.h>
58230592Sken
59230592Sken#include <protocols/dumprestore.h>
60230592Sken
61230592Sken#include <ctype.h>
62230592Sken#include <netdb.h>
63230592Sken#include <pwd.h>
64230592Sken#include <stdio.h>
65230592Sken#ifdef __STDC__
66230592Sken#include <errno.h>
67230592Sken#include <stdlib.h>
68230592Sken#include <string.h>
69230592Sken#include <unistd.h>
70230592Sken#endif
71230592Sken
72230592Sken#include "pathnames.h"
73230592Sken#include "dump.h"
74230592Sken
75230592Sken#define	TS_CLOSED	0
76230592Sken#define	TS_OPEN		1
77230592Sken
78230592Skenstatic	int rmtstate = TS_CLOSED;
79230592Skenstatic	int rmtape;
80230592Skenstatic	char *rmtpeer;
81230592Sken
82230592Skenstatic	int okname __P((char *));
83230592Skenstatic	int rmtcall __P((char *, char *));
84230592Skenstatic	void rmtconnaborted __P((/* int, int */));
85230592Skenstatic	int rmtgetb __P((void));
86230592Skenstatic	void rmtgetconn __P((void));
87230592Skenstatic	void rmtgets __P((char *, int));
88230592Skenstatic	int rmtreply __P((char *));
89230592Sken#ifdef KERBEROS
90230592Skenint	krcmd __P((char **, int /*u_short*/, char *, char *, int *, char *));
91230592Sken#endif
92230592Sken
93230592Skenstatic	int errfd = -1;
94230592Skenextern	int dokerberos;
95230592Skenextern	int ntrec;		/* blocking factor on tape */
96230592Sken
97230592Skenint
98230592Skenrmthost(host)
99230592Sken	char *host;
100230592Sken{
101230592Sken
102230592Sken	rmtpeer = malloc(strlen(host) + 1);
103230592Sken	if (rmtpeer)
104230592Sken		strcpy(rmtpeer, host);
105230592Sken	else
106230592Sken		rmtpeer = host;
107230592Sken	signal(SIGPIPE, rmtconnaborted);
108230592Sken	rmtgetconn();
109230592Sken	if (rmtape < 0)
110230592Sken		return (0);
111230592Sken	return (1);
112230592Sken}
113230592Sken
114230592Skenstatic void
115230592Skenrmtconnaborted()
116230592Sken{
117230592Sken	msg("Lost connection to remote host.\n");
118230592Sken	if (errfd != -1) {
119230592Sken		fd_set r;
120230592Sken		struct timeval t;
121230592Sken
122230592Sken		FD_ZERO(&r);
123230592Sken		FD_SET(errfd, &r);
124230592Sken		t.tv_sec = 0;
125230592Sken		t.tv_usec = 0;
126230592Sken		if (select(errfd + 1, &r, NULL, NULL, &t)) {
127230592Sken			int i;
128230592Sken			char buf[2048];
129230592Sken
130230592Sken			if ((i = read(errfd, buf, sizeof(buf) - 1)) > 0) {
131230592Sken				buf[i] = '\0';
132230592Sken				msg("on %s: %s%s", rmtpeer, buf,
133230592Sken					buf[i - 1] == '\n' ? "" : "\n");
134230592Sken			}
135230592Sken		}
136230592Sken	}
137230592Sken
138230592Sken	exit(X_ABORT);
139230592Sken}
140230592Sken
141230592Skenvoid
142230592Skenrmtgetconn()
143230592Sken{
144230592Sken	register char *cp;
145230592Sken	register const char *rmt;
146230592Sken	static struct servent *sp = NULL;
147230592Sken	static struct passwd *pwd = NULL;
148230592Sken	char *tuser;
149230592Sken	int size;
150230592Sken	int throughput;
151230592Sken	int on;
152230592Sken
153230592Sken	if (sp == NULL) {
154230592Sken		sp = getservbyname(dokerberos ? "kshell" : "shell", "tcp");
155230592Sken		if (sp == NULL) {
156230592Sken			msg("%s/tcp: unknown service\n",
157230592Sken			    dokerberos ? "kshell" : "shell");
158230592Sken			exit(X_STARTUP);
159230592Sken		}
160230592Sken		pwd = getpwuid(getuid());
161254116Sscottl		if (pwd == NULL) {
162			msg("who are you?\n");
163			exit(X_STARTUP);
164		}
165	}
166	if ((cp = strchr(rmtpeer, '@')) != NULL) {
167		tuser = rmtpeer;
168		*cp = '\0';
169		if (!okname(tuser))
170			exit(X_STARTUP);
171		rmtpeer = ++cp;
172	} else
173		tuser = pwd->pw_name;
174	if ((rmt = getenv("RMT")) == NULL)
175		rmt = _PATH_RMT;
176	msg("");
177#ifdef KERBEROS
178	if (dokerberos)
179		rmtape = krcmd(&rmtpeer, sp->s_port, tuser, rmt, &errfd,
180			       (char *)0);
181	else
182#endif
183		rmtape = rcmd(&rmtpeer, (u_short)sp->s_port, pwd->pw_name,
184			      tuser, rmt, &errfd);
185	if (rmtape < 0) {
186		msg("login to %s as %s failed.\n", rmtpeer, tuser);
187		return;
188	}
189	(void)fprintf(stderr, "Connection to %s established.\n", rmtpeer);
190	size = ntrec * TP_BSIZE;
191	if (size > 60 * 1024)		/* XXX */
192		size = 60 * 1024;
193	/* Leave some space for rmt request/response protocol */
194	size += 2 * 1024;
195	while (size > TP_BSIZE &&
196	    setsockopt(rmtape, SOL_SOCKET, SO_SNDBUF, &size, sizeof (size)) < 0)
197		    size -= TP_BSIZE;
198	(void)setsockopt(rmtape, SOL_SOCKET, SO_RCVBUF, &size, sizeof (size));
199	throughput = IPTOS_THROUGHPUT;
200	if (setsockopt(rmtape, IPPROTO_IP, IP_TOS,
201	    &throughput, sizeof(throughput)) < 0)
202		perror("IP_TOS:IPTOS_THROUGHPUT setsockopt");
203	on = 1;
204	if (setsockopt(rmtape, IPPROTO_TCP, TCP_NODELAY, &on, sizeof (on)) < 0)
205		perror("TCP_NODELAY setsockopt");
206}
207
208static int
209okname(cp0)
210	char *cp0;
211{
212	register char *cp;
213	register int c;
214
215	for (cp = cp0; *cp; cp++) {
216		c = *cp;
217		if (!isascii(c) || !(isalnum(c) || c == '_' || c == '-')) {
218			msg("invalid user name %s\n", cp0);
219			return (0);
220		}
221	}
222	return (1);
223}
224
225int
226rmtopen(tape, mode)
227	char *tape;
228	int mode;
229{
230	char buf[256];
231
232	(void)snprintf(buf, sizeof (buf), "O%.226s\n%d\n", tape, mode);
233	rmtstate = TS_OPEN;
234	return (rmtcall(tape, buf));
235}
236
237void
238rmtclose()
239{
240
241	if (rmtstate != TS_OPEN)
242		return;
243	rmtcall("close", "C\n");
244	rmtstate = TS_CLOSED;
245}
246
247int
248rmtread(buf, count)
249	char *buf;
250	int count;
251{
252	char line[30];
253	int n, i, cc;
254
255	(void)snprintf(line, sizeof (line), "R%d\n", count);
256	n = rmtcall("read", line);
257	if (n < 0)
258		/* rmtcall() properly sets errno for us on errors. */
259		return (n);
260	for (i = 0; i < n; i += cc) {
261		cc = read(rmtape, buf+i, n - i);
262		if (cc <= 0)
263			rmtconnaborted();
264	}
265	return (n);
266}
267
268int
269rmtwrite(buf, count)
270	char *buf;
271	int count;
272{
273	char line[30];
274
275	(void)snprintf(line, sizeof (line), "W%d\n", count);
276	write(rmtape, line, strlen(line));
277	write(rmtape, buf, count);
278	return (rmtreply("write"));
279}
280
281void
282rmtwrite0(count)
283	int count;
284{
285	char line[30];
286
287	(void)snprintf(line, sizeof (line), "W%d\n", count);
288	write(rmtape, line, strlen(line));
289}
290
291void
292rmtwrite1(buf, count)
293	char *buf;
294	int count;
295{
296
297	write(rmtape, buf, count);
298}
299
300int
301rmtwrite2()
302{
303
304	return (rmtreply("write"));
305}
306
307int
308rmtseek(offset, pos)
309	int offset, pos;
310{
311	char line[80];
312
313	(void)snprintf(line, sizeof (line), "L%d\n%d\n", offset, pos);
314	return (rmtcall("seek", line));
315}
316
317struct	mtget mts;
318
319struct mtget *
320rmtstatus()
321{
322	register int i;
323	register char *cp;
324
325	if (rmtstate != TS_OPEN)
326		return (NULL);
327	rmtcall("status", "S\n");
328	for (i = 0, cp = (char *)&mts; i < sizeof(mts); i++)
329		*cp++ = rmtgetb();
330	return (&mts);
331}
332
333int
334rmtioctl(cmd, count)
335	int cmd, count;
336{
337	char buf[256];
338
339	if (count < 0)
340		return (-1);
341	(void)snprintf(buf, sizeof (buf), "I%d\n%d\n", cmd, count);
342	return (rmtcall("ioctl", buf));
343}
344
345static int
346rmtcall(cmd, buf)
347	char *cmd, *buf;
348{
349
350	if (write(rmtape, buf, strlen(buf)) != strlen(buf))
351		rmtconnaborted();
352	return (rmtreply(cmd));
353}
354
355static int
356rmtreply(cmd)
357	char *cmd;
358{
359	register char *cp;
360	char code[30], emsg[BUFSIZ];
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