18fae3551SRodney W. Grimes /*-
2*8a16b7a1SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause
3*8a16b7a1SPedro F. Giffuni *
48fae3551SRodney W. Grimes * Copyright (c) 1980, 1993
58fae3551SRodney W. Grimes * The Regents of the University of California. All rights reserved.
68fae3551SRodney W. Grimes *
78fae3551SRodney W. Grimes * Redistribution and use in source and binary forms, with or without
88fae3551SRodney W. Grimes * modification, are permitted provided that the following conditions
98fae3551SRodney W. Grimes * are met:
108fae3551SRodney W. Grimes * 1. Redistributions of source code must retain the above copyright
118fae3551SRodney W. Grimes * notice, this list of conditions and the following disclaimer.
128fae3551SRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright
138fae3551SRodney W. Grimes * notice, this list of conditions and the following disclaimer in the
148fae3551SRodney W. Grimes * documentation and/or other materials provided with the distribution.
15fbbd9655SWarner Losh * 3. Neither the name of the University nor the names of its contributors
168fae3551SRodney W. Grimes * may be used to endorse or promote products derived from this software
178fae3551SRodney W. Grimes * without specific prior written permission.
188fae3551SRodney W. Grimes *
198fae3551SRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
208fae3551SRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
218fae3551SRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
228fae3551SRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
238fae3551SRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
248fae3551SRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
258fae3551SRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
268fae3551SRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
278fae3551SRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
288fae3551SRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
298fae3551SRodney W. Grimes * SUCH DAMAGE.
308fae3551SRodney W. Grimes */
318fae3551SRodney W. Grimes
328fae3551SRodney W. Grimes #include <sys/param.h>
338fae3551SRodney W. Grimes #include <sys/mtio.h>
348fae3551SRodney W. Grimes #include <sys/socket.h>
358fae3551SRodney W. Grimes #include <sys/time.h>
368fae3551SRodney W. Grimes
378fae3551SRodney W. Grimes #include <ufs/ufs/dinode.h>
388fae3551SRodney W. Grimes
398fae3551SRodney W. Grimes #include <netinet/in.h>
40d71ba03dSBill Fenner #include <netinet/in_systm.h>
41d71ba03dSBill Fenner #include <netinet/ip.h>
424a3bf3b2SBill Fenner #include <netinet/tcp.h>
438fae3551SRodney W. Grimes
448fae3551SRodney W. Grimes #include <protocols/dumprestore.h>
458fae3551SRodney W. Grimes
468fae3551SRodney W. Grimes #include <ctype.h>
478fae3551SRodney W. Grimes #include <netdb.h>
488fae3551SRodney W. Grimes #include <pwd.h>
498fae3551SRodney W. Grimes #include <stdio.h>
5089fdc4e1SMike Barcroft #include <limits.h>
5137736675SWarner Losh #include <errno.h>
528fae3551SRodney W. Grimes #include <stdlib.h>
538fae3551SRodney W. Grimes #include <string.h>
548fae3551SRodney W. Grimes #include <unistd.h>
558fae3551SRodney W. Grimes
568fae3551SRodney W. Grimes #include "pathnames.h"
578fae3551SRodney W. Grimes #include "dump.h"
588fae3551SRodney W. Grimes
598fae3551SRodney W. Grimes #define TS_CLOSED 0
608fae3551SRodney W. Grimes #define TS_OPEN 1
618fae3551SRodney W. Grimes
628fae3551SRodney W. Grimes static int rmtstate = TS_CLOSED;
638fae3551SRodney W. Grimes static int rmtape;
648fae3551SRodney W. Grimes static char *rmtpeer;
658fae3551SRodney W. Grimes
662db673abSWarner Losh static int okname(const char *);
672db673abSWarner Losh static int rmtcall(const char *, const char *);
682db673abSWarner Losh static void rmtconnaborted(int);
692db673abSWarner Losh static int rmtgetb(void);
702db673abSWarner Losh static void rmtgetconn(void);
712db673abSWarner Losh static void rmtgets(char *, int);
722db673abSWarner Losh static int rmtreply(const char *);
738fae3551SRodney W. Grimes
744aad1224SBill Fenner static int errfd = -1;
758fae3551SRodney W. Grimes
768fae3551SRodney W. Grimes int
rmthost(const char * host)772db673abSWarner Losh rmthost(const char *host)
788fae3551SRodney W. Grimes {
798fae3551SRodney W. Grimes
802db673abSWarner Losh rmtpeer = strdup(host);
812db673abSWarner Losh if (rmtpeer == NULL)
822db673abSWarner Losh return (0);
838fae3551SRodney W. Grimes signal(SIGPIPE, rmtconnaborted);
848fae3551SRodney W. Grimes rmtgetconn();
858fae3551SRodney W. Grimes if (rmtape < 0)
868fae3551SRodney W. Grimes return (0);
878fae3551SRodney W. Grimes return (1);
888fae3551SRodney W. Grimes }
898fae3551SRodney W. Grimes
908fae3551SRodney W. Grimes static void
rmtconnaborted(int sig __unused)912db673abSWarner Losh rmtconnaborted(int sig __unused)
928fae3551SRodney W. Grimes {
934aad1224SBill Fenner msg("Lost connection to remote host.\n");
944aad1224SBill Fenner if (errfd != -1) {
954aad1224SBill Fenner fd_set r;
964aad1224SBill Fenner struct timeval t;
978fae3551SRodney W. Grimes
984aad1224SBill Fenner FD_ZERO(&r);
994aad1224SBill Fenner FD_SET(errfd, &r);
1004aad1224SBill Fenner t.tv_sec = 0;
1014aad1224SBill Fenner t.tv_usec = 0;
1024aad1224SBill Fenner if (select(errfd + 1, &r, NULL, NULL, &t)) {
1034aad1224SBill Fenner int i;
1044aad1224SBill Fenner char buf[2048];
1054aad1224SBill Fenner
1064aad1224SBill Fenner if ((i = read(errfd, buf, sizeof(buf) - 1)) > 0) {
1074aad1224SBill Fenner buf[i] = '\0';
1084aad1224SBill Fenner msg("on %s: %s%s", rmtpeer, buf,
1094aad1224SBill Fenner buf[i - 1] == '\n' ? "" : "\n");
1104aad1224SBill Fenner }
1114aad1224SBill Fenner }
1124aad1224SBill Fenner }
1134aad1224SBill Fenner
1144aad1224SBill Fenner exit(X_ABORT);
1158fae3551SRodney W. Grimes }
1168fae3551SRodney W. Grimes
1178fae3551SRodney W. Grimes void
rmtgetconn(void)1182db673abSWarner Losh rmtgetconn(void)
1198fae3551SRodney W. Grimes {
120d2334e27SIan Dowse char *cp;
121d2334e27SIan Dowse const char *rmt;
1228fae3551SRodney W. Grimes static struct servent *sp = NULL;
1238fae3551SRodney W. Grimes static struct passwd *pwd = NULL;
1248fae3551SRodney W. Grimes char *tuser;
1258fae3551SRodney W. Grimes int size;
126d71ba03dSBill Fenner int throughput;
1274a3bf3b2SBill Fenner int on;
1288fae3551SRodney W. Grimes
1298fae3551SRodney W. Grimes if (sp == NULL) {
1308edde085SMark Murray sp = getservbyname("shell", "tcp");
1318fae3551SRodney W. Grimes if (sp == NULL) {
1328edde085SMark Murray msg("shell/tcp: unknown service\n");
133f69e804dSJoseph Koshy exit(X_STARTUP);
1348fae3551SRodney W. Grimes }
1358fae3551SRodney W. Grimes pwd = getpwuid(getuid());
1368fae3551SRodney W. Grimes if (pwd == NULL) {
1374aad1224SBill Fenner msg("who are you?\n");
138f69e804dSJoseph Koshy exit(X_STARTUP);
1398fae3551SRodney W. Grimes }
1408fae3551SRodney W. Grimes }
141a37c38b8SPeter Wemm if ((cp = strchr(rmtpeer, '@')) != NULL) {
1428fae3551SRodney W. Grimes tuser = rmtpeer;
1438fae3551SRodney W. Grimes *cp = '\0';
1448fae3551SRodney W. Grimes if (!okname(tuser))
145f69e804dSJoseph Koshy exit(X_STARTUP);
1468fae3551SRodney W. Grimes rmtpeer = ++cp;
1478fae3551SRodney W. Grimes } else
1488fae3551SRodney W. Grimes tuser = pwd->pw_name;
149019420a5SJoerg Wunsch if ((rmt = getenv("RMT")) == NULL)
150019420a5SJoerg Wunsch rmt = _PATH_RMT;
1518a0453d6SJohan Karlsson msg("%s", "");
1521982ee69SGarrett Wollman rmtape = rcmd(&rmtpeer, (u_short)sp->s_port, pwd->pw_name,
1531982ee69SGarrett Wollman tuser, rmt, &errfd);
1544aad1224SBill Fenner if (rmtape < 0) {
1554aad1224SBill Fenner msg("login to %s as %s failed.\n", rmtpeer, tuser);
156d71ba03dSBill Fenner return;
1574aad1224SBill Fenner }
158b11ecdd6SBill Fenner (void)fprintf(stderr, "Connection to %s established.\n", rmtpeer);
1598fae3551SRodney W. Grimes size = ntrec * TP_BSIZE;
1608fae3551SRodney W. Grimes if (size > 60 * 1024) /* XXX */
1618fae3551SRodney W. Grimes size = 60 * 1024;
1628fae3551SRodney W. Grimes /* Leave some space for rmt request/response protocol */
1638fae3551SRodney W. Grimes size += 2 * 1024;
1648fae3551SRodney W. Grimes while (size > TP_BSIZE &&
1658fae3551SRodney W. Grimes setsockopt(rmtape, SOL_SOCKET, SO_SNDBUF, &size, sizeof (size)) < 0)
1668fae3551SRodney W. Grimes size -= TP_BSIZE;
1678fae3551SRodney W. Grimes (void)setsockopt(rmtape, SOL_SOCKET, SO_RCVBUF, &size, sizeof (size));
168d71ba03dSBill Fenner throughput = IPTOS_THROUGHPUT;
169d71ba03dSBill Fenner if (setsockopt(rmtape, IPPROTO_IP, IP_TOS,
170d71ba03dSBill Fenner &throughput, sizeof(throughput)) < 0)
171d71ba03dSBill Fenner perror("IP_TOS:IPTOS_THROUGHPUT setsockopt");
1724a3bf3b2SBill Fenner on = 1;
1738fae3551SRodney W. Grimes if (setsockopt(rmtape, IPPROTO_TCP, TCP_NODELAY, &on, sizeof (on)) < 0)
1748fae3551SRodney W. Grimes perror("TCP_NODELAY setsockopt");
1758fae3551SRodney W. Grimes }
1768fae3551SRodney W. Grimes
1778fae3551SRodney W. Grimes static int
okname(const char * cp0)1782db673abSWarner Losh okname(const char *cp0)
1798fae3551SRodney W. Grimes {
1802db673abSWarner Losh const char *cp;
181d2334e27SIan Dowse int c;
1828fae3551SRodney W. Grimes
1838fae3551SRodney W. Grimes for (cp = cp0; *cp; cp++) {
1848fae3551SRodney W. Grimes c = *cp;
1858fae3551SRodney W. Grimes if (!isascii(c) || !(isalnum(c) || c == '_' || c == '-')) {
1864aad1224SBill Fenner msg("invalid user name %s\n", cp0);
1878fae3551SRodney W. Grimes return (0);
1888fae3551SRodney W. Grimes }
1898fae3551SRodney W. Grimes }
1908fae3551SRodney W. Grimes return (1);
1918fae3551SRodney W. Grimes }
1928fae3551SRodney W. Grimes
1938fae3551SRodney W. Grimes int
rmtopen(const char * tape,int mode)1942db673abSWarner Losh rmtopen(const char *tape, int mode)
1958fae3551SRodney W. Grimes {
1968fae3551SRodney W. Grimes char buf[256];
1978fae3551SRodney W. Grimes
198f5dcc2f1SWarner Losh (void)snprintf(buf, sizeof (buf), "O%.226s\n%d\n", tape, mode);
1998fae3551SRodney W. Grimes rmtstate = TS_OPEN;
2008fae3551SRodney W. Grimes return (rmtcall(tape, buf));
2018fae3551SRodney W. Grimes }
2028fae3551SRodney W. Grimes
2038fae3551SRodney W. Grimes void
rmtclose(void)2042db673abSWarner Losh rmtclose(void)
2058fae3551SRodney W. Grimes {
2068fae3551SRodney W. Grimes
2078fae3551SRodney W. Grimes if (rmtstate != TS_OPEN)
2088fae3551SRodney W. Grimes return;
2098fae3551SRodney W. Grimes rmtcall("close", "C\n");
2108fae3551SRodney W. Grimes rmtstate = TS_CLOSED;
2118fae3551SRodney W. Grimes }
2128fae3551SRodney W. Grimes
2138fae3551SRodney W. Grimes int
rmtread(char * buf,int count)2142db673abSWarner Losh rmtread(char *buf, int count)
2158fae3551SRodney W. Grimes {
2168fae3551SRodney W. Grimes char line[30];
2178fae3551SRodney W. Grimes int n, i, cc;
2188fae3551SRodney W. Grimes
219f5dcc2f1SWarner Losh (void)snprintf(line, sizeof (line), "R%d\n", count);
2208fae3551SRodney W. Grimes n = rmtcall("read", line);
22149fccf2aSJustin T. Gibbs if (n < 0)
22249fccf2aSJustin T. Gibbs /* rmtcall() properly sets errno for us on errors. */
22349fccf2aSJustin T. Gibbs return (n);
2248fae3551SRodney W. Grimes for (i = 0; i < n; i += cc) {
2258fae3551SRodney W. Grimes cc = read(rmtape, buf+i, n - i);
22649fccf2aSJustin T. Gibbs if (cc <= 0)
2272db673abSWarner Losh rmtconnaborted(0);
2288fae3551SRodney W. Grimes }
2298fae3551SRodney W. Grimes return (n);
2308fae3551SRodney W. Grimes }
2318fae3551SRodney W. Grimes
2328fae3551SRodney W. Grimes int
rmtwrite(const char * buf,int count)2332db673abSWarner Losh rmtwrite(const char *buf, int count)
2348fae3551SRodney W. Grimes {
2358fae3551SRodney W. Grimes char line[30];
2368fae3551SRodney W. Grimes
237f5dcc2f1SWarner Losh (void)snprintf(line, sizeof (line), "W%d\n", count);
2388fae3551SRodney W. Grimes write(rmtape, line, strlen(line));
2398fae3551SRodney W. Grimes write(rmtape, buf, count);
2408fae3551SRodney W. Grimes return (rmtreply("write"));
2418fae3551SRodney W. Grimes }
2428fae3551SRodney W. Grimes
2438fae3551SRodney W. Grimes void
rmtwrite0(int count)2442db673abSWarner Losh rmtwrite0(int count)
2458fae3551SRodney W. Grimes {
2468fae3551SRodney W. Grimes char line[30];
2478fae3551SRodney W. Grimes
248f5dcc2f1SWarner Losh (void)snprintf(line, sizeof (line), "W%d\n", count);
2498fae3551SRodney W. Grimes write(rmtape, line, strlen(line));
2508fae3551SRodney W. Grimes }
2518fae3551SRodney W. Grimes
2528fae3551SRodney W. Grimes void
rmtwrite1(const char * buf,int count)2532db673abSWarner Losh rmtwrite1(const char *buf, int count)
2548fae3551SRodney W. Grimes {
2558fae3551SRodney W. Grimes
2568fae3551SRodney W. Grimes write(rmtape, buf, count);
2578fae3551SRodney W. Grimes }
2588fae3551SRodney W. Grimes
2598fae3551SRodney W. Grimes int
rmtwrite2(void)2602db673abSWarner Losh rmtwrite2(void)
2618fae3551SRodney W. Grimes {
2628fae3551SRodney W. Grimes
2638fae3551SRodney W. Grimes return (rmtreply("write"));
2648fae3551SRodney W. Grimes }
2658fae3551SRodney W. Grimes
2668fae3551SRodney W. Grimes int
rmtseek(int offset,int pos)2672db673abSWarner Losh rmtseek(int offset, int pos) /* XXX off_t ? */
2688fae3551SRodney W. Grimes {
2698fae3551SRodney W. Grimes char line[80];
2708fae3551SRodney W. Grimes
271f5dcc2f1SWarner Losh (void)snprintf(line, sizeof (line), "L%d\n%d\n", offset, pos);
2728fae3551SRodney W. Grimes return (rmtcall("seek", line));
2738fae3551SRodney W. Grimes }
2748fae3551SRodney W. Grimes
2758fae3551SRodney W. Grimes struct mtget mts;
2768fae3551SRodney W. Grimes
2778fae3551SRodney W. Grimes struct mtget *
rmtstatus(void)2782db673abSWarner Losh rmtstatus(void)
2798fae3551SRodney W. Grimes {
280d2334e27SIan Dowse int i;
281d2334e27SIan Dowse char *cp;
2828fae3551SRodney W. Grimes
2838fae3551SRodney W. Grimes if (rmtstate != TS_OPEN)
2848fae3551SRodney W. Grimes return (NULL);
2858fae3551SRodney W. Grimes rmtcall("status", "S\n");
2868fae3551SRodney W. Grimes for (i = 0, cp = (char *)&mts; i < sizeof(mts); i++)
2878fae3551SRodney W. Grimes *cp++ = rmtgetb();
2888fae3551SRodney W. Grimes return (&mts);
2898fae3551SRodney W. Grimes }
2908fae3551SRodney W. Grimes
2918fae3551SRodney W. Grimes int
rmtioctl(int cmd,int count)2922db673abSWarner Losh rmtioctl(int cmd, int count)
2938fae3551SRodney W. Grimes {
2948fae3551SRodney W. Grimes char buf[256];
2958fae3551SRodney W. Grimes
2968fae3551SRodney W. Grimes if (count < 0)
2978fae3551SRodney W. Grimes return (-1);
298f5dcc2f1SWarner Losh (void)snprintf(buf, sizeof (buf), "I%d\n%d\n", cmd, count);
2998fae3551SRodney W. Grimes return (rmtcall("ioctl", buf));
3008fae3551SRodney W. Grimes }
3018fae3551SRodney W. Grimes
3028fae3551SRodney W. Grimes static int
rmtcall(const char * cmd,const char * buf)3032db673abSWarner Losh rmtcall(const char *cmd, const char *buf)
3048fae3551SRodney W. Grimes {
3058fae3551SRodney W. Grimes
3068fae3551SRodney W. Grimes if (write(rmtape, buf, strlen(buf)) != strlen(buf))
3072db673abSWarner Losh rmtconnaborted(0);
3088fae3551SRodney W. Grimes return (rmtreply(cmd));
3098fae3551SRodney W. Grimes }
3108fae3551SRodney W. Grimes
3118fae3551SRodney W. Grimes static int
rmtreply(const char * cmd)3122db673abSWarner Losh rmtreply(const char *cmd)
3138fae3551SRodney W. Grimes {
314d2334e27SIan Dowse char *cp;
3158fae3551SRodney W. Grimes char code[30], emsg[BUFSIZ];
3168fae3551SRodney W. Grimes
3178fae3551SRodney W. Grimes rmtgets(code, sizeof (code));
3188fae3551SRodney W. Grimes if (*code == 'E' || *code == 'F') {
3198fae3551SRodney W. Grimes rmtgets(emsg, sizeof (emsg));
3208fae3551SRodney W. Grimes msg("%s: %s", cmd, emsg);
32149fccf2aSJustin T. Gibbs errno = atoi(code + 1);
32249fccf2aSJustin T. Gibbs if (*code == 'F')
3238fae3551SRodney W. Grimes rmtstate = TS_CLOSED;
3248fae3551SRodney W. Grimes return (-1);
3258fae3551SRodney W. Grimes }
3268fae3551SRodney W. Grimes if (*code != 'A') {
3278fae3551SRodney W. Grimes /* Kill trailing newline */
3288fae3551SRodney W. Grimes cp = code + strlen(code);
3298fae3551SRodney W. Grimes if (cp > code && *--cp == '\n')
3308fae3551SRodney W. Grimes *cp = '\0';
3318fae3551SRodney W. Grimes
3328fae3551SRodney W. Grimes msg("Protocol to remote tape server botched (code \"%s\").\n",
3338fae3551SRodney W. Grimes code);
3342db673abSWarner Losh rmtconnaborted(0);
3358fae3551SRodney W. Grimes }
3368fae3551SRodney W. Grimes return (atoi(code + 1));
3378fae3551SRodney W. Grimes }
3388fae3551SRodney W. Grimes
3398fae3551SRodney W. Grimes int
rmtgetb(void)3402db673abSWarner Losh rmtgetb(void)
3418fae3551SRodney W. Grimes {
3428fae3551SRodney W. Grimes char c;
3438fae3551SRodney W. Grimes
3448fae3551SRodney W. Grimes if (read(rmtape, &c, 1) != 1)
3452db673abSWarner Losh rmtconnaborted(0);
3468fae3551SRodney W. Grimes return (c);
3478fae3551SRodney W. Grimes }
3488fae3551SRodney W. Grimes
3498fae3551SRodney W. Grimes /* Get a line (guaranteed to have a trailing newline). */
3508fae3551SRodney W. Grimes void
rmtgets(char * line,int len)3512db673abSWarner Losh rmtgets(char *line, int len)
3528fae3551SRodney W. Grimes {
353d2334e27SIan Dowse char *cp = line;
3548fae3551SRodney W. Grimes
3558fae3551SRodney W. Grimes while (len > 1) {
3568fae3551SRodney W. Grimes *cp = rmtgetb();
3578fae3551SRodney W. Grimes if (*cp == '\n') {
3588fae3551SRodney W. Grimes cp[1] = '\0';
3598fae3551SRodney W. Grimes return;
3608fae3551SRodney W. Grimes }
3618fae3551SRodney W. Grimes cp++;
3628fae3551SRodney W. Grimes len--;
3638fae3551SRodney W. Grimes }
3648fae3551SRodney W. Grimes *cp = '\0';
3658fae3551SRodney W. Grimes msg("Protocol to remote tape server botched.\n");
3668fae3551SRodney W. Grimes msg("(rmtgets got \"%s\").\n", line);
3672db673abSWarner Losh rmtconnaborted(0);
3688fae3551SRodney W. Grimes }
369