]> git.wh0rd.org - dump.git/blame - common/dumprmt.c
Added the RSH variable to specify a replacement for build-in rcmd
[dump.git] / common / dumprmt.c
CommitLineData
1227625a
SP
1/*
2 * Ported to Linux's Second Extended File System as part of the
3 * dump and restore backup suit
b45f51d6 4 * Remy Card <card@Linux.EU.Org>, 1994-1997
df9ae507 5 * Stelian Pop <pop@cybercable.fr>, 1999
1227625a
SP
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
b45f51d6 42static const char rcsid[] =
0c62667d 43 "$Id: dumprmt.c,v 1.7 1999/10/30 22:55:50 tiniou Exp $";
1227625a
SP
44#endif /* not lint */
45
b45f51d6
SP
46#ifdef __linux__
47#include <sys/types.h>
48#include <linux/types.h>
49#endif
1227625a
SP
50#include <sys/param.h>
51#include <sys/mtio.h>
1227625a
SP
52#include <sys/socket.h>
53#include <sys/time.h>
54#ifdef __linux__
55#include <linux/ext2_fs.h>
56#include <bsdcompat.h>
b45f51d6 57#include <signal.h>
1227625a
SP
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>
b45f51d6
SP
69#include <netinet/in_systm.h>
70#include <netinet/ip.h>
1227625a
SP
71#include <netinet/tcp.h>
72
73#include <protocols/dumprestore.h>
74
75#include <ctype.h>
ddd2ef55
SP
76#include <errno.h>
77#include <compaterr.h>
1227625a
SP
78#include <netdb.h>
79#include <pwd.h>
1227625a
SP
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
97static int rmtstate = TS_CLOSED;
0c62667d
SP
98static int tormtape = -1;
99static int fromrmtape = -1;
ddd2ef55 100static const char *rmtpeer = 0;
1227625a 101
ddd2ef55
SP
102static int okname __P((const char *));
103static int rmtcall __P((const char *, const char *));
104static void rmtconnaborted __P((int));
1227625a 105static int rmtgetb __P((void));
0c62667d 106static int rmtgetconn __P((void));
ddd2ef55
SP
107static void rmtgets __P((char *, size_t));
108static int rmtreply __P((const char *));
0c62667d 109static int piped_child __P((const char **command));
b45f51d6
SP
110#ifdef KERBEROS
111int krcmd __P((char **, int /*u_short*/, char *, char *, int *, char *));
112#endif
1227625a 113
b45f51d6
SP
114static int errfd = -1;
115extern int dokerberos;
1227625a 116extern int ntrec; /* blocking factor on tape */
ddd2ef55
SP
117#ifndef errno
118extern int errno;
119#endif
1227625a
SP
120
121int
ddd2ef55 122rmthost(const char *host)
1227625a 123{
1227625a 124 if (rmtpeer)
ddd2ef55
SP
125 free((void *)rmtpeer);
126 if ((rmtpeer = strdup(host)) == NULL)
1227625a
SP
127 rmtpeer = host;
128 signal(SIGPIPE, rmtconnaborted);
0c62667d 129 return rmtgetconn();
1227625a
SP
130}
131
132static void
ddd2ef55 133rmtconnaborted(int signo)
1227625a 134{
b45f51d6
SP
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 }
1227625a 155
b45f51d6 156 exit(X_ABORT);
1227625a
SP
157}
158
0c62667d 159static int
ddd2ef55 160rmtgetconn(void)
1227625a
SP
161{
162 register char *cp;
b45f51d6 163 register const char *rmt;
1227625a
SP
164 static struct servent *sp = NULL;
165 static struct passwd *pwd = NULL;
ddd2ef55 166 const char *tuser;
0c62667d 167 const char *rsh;
1227625a 168 int size;
b45f51d6
SP
169 int throughput;
170 int on;
1227625a 171
0c62667d
SP
172 rsh = getenv("RSH");
173
174 if (!rsh && sp == NULL) {
b45f51d6 175 sp = getservbyname(dokerberos ? "kshell" : "shell", "tcp");
ddd2ef55
SP
176 if (sp == NULL)
177 errx(1, "%s/tcp: unknown service",
b45f51d6 178 dokerberos ? "kshell" : "shell");
0c62667d
SP
179 }
180 if (pwd == NULL) {
1227625a 181 pwd = getpwuid(getuid());
ddd2ef55
SP
182 if (pwd == NULL)
183 errx(1, "who are you?");
1227625a
SP
184 }
185 if ((cp = strchr(rmtpeer, '@')) != NULL) {
186 tuser = rmtpeer;
187 *cp = '\0';
188 if (!okname(tuser))
b45f51d6 189 exit(X_STARTUP);
1227625a
SP
190 rmtpeer = ++cp;
191 } else
192 tuser = pwd->pw_name;
b45f51d6
SP
193 if ((rmt = getenv("RMT")) == NULL)
194 rmt = _PATH_RMT;
195 msg("");
0c62667d
SP
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 {
b45f51d6 212#ifdef KERBEROS
0c62667d
SP
213 if (dokerberos)
214 tormtape = krcmd((char **)&rmtpeer, sp->s_port, tuser, rmt, &errfd,
215 (char *)0);
216 else
b45f51d6 217#endif
0c62667d
SP
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;
b45f51d6
SP
241 }
242 (void)fprintf(stderr, "Connection to %s established.\n", rmtpeer);
0c62667d 243 return 1;
1227625a
SP
244}
245
246static int
ddd2ef55 247okname(const char *cp0)
1227625a 248{
ddd2ef55 249 register const char *cp;
1227625a
SP
250 register int c;
251
252 for (cp = cp0; *cp; cp++) {
253 c = *cp;
254 if (!isascii(c) || !(isalnum(c) || c == '_' || c == '-')) {
ddd2ef55 255 warnx("invalid user name %s\n", cp0);
1227625a
SP
256 return (0);
257 }
258 }
259 return (1);
260}
261
262int
ddd2ef55 263rmtopen(const char *tape, int mode)
1227625a 264{
ddd2ef55 265 char buf[MAXPATHLEN];
1227625a 266
ddd2ef55 267 (void)snprintf(buf, sizeof (buf), "O%s\n%d\n", tape, mode);
1227625a
SP
268 rmtstate = TS_OPEN;
269 return (rmtcall(tape, buf));
270}
271
272void
ddd2ef55 273rmtclose(void)
1227625a
SP
274{
275
276 if (rmtstate != TS_OPEN)
277 return;
278 rmtcall("close", "C\n");
279 rmtstate = TS_CLOSED;
280}
281
282int
ddd2ef55 283rmtread(char *buf, size_t count)
1227625a
SP
284{
285 char line[30];
ddd2ef55
SP
286 int n, i;
287 ssize_t cc;
1227625a 288
ddd2ef55 289 (void)snprintf(line, sizeof (line), "R%u\n", (unsigned)count);
1227625a 290 n = rmtcall("read", line);
b45f51d6
SP
291 if (n < 0)
292 /* rmtcall() properly sets errno for us on errors. */
293 return (n);
1227625a 294 for (i = 0; i < n; i += cc) {
0c62667d 295 cc = read(fromrmtape, buf+i, n - i);
b45f51d6 296 if (cc <= 0)
ddd2ef55 297 rmtconnaborted(0);
1227625a
SP
298 }
299 return (n);
300}
301
302int
ddd2ef55 303rmtwrite(const char *buf, size_t count)
1227625a
SP
304{
305 char line[30];
306
b45f51d6 307 (void)snprintf(line, sizeof (line), "W%d\n", count);
0c62667d
SP
308 write(tormtape, line, strlen(line));
309 write(tormtape, buf, count);
1227625a
SP
310 return (rmtreply("write"));
311}
312
1227625a 313int
ddd2ef55 314rmtseek(int offset, int pos)
1227625a
SP
315{
316 char line[80];
317
b45f51d6 318 (void)snprintf(line, sizeof (line), "L%d\n%d\n", offset, pos);
1227625a
SP
319 return (rmtcall("seek", line));
320}
321
322struct mtget mts;
323
324struct mtget *
ddd2ef55 325rmtstatus(void)
1227625a
SP
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
338int
ddd2ef55 339rmtioctl(int cmd, int count)
1227625a
SP
340{
341 char buf[256];
342
343 if (count < 0)
344 return (-1);
b45f51d6 345 (void)snprintf(buf, sizeof (buf), "I%d\n%d\n", cmd, count);
1227625a
SP
346 return (rmtcall("ioctl", buf));
347}
348
349static int
ddd2ef55 350rmtcall(const char *cmd, const char *buf)
1227625a
SP
351{
352
0c62667d 353 if (write(tormtape, buf, strlen(buf)) != strlen(buf))
ddd2ef55 354 rmtconnaborted(0);
1227625a
SP
355 return (rmtreply(cmd));
356}
357
358static int
ddd2ef55 359rmtreply(const char *cmd)
1227625a
SP
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);
b45f51d6
SP
368 errno = atoi(code + 1);
369 if (*code == 'F')
1227625a 370 rmtstate = TS_CLOSED;
1227625a
SP
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);
ddd2ef55 381 rmtconnaborted(0);
1227625a
SP
382 }
383 return (atoi(code + 1));
384}
385
ddd2ef55
SP
386static int
387rmtgetb(void)
1227625a
SP
388{
389 char c;
390
0c62667d 391 if (read(fromrmtape, &c, 1) != 1)
ddd2ef55 392 rmtconnaborted(0);
1227625a
SP
393 return (c);
394}
395
396/* Get a line (guaranteed to have a trailing newline). */
ddd2ef55
SP
397static void
398rmtgets(char *line, size_t len)
1227625a
SP
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);
ddd2ef55 414 rmtconnaborted(0);
1227625a 415}
0c62667d
SP
416
417int 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}