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