147082Smckusick /*-
261484Sbostic * Copyright (c) 1980, 1993
361484Sbostic * The Regents of the University of California. All rights reserved.
447082Smckusick *
547082Smckusick * %sccs.include.redist.c%
622039Sdist */
76645Ssam
822039Sdist #ifndef lint
9*68991Sbostic static char sccsid[] = "@(#)dumprmt.c 8.3 (Berkeley) 04/28/95";
1046587Storek #endif /* not lint */
1122039Sdist
126884Ssam #include <sys/param.h>
136645Ssam #include <sys/mtio.h>
146645Ssam #include <sys/ioctl.h>
1517538Sralph #include <sys/socket.h>
1657724Smckusick #include <sys/time.h>
1757724Smckusick #ifdef sunos
1857724Smckusick #include <sys/vnode.h>
1957724Smckusick
2057724Smckusick #include <ufs/inode.h>
2150498Smckusick #else
2257724Smckusick #include <ufs/ufs/dinode.h>
2350498Smckusick #endif
246645Ssam
259306Ssam #include <netinet/in.h>
2657724Smckusick #include <netinet/tcp.h>
279306Ssam
2857724Smckusick #include <protocols/dumprestore.h>
2957724Smckusick
3057724Smckusick #include <ctype.h>
3168986Sbostic #include <err.h>
329306Ssam #include <netdb.h>
3337946Sbostic #include <pwd.h>
3457724Smckusick #include <signal.h>
3557724Smckusick #include <stdio.h>
3646795Sbostic #ifdef __STDC__
3746587Storek #include <stdlib.h>
3846587Storek #include <string.h>
3957724Smckusick #include <unistd.h>
4046795Sbostic #endif
4157724Smckusick
4237946Sbostic #include "pathnames.h"
4357724Smckusick #include "dump.h"
449306Ssam
456645Ssam #define TS_CLOSED 0
466645Ssam #define TS_OPEN 1
476645Ssam
486645Ssam static int rmtstate = TS_CLOSED;
4957724Smckusick static int rmtape;
5057724Smckusick static char *rmtpeer;
516645Ssam
5257724Smckusick static int okname __P((char *));
5357724Smckusick static int rmtcall __P((char *, char *));
5457724Smckusick static void rmtconnaborted __P((/* int, int */));
5557724Smckusick static int rmtgetb __P((void));
5657724Smckusick static void rmtgetconn __P((void));
5757724Smckusick static void rmtgets __P((char *, int));
5857724Smckusick static int rmtreply __P((char *));
5917538Sralph
6057724Smckusick extern int ntrec; /* blocking factor on tape */
6154044Smckusick
6246587Storek int
rmthost(host)636645Ssam rmthost(host)
646645Ssam char *host;
656645Ssam {
666645Ssam
6757724Smckusick rmtpeer = malloc(strlen(host) + 1);
6857724Smckusick if (rmtpeer)
6957724Smckusick strcpy(rmtpeer, host);
7057724Smckusick else
7157724Smckusick rmtpeer = host;
7213032Ssam signal(SIGPIPE, rmtconnaborted);
736645Ssam rmtgetconn();
746645Ssam if (rmtape < 0)
7517538Sralph return (0);
7617538Sralph return (1);
776645Ssam }
786645Ssam
7957724Smckusick static void
rmtconnaborted()806645Ssam rmtconnaborted()
816645Ssam {
826645Ssam
8368986Sbostic errx(1, "Lost connection to remote host.");
846645Ssam }
856645Ssam
8646587Storek void
rmtgetconn()876645Ssam rmtgetconn()
886645Ssam {
8957724Smckusick register char *cp;
9059924Storek static struct servent *sp = NULL;
9159924Storek static struct passwd *pwd = NULL;
9257724Smckusick #ifdef notdef
9357724Smckusick static int on = 1;
9457724Smckusick #endif
9557724Smckusick char *tuser;
9617538Sralph int size;
9757724Smckusick int maxseg;
986645Ssam
9959924Storek if (sp == NULL) {
1009306Ssam sp = getservbyname("shell", "tcp");
10168986Sbostic if (sp == NULL)
10268986Sbostic errx(1, "shell/tcp: unknown service");
10357724Smckusick pwd = getpwuid(getuid());
10468986Sbostic if (pwd == NULL)
10568986Sbostic errx(1, "who are you?");
1069306Ssam }
107*68991Sbostic if ((cp = strchr(rmtpeer, '@')) != NULL) {
10857724Smckusick tuser = rmtpeer;
10957724Smckusick *cp = '\0';
11057724Smckusick if (!okname(tuser))
11157724Smckusick exit(1);
11257724Smckusick rmtpeer = ++cp;
11357724Smckusick } else
11457724Smckusick tuser = pwd->pw_name;
11557724Smckusick rmtape = rcmd(&rmtpeer, (u_short)sp->s_port, pwd->pw_name, tuser,
11657724Smckusick _PATH_RMT, (int *)0);
11717538Sralph size = ntrec * TP_BSIZE;
11857724Smckusick if (size > 60 * 1024) /* XXX */
11957724Smckusick size = 60 * 1024;
12057724Smckusick /* Leave some space for rmt request/response protocol */
12157724Smckusick size += 2 * 1024;
12218493Smckusick while (size > TP_BSIZE &&
12318493Smckusick setsockopt(rmtape, SOL_SOCKET, SO_SNDBUF, &size, sizeof (size)) < 0)
12457724Smckusick size -= TP_BSIZE;
12557724Smckusick (void)setsockopt(rmtape, SOL_SOCKET, SO_RCVBUF, &size, sizeof (size));
12657724Smckusick maxseg = 1024;
12757724Smckusick if (setsockopt(rmtape, IPPROTO_TCP, TCP_MAXSEG,
12857724Smckusick &maxseg, sizeof (maxseg)) < 0)
12957724Smckusick perror("TCP_MAXSEG setsockopt");
13057724Smckusick
13157724Smckusick #ifdef notdef
13257724Smckusick if (setsockopt(rmtape, IPPROTO_TCP, TCP_NODELAY, &on, sizeof (on)) < 0)
13357724Smckusick perror("TCP_NODELAY setsockopt");
13457724Smckusick #endif
1356645Ssam }
1366645Ssam
13757724Smckusick static int
okname(cp0)13857724Smckusick okname(cp0)
13957724Smckusick char *cp0;
14057724Smckusick {
14157724Smckusick register char *cp;
14257724Smckusick register int c;
14357724Smckusick
14457724Smckusick for (cp = cp0; *cp; cp++) {
14557724Smckusick c = *cp;
14657724Smckusick if (!isascii(c) || !(isalnum(c) || c == '_' || c == '-')) {
14768986Sbostic warnx("invalid user name: %s", cp0);
14857724Smckusick return (0);
14957724Smckusick }
15057724Smckusick }
15157724Smckusick return (1);
15257724Smckusick }
15357724Smckusick
15446587Storek int
rmtopen(tape,mode)1556645Ssam rmtopen(tape, mode)
1566645Ssam char *tape;
1576645Ssam int mode;
1586645Ssam {
1596645Ssam char buf[256];
1606645Ssam
16132455Sbostic (void)sprintf(buf, "O%s\n%d\n", tape, mode);
1626645Ssam rmtstate = TS_OPEN;
16324836Smckusick return (rmtcall(tape, buf));
1646645Ssam }
1656645Ssam
16646587Storek void
rmtclose()1676645Ssam rmtclose()
1686645Ssam {
1696645Ssam
1706645Ssam if (rmtstate != TS_OPEN)
1716645Ssam return;
1726645Ssam rmtcall("close", "C\n");
1736645Ssam rmtstate = TS_CLOSED;
1746645Ssam }
1756645Ssam
17646587Storek int
rmtread(buf,count)1776645Ssam rmtread(buf, count)
1786645Ssam char *buf;
1796645Ssam int count;
1806645Ssam {
1816645Ssam char line[30];
1826645Ssam int n, i, cc;
1836884Ssam extern errno;
1846645Ssam
18532455Sbostic (void)sprintf(line, "R%d\n", count);
1866645Ssam n = rmtcall("read", line);
1876884Ssam if (n < 0) {
1886884Ssam errno = n;
1896645Ssam return (-1);
1906884Ssam }
1916645Ssam for (i = 0; i < n; i += cc) {
1926645Ssam cc = read(rmtape, buf+i, n - i);
1936884Ssam if (cc <= 0) {
1946645Ssam rmtconnaborted();
1956884Ssam }
1966645Ssam }
1976645Ssam return (n);
1986645Ssam }
1996645Ssam
20046587Storek int
rmtwrite(buf,count)2016645Ssam rmtwrite(buf, count)
2026645Ssam char *buf;
2036645Ssam int count;
2046645Ssam {
2056645Ssam char line[30];
2066645Ssam
20732455Sbostic (void)sprintf(line, "W%d\n", count);
2086645Ssam write(rmtape, line, strlen(line));
2096645Ssam write(rmtape, buf, count);
2106645Ssam return (rmtreply("write"));
2116645Ssam }
2126645Ssam
21346587Storek void
rmtwrite0(count)2146645Ssam rmtwrite0(count)
2156645Ssam int count;
2166645Ssam {
2176645Ssam char line[30];
2186645Ssam
21932455Sbostic (void)sprintf(line, "W%d\n", count);
2206645Ssam write(rmtape, line, strlen(line));
2216645Ssam }
2226645Ssam
22346587Storek void
rmtwrite1(buf,count)2246645Ssam rmtwrite1(buf, count)
2256645Ssam char *buf;
2266645Ssam int count;
2276645Ssam {
2286645Ssam
2296645Ssam write(rmtape, buf, count);
2306645Ssam }
2316645Ssam
23246587Storek int
rmtwrite2()2336645Ssam rmtwrite2()
2346645Ssam {
2356645Ssam
2366645Ssam return (rmtreply("write"));
2376645Ssam }
2386645Ssam
23946587Storek int
rmtseek(offset,pos)2406645Ssam rmtseek(offset, pos)
2416645Ssam int offset, pos;
2426645Ssam {
2436645Ssam char line[80];
2446645Ssam
24532455Sbostic (void)sprintf(line, "L%d\n%d\n", offset, pos);
2466645Ssam return (rmtcall("seek", line));
2476645Ssam }
2486645Ssam
2496645Ssam struct mtget mts;
2506645Ssam
2516645Ssam struct mtget *
rmtstatus()2526645Ssam rmtstatus()
2536645Ssam {
2546645Ssam register int i;
2556645Ssam register char *cp;
2566645Ssam
2576645Ssam if (rmtstate != TS_OPEN)
25859924Storek return (NULL);
2596645Ssam rmtcall("status", "S\n");
2606645Ssam for (i = 0, cp = (char *)&mts; i < sizeof(mts); i++)
2616645Ssam *cp++ = rmtgetb();
2626645Ssam return (&mts);
2636645Ssam }
2646645Ssam
26557727Smckusick int
rmtioctl(cmd,count)26657727Smckusick rmtioctl(cmd, count)
26757727Smckusick int cmd, count;
26857727Smckusick {
26957727Smckusick char buf[256];
27057727Smckusick
27157727Smckusick if (count < 0)
27257727Smckusick return (-1);
27357727Smckusick (void)sprintf(buf, "I%d\n%d\n", cmd, count);
27457727Smckusick return (rmtcall("ioctl", buf));
27557727Smckusick }
27657727Smckusick
27757724Smckusick static int
rmtcall(cmd,buf)2786645Ssam rmtcall(cmd, buf)
2796645Ssam char *cmd, *buf;
2806645Ssam {
2816645Ssam
2826645Ssam if (write(rmtape, buf, strlen(buf)) != strlen(buf))
2836645Ssam rmtconnaborted();
2846645Ssam return (rmtreply(cmd));
2856645Ssam }
2866645Ssam
28757724Smckusick static int
rmtreply(cmd)2886645Ssam rmtreply(cmd)
2896645Ssam char *cmd;
2906645Ssam {
29159924Storek register char *cp;
2926645Ssam char code[30], emsg[BUFSIZ];
2936645Ssam
2946645Ssam rmtgets(code, sizeof (code));
2956645Ssam if (*code == 'E' || *code == 'F') {
2966645Ssam rmtgets(emsg, sizeof (emsg));
29759924Storek msg("%s: %s", cmd, emsg);
2986645Ssam if (*code == 'F') {
2996645Ssam rmtstate = TS_CLOSED;
3006645Ssam return (-1);
3016645Ssam }
3026645Ssam return (-1);
3036645Ssam }
3046645Ssam if (*code != 'A') {
30559924Storek /* Kill trailing newline */
30659924Storek cp = code + strlen(code);
30759924Storek if (cp > code && *--cp == '\n')
30859924Storek *cp = '\0';
30959924Storek
31059924Storek msg("Protocol to remote tape server botched (code \"%s\").\n",
3116645Ssam code);
3126645Ssam rmtconnaborted();
3136645Ssam }
3146645Ssam return (atoi(code + 1));
3156645Ssam }
3166645Ssam
31746587Storek int
rmtgetb()3186645Ssam rmtgetb()
3196645Ssam {
3206645Ssam char c;
3216645Ssam
3226645Ssam if (read(rmtape, &c, 1) != 1)
3236645Ssam rmtconnaborted();
3246645Ssam return (c);
3256645Ssam }
3266645Ssam
32759924Storek /* Get a line (guaranteed to have a trailing newline). */
32846587Storek void
rmtgets(line,len)32957724Smckusick rmtgets(line, len)
33057724Smckusick char *line;
3316645Ssam int len;
3326645Ssam {
33357724Smckusick register char *cp = line;
3346645Ssam
3356645Ssam while (len > 1) {
3366645Ssam *cp = rmtgetb();
3376645Ssam if (*cp == '\n') {
33859924Storek cp[1] = '\0';
3396645Ssam return;
3406645Ssam }
3416645Ssam cp++;
3426645Ssam len--;
3436645Ssam }
34459924Storek *cp = '\0';
34557724Smckusick msg("Protocol to remote tape server botched.\n");
34657724Smckusick msg("(rmtgets got \"%s\").\n", line);
3476645Ssam rmtconnaborted();
3486645Ssam }
349