1 /* $OpenBSD: dumprmt.c,v 1.25 2008/01/02 12:59:35 chl Exp $ */ 2 /* $NetBSD: dumprmt.c,v 1.17 1997/06/05 16:10:47 mrg Exp $ */ 3 4 /*- 5 * Copyright (c) 1980, 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. Neither the name of the University nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33 #ifndef lint 34 #if 0 35 static char sccsid[] = "@(#)dumprmt.c 8.1 (Berkeley) 6/5/93"; 36 #else 37 static const char rcsid[] = "$OpenBSD: dumprmt.c,v 1.25 2008/01/02 12:59:35 chl Exp $"; 38 #endif 39 #endif /* not lint */ 40 41 #include <sys/param.h> 42 #include <sys/mtio.h> 43 #include <sys/ioctl.h> 44 #include <sys/socket.h> 45 #include <sys/time.h> 46 #include <ufs/ufs/dinode.h> 47 48 #include <netinet/in.h> 49 #include <netinet/tcp.h> 50 51 #include <protocols/dumprestore.h> 52 53 #include <ctype.h> 54 #include <err.h> 55 #include <netdb.h> 56 #include <errno.h> 57 #include <pwd.h> 58 #include <signal.h> 59 #include <stdio.h> 60 #include <stdlib.h> 61 #include <string.h> 62 #include <unistd.h> 63 64 #include "pathnames.h" 65 #include "dump.h" 66 67 #define TS_CLOSED 0 68 #define TS_OPEN 1 69 70 static int rmtstate = TS_CLOSED; 71 static int rmtape; 72 static char *rmtpeer; 73 74 static int okname(char *); 75 static int rmtcall(char *, char *); 76 static void rmtconnaborted(int); 77 static int rmtgetb(void); 78 static void rmtgetconn(void); 79 static void rmtgets(char *, int); 80 static int rmtreply(char *); 81 82 extern int ntrec; /* blocking factor on tape */ 83 84 int 85 rmthost(char *host) 86 { 87 int len = strlen(host) + 1; 88 89 rmtpeer = malloc(len); 90 if (rmtpeer) 91 strlcpy(rmtpeer, host, len); 92 else 93 rmtpeer = host; 94 signal(SIGPIPE, rmtconnaborted); 95 rmtgetconn(); 96 if (rmtape < 0) 97 return (0); 98 return (1); 99 } 100 101 /* ARGSUSED */ 102 static void 103 rmtconnaborted(int signo) 104 { 105 /* XXX signal race */ 106 errx(X_ABORT, "Lost connection to remote host."); 107 } 108 109 void 110 rmtgetconn(void) 111 { 112 char *cp; 113 static struct servent *sp = NULL; 114 static struct passwd *pwd = NULL; 115 static int on = 1; 116 char *tuser, *name; 117 int size; 118 int maxseg; 119 120 if (sp == NULL) { 121 sp = getservbyname("shell", "tcp"); 122 if (sp == NULL) 123 errx(X_STARTUP, "shell/tcp: unknown service"); 124 pwd = getpwuid(getuid()); 125 if (pwd == NULL) 126 errx(X_STARTUP, "who are you?"); 127 } 128 if ((name = strdup(pwd->pw_name)) == NULL) 129 err(X_STARTUP, "malloc"); 130 if ((cp = strchr(rmtpeer, '@')) != NULL) { 131 tuser = rmtpeer; 132 *cp = '\0'; 133 if (!okname(tuser)) 134 exit(X_STARTUP); 135 rmtpeer = ++cp; 136 } else 137 tuser = name; 138 139 rmtape = rcmd(&rmtpeer, sp->s_port, name, tuser, _PATH_RMT, NULL); 140 (void)free(name); 141 if (rmtape < 0) 142 return; 143 144 size = ntrec * TP_BSIZE; 145 if (size > 60 * 1024) /* XXX */ 146 size = 60 * 1024; 147 /* Leave some space for rmt request/response protocol */ 148 size += 2 * 1024; 149 while (size > TP_BSIZE && 150 setsockopt(rmtape, SOL_SOCKET, SO_SNDBUF, &size, sizeof(size)) < 0) 151 size -= TP_BSIZE; 152 (void)setsockopt(rmtape, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size)); 153 154 maxseg = 1024; 155 (void)setsockopt(rmtape, IPPROTO_TCP, TCP_MAXSEG, &maxseg, 156 sizeof(maxseg)); 157 158 (void) setsockopt(rmtape, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)); 159 } 160 161 static int 162 okname(char *cp0) 163 { 164 char *cp; 165 int c; 166 167 for (cp = cp0; *cp; cp++) { 168 c = *cp; 169 if (!isascii(c) || !(isalnum(c) || c == '_' || c == '-')) { 170 warnx("invalid user name: %s", cp0); 171 return (0); 172 } 173 } 174 return (1); 175 } 176 177 int 178 rmtopen(char *tape, int mode) 179 { 180 char buf[256]; 181 182 (void)snprintf(buf, sizeof(buf), "O%s\n%d\n", tape, mode); 183 rmtstate = TS_OPEN; 184 return (rmtcall(tape, buf)); 185 } 186 187 void 188 rmtclose(void) 189 { 190 191 if (rmtstate != TS_OPEN) 192 return; 193 rmtcall("close", "C\n"); 194 rmtstate = TS_CLOSED; 195 } 196 197 int 198 rmtread(char *buf, int count) 199 { 200 char line[30]; 201 int n, i, cc; 202 203 (void)snprintf(line, sizeof(line), "R%d\n", count); 204 n = rmtcall("read", line); 205 if (n < 0) { 206 errno = n; 207 return (-1); 208 } 209 for (i = 0; i < n; i += cc) { 210 cc = read(rmtape, buf+i, n - i); 211 if (cc <= 0) { 212 rmtconnaborted(0); 213 } 214 } 215 return (n); 216 } 217 218 int 219 rmtwrite(char *buf, int count) 220 { 221 char line[30]; 222 223 (void)snprintf(line, sizeof(line), "W%d\n", count); 224 write(rmtape, line, strlen(line)); 225 write(rmtape, buf, count); 226 return (rmtreply("write")); 227 } 228 229 int 230 rmtseek(int offset, int pos) 231 { 232 char line[80]; 233 234 (void)snprintf(line, sizeof(line), "L%d\n%d\n", offset, pos); 235 return (rmtcall("seek", line)); 236 } 237 238 int 239 rmtioctl(int cmd, int count) 240 { 241 char buf[256]; 242 243 if (count < 0) 244 return (-1); 245 (void)snprintf(buf, sizeof(buf), "I%d\n%d\n", cmd, count); 246 return (rmtcall("ioctl", buf)); 247 } 248 249 static int 250 rmtcall(char *cmd, char *buf) 251 { 252 253 if (write(rmtape, buf, strlen(buf)) != strlen(buf)) 254 rmtconnaborted(0); 255 return (rmtreply(cmd)); 256 } 257 258 static int 259 rmtreply(char *cmd) 260 { 261 char *cp; 262 char code[30], emsg[BUFSIZ]; 263 264 rmtgets(code, sizeof(code)); 265 if (*code == 'E' || *code == 'F') { 266 rmtgets(emsg, sizeof(emsg)); 267 msg("%s: %s", cmd, emsg); 268 errno = atoi(&code[1]); 269 if (*code == 'F') 270 rmtstate = TS_CLOSED; 271 return (-1); 272 } 273 if (*code != 'A') { 274 /* Kill trailing newline */ 275 cp = code + strlen(code); 276 if (cp > code && *--cp == '\n') 277 *cp = '\0'; 278 279 msg("Protocol to remote tape server botched (code \"%s\").\n", 280 code); 281 rmtconnaborted(0); 282 } 283 return (atoi(code + 1)); 284 } 285 286 int 287 rmtgetb(void) 288 { 289 char c; 290 291 if (read(rmtape, &c, 1) != 1) 292 rmtconnaborted(0); 293 return (c); 294 } 295 296 /* Get a line (guaranteed to have a trailing newline). */ 297 void 298 rmtgets(char *line, int len) 299 { 300 char *cp = line; 301 302 while (len > 1) { 303 *cp = rmtgetb(); 304 if (*cp == '\n') { 305 cp[1] = '\0'; 306 return; 307 } 308 cp++; 309 len--; 310 } 311 *cp = '\0'; 312 msg("Protocol to remote tape server botched.\n"); 313 msg("(rmtgets got \"%s\").\n", line); 314 rmtconnaborted(0); 315 } 316