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