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