1 /*-
2 * Copyright (c) 1980, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * %sccs.include.redist.c%
6 */
7
8 #ifndef lint
9 static char sccsid[] = "@(#)dumprmt.c 8.3 (Berkeley) 04/28/95";
10 #endif /* not lint */
11
12 #include <sys/param.h>
13 #include <sys/mtio.h>
14 #include <sys/ioctl.h>
15 #include <sys/socket.h>
16 #include <sys/time.h>
17 #ifdef sunos
18 #include <sys/vnode.h>
19
20 #include <ufs/inode.h>
21 #else
22 #include <ufs/ufs/dinode.h>
23 #endif
24
25 #include <netinet/in.h>
26 #include <netinet/tcp.h>
27
28 #include <protocols/dumprestore.h>
29
30 #include <ctype.h>
31 #include <err.h>
32 #include <netdb.h>
33 #include <pwd.h>
34 #include <signal.h>
35 #include <stdio.h>
36 #ifdef __STDC__
37 #include <stdlib.h>
38 #include <string.h>
39 #include <unistd.h>
40 #endif
41
42 #include "pathnames.h"
43 #include "dump.h"
44
45 #define TS_CLOSED 0
46 #define TS_OPEN 1
47
48 static int rmtstate = TS_CLOSED;
49 static int rmtape;
50 static char *rmtpeer;
51
52 static int okname __P((char *));
53 static int rmtcall __P((char *, char *));
54 static void rmtconnaborted __P((/* int, int */));
55 static int rmtgetb __P((void));
56 static void rmtgetconn __P((void));
57 static void rmtgets __P((char *, int));
58 static int rmtreply __P((char *));
59
60 extern int ntrec; /* blocking factor on tape */
61
62 int
rmthost(host)63 rmthost(host)
64 char *host;
65 {
66
67 rmtpeer = malloc(strlen(host) + 1);
68 if (rmtpeer)
69 strcpy(rmtpeer, host);
70 else
71 rmtpeer = host;
72 signal(SIGPIPE, rmtconnaborted);
73 rmtgetconn();
74 if (rmtape < 0)
75 return (0);
76 return (1);
77 }
78
79 static void
rmtconnaborted()80 rmtconnaborted()
81 {
82
83 errx(1, "Lost connection to remote host.");
84 }
85
86 void
rmtgetconn()87 rmtgetconn()
88 {
89 register char *cp;
90 static struct servent *sp = NULL;
91 static struct passwd *pwd = NULL;
92 #ifdef notdef
93 static int on = 1;
94 #endif
95 char *tuser;
96 int size;
97 int maxseg;
98
99 if (sp == NULL) {
100 sp = getservbyname("shell", "tcp");
101 if (sp == NULL)
102 errx(1, "shell/tcp: unknown service");
103 pwd = getpwuid(getuid());
104 if (pwd == NULL)
105 errx(1, "who are you?");
106 }
107 if ((cp = strchr(rmtpeer, '@')) != NULL) {
108 tuser = rmtpeer;
109 *cp = '\0';
110 if (!okname(tuser))
111 exit(1);
112 rmtpeer = ++cp;
113 } else
114 tuser = pwd->pw_name;
115 rmtape = rcmd(&rmtpeer, (u_short)sp->s_port, pwd->pw_name, tuser,
116 _PATH_RMT, (int *)0);
117 size = ntrec * TP_BSIZE;
118 if (size > 60 * 1024) /* XXX */
119 size = 60 * 1024;
120 /* Leave some space for rmt request/response protocol */
121 size += 2 * 1024;
122 while (size > TP_BSIZE &&
123 setsockopt(rmtape, SOL_SOCKET, SO_SNDBUF, &size, sizeof (size)) < 0)
124 size -= TP_BSIZE;
125 (void)setsockopt(rmtape, SOL_SOCKET, SO_RCVBUF, &size, sizeof (size));
126 maxseg = 1024;
127 if (setsockopt(rmtape, IPPROTO_TCP, TCP_MAXSEG,
128 &maxseg, sizeof (maxseg)) < 0)
129 perror("TCP_MAXSEG setsockopt");
130
131 #ifdef notdef
132 if (setsockopt(rmtape, IPPROTO_TCP, TCP_NODELAY, &on, sizeof (on)) < 0)
133 perror("TCP_NODELAY setsockopt");
134 #endif
135 }
136
137 static int
okname(cp0)138 okname(cp0)
139 char *cp0;
140 {
141 register char *cp;
142 register int c;
143
144 for (cp = cp0; *cp; cp++) {
145 c = *cp;
146 if (!isascii(c) || !(isalnum(c) || c == '_' || c == '-')) {
147 warnx("invalid user name: %s", cp0);
148 return (0);
149 }
150 }
151 return (1);
152 }
153
154 int
rmtopen(tape,mode)155 rmtopen(tape, mode)
156 char *tape;
157 int mode;
158 {
159 char buf[256];
160
161 (void)sprintf(buf, "O%s\n%d\n", tape, mode);
162 rmtstate = TS_OPEN;
163 return (rmtcall(tape, buf));
164 }
165
166 void
rmtclose()167 rmtclose()
168 {
169
170 if (rmtstate != TS_OPEN)
171 return;
172 rmtcall("close", "C\n");
173 rmtstate = TS_CLOSED;
174 }
175
176 int
rmtread(buf,count)177 rmtread(buf, count)
178 char *buf;
179 int count;
180 {
181 char line[30];
182 int n, i, cc;
183 extern errno;
184
185 (void)sprintf(line, "R%d\n", count);
186 n = rmtcall("read", line);
187 if (n < 0) {
188 errno = n;
189 return (-1);
190 }
191 for (i = 0; i < n; i += cc) {
192 cc = read(rmtape, buf+i, n - i);
193 if (cc <= 0) {
194 rmtconnaborted();
195 }
196 }
197 return (n);
198 }
199
200 int
rmtwrite(buf,count)201 rmtwrite(buf, count)
202 char *buf;
203 int count;
204 {
205 char line[30];
206
207 (void)sprintf(line, "W%d\n", count);
208 write(rmtape, line, strlen(line));
209 write(rmtape, buf, count);
210 return (rmtreply("write"));
211 }
212
213 void
rmtwrite0(count)214 rmtwrite0(count)
215 int count;
216 {
217 char line[30];
218
219 (void)sprintf(line, "W%d\n", count);
220 write(rmtape, line, strlen(line));
221 }
222
223 void
rmtwrite1(buf,count)224 rmtwrite1(buf, count)
225 char *buf;
226 int count;
227 {
228
229 write(rmtape, buf, count);
230 }
231
232 int
rmtwrite2()233 rmtwrite2()
234 {
235
236 return (rmtreply("write"));
237 }
238
239 int
rmtseek(offset,pos)240 rmtseek(offset, pos)
241 int offset, pos;
242 {
243 char line[80];
244
245 (void)sprintf(line, "L%d\n%d\n", offset, pos);
246 return (rmtcall("seek", line));
247 }
248
249 struct mtget mts;
250
251 struct mtget *
rmtstatus()252 rmtstatus()
253 {
254 register int i;
255 register char *cp;
256
257 if (rmtstate != TS_OPEN)
258 return (NULL);
259 rmtcall("status", "S\n");
260 for (i = 0, cp = (char *)&mts; i < sizeof(mts); i++)
261 *cp++ = rmtgetb();
262 return (&mts);
263 }
264
265 int
rmtioctl(cmd,count)266 rmtioctl(cmd, count)
267 int cmd, count;
268 {
269 char buf[256];
270
271 if (count < 0)
272 return (-1);
273 (void)sprintf(buf, "I%d\n%d\n", cmd, count);
274 return (rmtcall("ioctl", buf));
275 }
276
277 static int
rmtcall(cmd,buf)278 rmtcall(cmd, buf)
279 char *cmd, *buf;
280 {
281
282 if (write(rmtape, buf, strlen(buf)) != strlen(buf))
283 rmtconnaborted();
284 return (rmtreply(cmd));
285 }
286
287 static int
rmtreply(cmd)288 rmtreply(cmd)
289 char *cmd;
290 {
291 register char *cp;
292 char code[30], emsg[BUFSIZ];
293
294 rmtgets(code, sizeof (code));
295 if (*code == 'E' || *code == 'F') {
296 rmtgets(emsg, sizeof (emsg));
297 msg("%s: %s", cmd, emsg);
298 if (*code == 'F') {
299 rmtstate = TS_CLOSED;
300 return (-1);
301 }
302 return (-1);
303 }
304 if (*code != 'A') {
305 /* Kill trailing newline */
306 cp = code + strlen(code);
307 if (cp > code && *--cp == '\n')
308 *cp = '\0';
309
310 msg("Protocol to remote tape server botched (code \"%s\").\n",
311 code);
312 rmtconnaborted();
313 }
314 return (atoi(code + 1));
315 }
316
317 int
rmtgetb()318 rmtgetb()
319 {
320 char c;
321
322 if (read(rmtape, &c, 1) != 1)
323 rmtconnaborted();
324 return (c);
325 }
326
327 /* Get a line (guaranteed to have a trailing newline). */
328 void
rmtgets(line,len)329 rmtgets(line, len)
330 char *line;
331 int len;
332 {
333 register char *cp = line;
334
335 while (len > 1) {
336 *cp = rmtgetb();
337 if (*cp == '\n') {
338 cp[1] = '\0';
339 return;
340 }
341 cp++;
342 len--;
343 }
344 *cp = '\0';
345 msg("Protocol to remote tape server botched.\n");
346 msg("(rmtgets got \"%s\").\n", line);
347 rmtconnaborted();
348 }
349