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