11558Srgrimes/*- 21558Srgrimes * Copyright (c) 1980, 1993 31558Srgrimes * The Regents of the University of California. All rights reserved. 41558Srgrimes * 51558Srgrimes * Redistribution and use in source and binary forms, with or without 61558Srgrimes * modification, are permitted provided that the following conditions 71558Srgrimes * are met: 81558Srgrimes * 1. Redistributions of source code must retain the above copyright 91558Srgrimes * notice, this list of conditions and the following disclaimer. 101558Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111558Srgrimes * notice, this list of conditions and the following disclaimer in the 121558Srgrimes * documentation and/or other materials provided with the distribution. 13128085Sbde * 4. Neither the name of the University nor the names of its contributors 141558Srgrimes * may be used to endorse or promote products derived from this software 151558Srgrimes * without specific prior written permission. 161558Srgrimes * 171558Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 181558Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 191558Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 201558Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 211558Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 221558Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 231558Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 241558Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 251558Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 261558Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 271558Srgrimes * SUCH DAMAGE. 281558Srgrimes */ 291558Srgrimes 301558Srgrimes#ifndef lint 3136997Scharnier#if 0 3223672Speterstatic char sccsid[] = "@(#)dumprmt.c 8.3 (Berkeley) 4/28/95"; 3336997Scharnier#endif 3436997Scharnierstatic const char rcsid[] = 3550476Speter "$FreeBSD: releng/10.3/sbin/dump/dumprmt.c 128085 2004-04-10 02:22:35Z bde $"; 361558Srgrimes#endif /* not lint */ 371558Srgrimes 381558Srgrimes#include <sys/param.h> 391558Srgrimes#include <sys/mtio.h> 401558Srgrimes#include <sys/socket.h> 411558Srgrimes#include <sys/time.h> 421558Srgrimes 431558Srgrimes#include <ufs/ufs/dinode.h> 441558Srgrimes 451558Srgrimes#include <netinet/in.h> 4619239Sfenner#include <netinet/in_systm.h> 4719239Sfenner#include <netinet/ip.h> 4836115Sfenner#include <netinet/tcp.h> 491558Srgrimes 501558Srgrimes#include <protocols/dumprestore.h> 511558Srgrimes 521558Srgrimes#include <ctype.h> 531558Srgrimes#include <netdb.h> 541558Srgrimes#include <pwd.h> 551558Srgrimes#include <stdio.h> 56103949Smike#include <limits.h> 5759216Simp#include <errno.h> 581558Srgrimes#include <stdlib.h> 591558Srgrimes#include <string.h> 601558Srgrimes#include <unistd.h> 611558Srgrimes 621558Srgrimes#include "pathnames.h" 631558Srgrimes#include "dump.h" 641558Srgrimes 651558Srgrimes#define TS_CLOSED 0 661558Srgrimes#define TS_OPEN 1 671558Srgrimes 681558Srgrimesstatic int rmtstate = TS_CLOSED; 691558Srgrimesstatic int rmtape; 701558Srgrimesstatic char *rmtpeer; 711558Srgrimes 7292837Simpstatic int okname(const char *); 7392837Simpstatic int rmtcall(const char *, const char *); 7492837Simpstatic void rmtconnaborted(int); 7592837Simpstatic int rmtgetb(void); 7692837Simpstatic void rmtgetconn(void); 7792837Simpstatic void rmtgets(char *, int); 7892837Simpstatic int rmtreply(const char *); 791558Srgrimes 8019300Sfennerstatic int errfd = -1; 811558Srgrimesextern int ntrec; /* blocking factor on tape */ 821558Srgrimes 831558Srgrimesint 8492837Simprmthost(const char *host) 851558Srgrimes{ 861558Srgrimes 8792837Simp rmtpeer = strdup(host); 8892837Simp if (rmtpeer == NULL) 8992837Simp return (0); 901558Srgrimes signal(SIGPIPE, rmtconnaborted); 911558Srgrimes rmtgetconn(); 921558Srgrimes if (rmtape < 0) 931558Srgrimes return (0); 941558Srgrimes return (1); 951558Srgrimes} 961558Srgrimes 971558Srgrimesstatic void 9892837Simprmtconnaborted(int sig __unused) 991558Srgrimes{ 10019300Sfenner msg("Lost connection to remote host.\n"); 10119300Sfenner if (errfd != -1) { 10219300Sfenner fd_set r; 10319300Sfenner struct timeval t; 1041558Srgrimes 10519300Sfenner FD_ZERO(&r); 10619300Sfenner FD_SET(errfd, &r); 10719300Sfenner t.tv_sec = 0; 10819300Sfenner t.tv_usec = 0; 10919300Sfenner if (select(errfd + 1, &r, NULL, NULL, &t)) { 11019300Sfenner int i; 11119300Sfenner char buf[2048]; 11219300Sfenner 11319300Sfenner if ((i = read(errfd, buf, sizeof(buf) - 1)) > 0) { 11419300Sfenner buf[i] = '\0'; 11519300Sfenner msg("on %s: %s%s", rmtpeer, buf, 11619300Sfenner buf[i - 1] == '\n' ? "" : "\n"); 11719300Sfenner } 11819300Sfenner } 11919300Sfenner } 12019300Sfenner 12119300Sfenner exit(X_ABORT); 1221558Srgrimes} 1231558Srgrimes 1241558Srgrimesvoid 12592837Simprmtgetconn(void) 1261558Srgrimes{ 12786473Siedowse char *cp; 12886473Siedowse const char *rmt; 1291558Srgrimes static struct servent *sp = NULL; 1301558Srgrimes static struct passwd *pwd = NULL; 1311558Srgrimes char *tuser; 1321558Srgrimes int size; 13319239Sfenner int throughput; 13436115Sfenner int on; 1351558Srgrimes 1361558Srgrimes if (sp == NULL) { 137114452Smarkm sp = getservbyname("shell", "tcp"); 1381558Srgrimes if (sp == NULL) { 139114452Smarkm msg("shell/tcp: unknown service\n"); 14037635Sjkoshy exit(X_STARTUP); 1411558Srgrimes } 1421558Srgrimes pwd = getpwuid(getuid()); 1431558Srgrimes if (pwd == NULL) { 14419300Sfenner msg("who are you?\n"); 14537635Sjkoshy exit(X_STARTUP); 1461558Srgrimes } 1471558Srgrimes } 14823672Speter if ((cp = strchr(rmtpeer, '@')) != NULL) { 1491558Srgrimes tuser = rmtpeer; 1501558Srgrimes *cp = '\0'; 1511558Srgrimes if (!okname(tuser)) 15237635Sjkoshy exit(X_STARTUP); 1531558Srgrimes rmtpeer = ++cp; 1541558Srgrimes } else 1551558Srgrimes tuser = pwd->pw_name; 15612377Sjoerg if ((rmt = getenv("RMT")) == NULL) 15712377Sjoerg rmt = _PATH_RMT; 158122669Sjohan msg("%s", ""); 159114452Smarkm rmtape = rcmd(&rmtpeer, (u_short)sp->s_port, pwd->pw_name, 160114452Smarkm tuser, rmt, &errfd); 16119300Sfenner if (rmtape < 0) { 16219300Sfenner msg("login to %s as %s failed.\n", rmtpeer, tuser); 16319239Sfenner return; 16419300Sfenner } 16519317Sfenner (void)fprintf(stderr, "Connection to %s established.\n", rmtpeer); 1661558Srgrimes size = ntrec * TP_BSIZE; 1671558Srgrimes if (size > 60 * 1024) /* XXX */ 1681558Srgrimes size = 60 * 1024; 1691558Srgrimes /* Leave some space for rmt request/response protocol */ 1701558Srgrimes size += 2 * 1024; 1711558Srgrimes while (size > TP_BSIZE && 1721558Srgrimes setsockopt(rmtape, SOL_SOCKET, SO_SNDBUF, &size, sizeof (size)) < 0) 1731558Srgrimes size -= TP_BSIZE; 1741558Srgrimes (void)setsockopt(rmtape, SOL_SOCKET, SO_RCVBUF, &size, sizeof (size)); 17519239Sfenner throughput = IPTOS_THROUGHPUT; 17619239Sfenner if (setsockopt(rmtape, IPPROTO_IP, IP_TOS, 17719239Sfenner &throughput, sizeof(throughput)) < 0) 17819239Sfenner perror("IP_TOS:IPTOS_THROUGHPUT setsockopt"); 17936115Sfenner on = 1; 1801558Srgrimes if (setsockopt(rmtape, IPPROTO_TCP, TCP_NODELAY, &on, sizeof (on)) < 0) 1811558Srgrimes perror("TCP_NODELAY setsockopt"); 1821558Srgrimes} 1831558Srgrimes 1841558Srgrimesstatic int 18592837Simpokname(const char *cp0) 1861558Srgrimes{ 18792837Simp const char *cp; 18886473Siedowse int c; 1891558Srgrimes 1901558Srgrimes for (cp = cp0; *cp; cp++) { 1911558Srgrimes c = *cp; 1921558Srgrimes if (!isascii(c) || !(isalnum(c) || c == '_' || c == '-')) { 19319300Sfenner msg("invalid user name %s\n", cp0); 1941558Srgrimes return (0); 1951558Srgrimes } 1961558Srgrimes } 1971558Srgrimes return (1); 1981558Srgrimes} 1991558Srgrimes 2001558Srgrimesint 20192837Simprmtopen(const char *tape, int mode) 2021558Srgrimes{ 2031558Srgrimes char buf[256]; 2041558Srgrimes 20521409Simp (void)snprintf(buf, sizeof (buf), "O%.226s\n%d\n", tape, mode); 2061558Srgrimes rmtstate = TS_OPEN; 2071558Srgrimes return (rmtcall(tape, buf)); 2081558Srgrimes} 2091558Srgrimes 2101558Srgrimesvoid 21192837Simprmtclose(void) 2121558Srgrimes{ 2131558Srgrimes 2141558Srgrimes if (rmtstate != TS_OPEN) 2151558Srgrimes return; 2161558Srgrimes rmtcall("close", "C\n"); 2171558Srgrimes rmtstate = TS_CLOSED; 2181558Srgrimes} 2191558Srgrimes 2201558Srgrimesint 22192837Simprmtread(char *buf, int count) 2221558Srgrimes{ 2231558Srgrimes char line[30]; 2241558Srgrimes int n, i, cc; 2251558Srgrimes 22621409Simp (void)snprintf(line, sizeof (line), "R%d\n", count); 2271558Srgrimes n = rmtcall("read", line); 22839256Sgibbs if (n < 0) 22939256Sgibbs /* rmtcall() properly sets errno for us on errors. */ 23039256Sgibbs return (n); 2311558Srgrimes for (i = 0; i < n; i += cc) { 2321558Srgrimes cc = read(rmtape, buf+i, n - i); 23339256Sgibbs if (cc <= 0) 23492837Simp rmtconnaborted(0); 2351558Srgrimes } 2361558Srgrimes return (n); 2371558Srgrimes} 2381558Srgrimes 2391558Srgrimesint 24092837Simprmtwrite(const char *buf, int count) 2411558Srgrimes{ 2421558Srgrimes char line[30]; 2431558Srgrimes 24421409Simp (void)snprintf(line, sizeof (line), "W%d\n", count); 2451558Srgrimes write(rmtape, line, strlen(line)); 2461558Srgrimes write(rmtape, buf, count); 2471558Srgrimes return (rmtreply("write")); 2481558Srgrimes} 2491558Srgrimes 2501558Srgrimesvoid 25192837Simprmtwrite0(int count) 2521558Srgrimes{ 2531558Srgrimes char line[30]; 2541558Srgrimes 25521409Simp (void)snprintf(line, sizeof (line), "W%d\n", count); 2561558Srgrimes write(rmtape, line, strlen(line)); 2571558Srgrimes} 2581558Srgrimes 2591558Srgrimesvoid 26092837Simprmtwrite1(const char *buf, int count) 2611558Srgrimes{ 2621558Srgrimes 2631558Srgrimes write(rmtape, buf, count); 2641558Srgrimes} 2651558Srgrimes 2661558Srgrimesint 26792837Simprmtwrite2(void) 2681558Srgrimes{ 2691558Srgrimes 2701558Srgrimes return (rmtreply("write")); 2711558Srgrimes} 2721558Srgrimes 2731558Srgrimesint 27492837Simprmtseek(int offset, int pos) /* XXX off_t ? */ 2751558Srgrimes{ 2761558Srgrimes char line[80]; 2771558Srgrimes 27821409Simp (void)snprintf(line, sizeof (line), "L%d\n%d\n", offset, pos); 2791558Srgrimes return (rmtcall("seek", line)); 2801558Srgrimes} 2811558Srgrimes 2821558Srgrimesstruct mtget mts; 2831558Srgrimes 2841558Srgrimesstruct mtget * 28592837Simprmtstatus(void) 2861558Srgrimes{ 28786473Siedowse int i; 28886473Siedowse char *cp; 2891558Srgrimes 2901558Srgrimes if (rmtstate != TS_OPEN) 2911558Srgrimes return (NULL); 2921558Srgrimes rmtcall("status", "S\n"); 2931558Srgrimes for (i = 0, cp = (char *)&mts; i < sizeof(mts); i++) 2941558Srgrimes *cp++ = rmtgetb(); 2951558Srgrimes return (&mts); 2961558Srgrimes} 2971558Srgrimes 2981558Srgrimesint 29992837Simprmtioctl(int cmd, int count) 3001558Srgrimes{ 3011558Srgrimes char buf[256]; 3021558Srgrimes 3031558Srgrimes if (count < 0) 3041558Srgrimes return (-1); 30521409Simp (void)snprintf(buf, sizeof (buf), "I%d\n%d\n", cmd, count); 3061558Srgrimes return (rmtcall("ioctl", buf)); 3071558Srgrimes} 3081558Srgrimes 3091558Srgrimesstatic int 31092837Simprmtcall(const char *cmd, const char *buf) 3111558Srgrimes{ 3121558Srgrimes 3131558Srgrimes if (write(rmtape, buf, strlen(buf)) != strlen(buf)) 31492837Simp rmtconnaborted(0); 3151558Srgrimes return (rmtreply(cmd)); 3161558Srgrimes} 3171558Srgrimes 3181558Srgrimesstatic int 31992837Simprmtreply(const char *cmd) 3201558Srgrimes{ 32186473Siedowse char *cp; 3221558Srgrimes char code[30], emsg[BUFSIZ]; 3231558Srgrimes 3241558Srgrimes rmtgets(code, sizeof (code)); 3251558Srgrimes if (*code == 'E' || *code == 'F') { 3261558Srgrimes rmtgets(emsg, sizeof (emsg)); 3271558Srgrimes msg("%s: %s", cmd, emsg); 32839256Sgibbs errno = atoi(code + 1); 32939256Sgibbs if (*code == 'F') 3301558Srgrimes rmtstate = TS_CLOSED; 3311558Srgrimes return (-1); 3321558Srgrimes } 3331558Srgrimes if (*code != 'A') { 3341558Srgrimes /* Kill trailing newline */ 3351558Srgrimes cp = code + strlen(code); 3361558Srgrimes if (cp > code && *--cp == '\n') 3371558Srgrimes *cp = '\0'; 3381558Srgrimes 3391558Srgrimes msg("Protocol to remote tape server botched (code \"%s\").\n", 3401558Srgrimes code); 34192837Simp rmtconnaborted(0); 3421558Srgrimes } 3431558Srgrimes return (atoi(code + 1)); 3441558Srgrimes} 3451558Srgrimes 3461558Srgrimesint 34792837Simprmtgetb(void) 3481558Srgrimes{ 3491558Srgrimes char c; 3501558Srgrimes 3511558Srgrimes if (read(rmtape, &c, 1) != 1) 35292837Simp rmtconnaborted(0); 3531558Srgrimes return (c); 3541558Srgrimes} 3551558Srgrimes 3561558Srgrimes/* Get a line (guaranteed to have a trailing newline). */ 3571558Srgrimesvoid 35892837Simprmtgets(char *line, int len) 3591558Srgrimes{ 36086473Siedowse char *cp = line; 3611558Srgrimes 3621558Srgrimes while (len > 1) { 3631558Srgrimes *cp = rmtgetb(); 3641558Srgrimes if (*cp == '\n') { 3651558Srgrimes cp[1] = '\0'; 3661558Srgrimes return; 3671558Srgrimes } 3681558Srgrimes cp++; 3691558Srgrimes len--; 3701558Srgrimes } 3711558Srgrimes *cp = '\0'; 3721558Srgrimes msg("Protocol to remote tape server botched.\n"); 3731558Srgrimes msg("(rmtgets got \"%s\").\n", line); 37492837Simp rmtconnaborted(0); 3751558Srgrimes} 376