147082Smckusick /*- 247082Smckusick * Copyright (c) 1980 The Regents of the University of California. 347082Smckusick * All rights reserved. 447082Smckusick * 547082Smckusick * %sccs.include.redist.c% 622039Sdist */ 76645Ssam 822039Sdist #ifndef lint 9*59924Storek static char sccsid[] = "@(#)dumprmt.c 5.18 (Berkeley) 05/11/93"; 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> 319306Ssam #include <netdb.h> 3237946Sbostic #include <pwd.h> 3357724Smckusick #include <signal.h> 3457724Smckusick #include <stdio.h> 3546795Sbostic #ifdef __STDC__ 3646587Storek #include <stdlib.h> 3746587Storek #include <string.h> 3857724Smckusick #include <unistd.h> 3946795Sbostic #endif 4057724Smckusick 4137946Sbostic #include "pathnames.h" 4257724Smckusick #include "dump.h" 439306Ssam 446645Ssam #define TS_CLOSED 0 456645Ssam #define TS_OPEN 1 466645Ssam 476645Ssam static int rmtstate = TS_CLOSED; 4857724Smckusick static int rmtape; 4957724Smckusick static char *rmtpeer; 506645Ssam 5157724Smckusick static int okname __P((char *)); 5257724Smckusick static int rmtcall __P((char *, char *)); 5357724Smckusick static void rmtconnaborted __P((/* int, int */)); 5457724Smckusick static int rmtgetb __P((void)); 5557724Smckusick static void rmtgetconn __P((void)); 5657724Smckusick static void rmtgets __P((char *, int)); 5757724Smckusick static int rmtreply __P((char *)); 5817538Sralph 5957724Smckusick extern int ntrec; /* blocking factor on tape */ 6054044Smckusick 6146587Storek int 626645Ssam rmthost(host) 636645Ssam char *host; 646645Ssam { 656645Ssam 6657724Smckusick rmtpeer = malloc(strlen(host) + 1); 6757724Smckusick if (rmtpeer) 6857724Smckusick strcpy(rmtpeer, host); 6957724Smckusick else 7057724Smckusick rmtpeer = host; 7113032Ssam signal(SIGPIPE, rmtconnaborted); 726645Ssam rmtgetconn(); 736645Ssam if (rmtape < 0) 7417538Sralph return (0); 7517538Sralph return (1); 766645Ssam } 776645Ssam 7857724Smckusick static void 796645Ssam rmtconnaborted() 806645Ssam { 816645Ssam 8254044Smckusick (void) fprintf(stderr, "rdump: Lost connection to remote host.\n"); 8357724Smckusick exit(1); 846645Ssam } 856645Ssam 8646587Storek void 876645Ssam rmtgetconn() 886645Ssam { 8957724Smckusick register char *cp; 90*59924Storek static struct servent *sp = NULL; 91*59924Storek 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 99*59924Storek if (sp == NULL) { 1009306Ssam sp = getservbyname("shell", "tcp"); 101*59924Storek if (sp == NULL) { 10254044Smckusick (void) fprintf(stderr, 10354044Smckusick "rdump: shell/tcp: unknown service\n"); 10457724Smckusick exit(1); 1059306Ssam } 10657724Smckusick pwd = getpwuid(getuid()); 107*59924Storek if (pwd == NULL) { 10857724Smckusick (void) fprintf(stderr, "rdump: who are you?\n"); 10957724Smckusick exit(1); 11057724Smckusick } 1119306Ssam } 112*59924Storek if ((cp = index(rmtpeer, '@')) != NULL) { 11357724Smckusick tuser = rmtpeer; 11457724Smckusick *cp = '\0'; 11557724Smckusick if (!okname(tuser)) 11657724Smckusick exit(1); 11757724Smckusick rmtpeer = ++cp; 11857724Smckusick } else 11957724Smckusick tuser = pwd->pw_name; 12057724Smckusick rmtape = rcmd(&rmtpeer, (u_short)sp->s_port, pwd->pw_name, tuser, 12157724Smckusick _PATH_RMT, (int *)0); 12217538Sralph size = ntrec * TP_BSIZE; 12357724Smckusick if (size > 60 * 1024) /* XXX */ 12457724Smckusick size = 60 * 1024; 12557724Smckusick /* Leave some space for rmt request/response protocol */ 12657724Smckusick size += 2 * 1024; 12718493Smckusick while (size > TP_BSIZE && 12818493Smckusick setsockopt(rmtape, SOL_SOCKET, SO_SNDBUF, &size, sizeof (size)) < 0) 12957724Smckusick size -= TP_BSIZE; 13057724Smckusick (void)setsockopt(rmtape, SOL_SOCKET, SO_RCVBUF, &size, sizeof (size)); 13157724Smckusick maxseg = 1024; 13257724Smckusick if (setsockopt(rmtape, IPPROTO_TCP, TCP_MAXSEG, 13357724Smckusick &maxseg, sizeof (maxseg)) < 0) 13457724Smckusick perror("TCP_MAXSEG setsockopt"); 13557724Smckusick 13657724Smckusick #ifdef notdef 13757724Smckusick if (setsockopt(rmtape, IPPROTO_TCP, TCP_NODELAY, &on, sizeof (on)) < 0) 13857724Smckusick perror("TCP_NODELAY setsockopt"); 13957724Smckusick #endif 1406645Ssam } 1416645Ssam 14257724Smckusick static int 14357724Smckusick okname(cp0) 14457724Smckusick char *cp0; 14557724Smckusick { 14657724Smckusick register char *cp; 14757724Smckusick register int c; 14857724Smckusick 14957724Smckusick for (cp = cp0; *cp; cp++) { 15057724Smckusick c = *cp; 15157724Smckusick if (!isascii(c) || !(isalnum(c) || c == '_' || c == '-')) { 15257724Smckusick (void) fprintf(stderr, "rdump: invalid user name %s\n", 15357724Smckusick cp0); 15457724Smckusick return (0); 15557724Smckusick } 15657724Smckusick } 15757724Smckusick return (1); 15857724Smckusick } 15957724Smckusick 16046587Storek int 1616645Ssam rmtopen(tape, mode) 1626645Ssam char *tape; 1636645Ssam int mode; 1646645Ssam { 1656645Ssam char buf[256]; 1666645Ssam 16732455Sbostic (void)sprintf(buf, "O%s\n%d\n", tape, mode); 1686645Ssam rmtstate = TS_OPEN; 16924836Smckusick return (rmtcall(tape, buf)); 1706645Ssam } 1716645Ssam 17246587Storek void 1736645Ssam rmtclose() 1746645Ssam { 1756645Ssam 1766645Ssam if (rmtstate != TS_OPEN) 1776645Ssam return; 1786645Ssam rmtcall("close", "C\n"); 1796645Ssam rmtstate = TS_CLOSED; 1806645Ssam } 1816645Ssam 18246587Storek int 1836645Ssam rmtread(buf, count) 1846645Ssam char *buf; 1856645Ssam int count; 1866645Ssam { 1876645Ssam char line[30]; 1886645Ssam int n, i, cc; 1896884Ssam extern errno; 1906645Ssam 19132455Sbostic (void)sprintf(line, "R%d\n", count); 1926645Ssam n = rmtcall("read", line); 1936884Ssam if (n < 0) { 1946884Ssam errno = n; 1956645Ssam return (-1); 1966884Ssam } 1976645Ssam for (i = 0; i < n; i += cc) { 1986645Ssam cc = read(rmtape, buf+i, n - i); 1996884Ssam if (cc <= 0) { 2006645Ssam rmtconnaborted(); 2016884Ssam } 2026645Ssam } 2036645Ssam return (n); 2046645Ssam } 2056645Ssam 20646587Storek int 2076645Ssam rmtwrite(buf, count) 2086645Ssam char *buf; 2096645Ssam int count; 2106645Ssam { 2116645Ssam char line[30]; 2126645Ssam 21332455Sbostic (void)sprintf(line, "W%d\n", count); 2146645Ssam write(rmtape, line, strlen(line)); 2156645Ssam write(rmtape, buf, count); 2166645Ssam return (rmtreply("write")); 2176645Ssam } 2186645Ssam 21946587Storek void 2206645Ssam rmtwrite0(count) 2216645Ssam int count; 2226645Ssam { 2236645Ssam char line[30]; 2246645Ssam 22532455Sbostic (void)sprintf(line, "W%d\n", count); 2266645Ssam write(rmtape, line, strlen(line)); 2276645Ssam } 2286645Ssam 22946587Storek void 2306645Ssam rmtwrite1(buf, count) 2316645Ssam char *buf; 2326645Ssam int count; 2336645Ssam { 2346645Ssam 2356645Ssam write(rmtape, buf, count); 2366645Ssam } 2376645Ssam 23846587Storek int 2396645Ssam rmtwrite2() 2406645Ssam { 2416645Ssam 2426645Ssam return (rmtreply("write")); 2436645Ssam } 2446645Ssam 24546587Storek int 2466645Ssam rmtseek(offset, pos) 2476645Ssam int offset, pos; 2486645Ssam { 2496645Ssam char line[80]; 2506645Ssam 25132455Sbostic (void)sprintf(line, "L%d\n%d\n", offset, pos); 2526645Ssam return (rmtcall("seek", line)); 2536645Ssam } 2546645Ssam 2556645Ssam struct mtget mts; 2566645Ssam 2576645Ssam struct mtget * 2586645Ssam rmtstatus() 2596645Ssam { 2606645Ssam register int i; 2616645Ssam register char *cp; 2626645Ssam 2636645Ssam if (rmtstate != TS_OPEN) 264*59924Storek return (NULL); 2656645Ssam rmtcall("status", "S\n"); 2666645Ssam for (i = 0, cp = (char *)&mts; i < sizeof(mts); i++) 2676645Ssam *cp++ = rmtgetb(); 2686645Ssam return (&mts); 2696645Ssam } 2706645Ssam 27157727Smckusick int 27257727Smckusick rmtioctl(cmd, count) 27357727Smckusick int cmd, count; 27457727Smckusick { 27557727Smckusick char buf[256]; 27657727Smckusick 27757727Smckusick if (count < 0) 27857727Smckusick return (-1); 27957727Smckusick (void)sprintf(buf, "I%d\n%d\n", cmd, count); 28057727Smckusick return (rmtcall("ioctl", buf)); 28157727Smckusick } 28257727Smckusick 28357724Smckusick static int 2846645Ssam rmtcall(cmd, buf) 2856645Ssam char *cmd, *buf; 2866645Ssam { 2876645Ssam 2886645Ssam if (write(rmtape, buf, strlen(buf)) != strlen(buf)) 2896645Ssam rmtconnaborted(); 2906645Ssam return (rmtreply(cmd)); 2916645Ssam } 2926645Ssam 29357724Smckusick static int 2946645Ssam rmtreply(cmd) 2956645Ssam char *cmd; 2966645Ssam { 297*59924Storek register char *cp; 2986645Ssam char code[30], emsg[BUFSIZ]; 2996645Ssam 3006645Ssam rmtgets(code, sizeof (code)); 3016645Ssam if (*code == 'E' || *code == 'F') { 3026645Ssam rmtgets(emsg, sizeof (emsg)); 303*59924Storek msg("%s: %s", cmd, emsg); 3046645Ssam if (*code == 'F') { 3056645Ssam rmtstate = TS_CLOSED; 3066645Ssam return (-1); 3076645Ssam } 3086645Ssam return (-1); 3096645Ssam } 3106645Ssam if (*code != 'A') { 311*59924Storek /* Kill trailing newline */ 312*59924Storek cp = code + strlen(code); 313*59924Storek if (cp > code && *--cp == '\n') 314*59924Storek *cp = '\0'; 315*59924Storek 316*59924Storek msg("Protocol to remote tape server botched (code \"%s\").\n", 3176645Ssam code); 3186645Ssam rmtconnaborted(); 3196645Ssam } 3206645Ssam return (atoi(code + 1)); 3216645Ssam } 3226645Ssam 32346587Storek int 3246645Ssam rmtgetb() 3256645Ssam { 3266645Ssam char c; 3276645Ssam 3286645Ssam if (read(rmtape, &c, 1) != 1) 3296645Ssam rmtconnaborted(); 3306645Ssam return (c); 3316645Ssam } 3326645Ssam 333*59924Storek /* Get a line (guaranteed to have a trailing newline). */ 33446587Storek void 33557724Smckusick rmtgets(line, len) 33657724Smckusick char *line; 3376645Ssam int len; 3386645Ssam { 33957724Smckusick register char *cp = line; 3406645Ssam 3416645Ssam while (len > 1) { 3426645Ssam *cp = rmtgetb(); 3436645Ssam if (*cp == '\n') { 344*59924Storek cp[1] = '\0'; 3456645Ssam return; 3466645Ssam } 3476645Ssam cp++; 3486645Ssam len--; 3496645Ssam } 350*59924Storek *cp = '\0'; 35157724Smckusick msg("Protocol to remote tape server botched.\n"); 35257724Smckusick msg("(rmtgets got \"%s\").\n", line); 3536645Ssam rmtconnaborted(); 3546645Ssam } 355