1 /* $OpenBSD: mtrmt.c,v 1.25 2023/03/08 04:43:04 guenther Exp $ */ 2 /* $NetBSD: mtrmt.c,v 1.2 1996/03/06 06:22:07 scottr 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 #include <sys/types.h> 34 #include <sys/mtio.h> 35 #include <sys/ioctl.h> 36 #include <sys/socket.h> 37 #include <sys/time.h> 38 #include <ufs/ufs/dinode.h> 39 40 #include <netinet/in.h> 41 #include <netinet/tcp.h> 42 43 #include <protocols/dumprestore.h> 44 45 #include <ctype.h> 46 #include <err.h> 47 #include <netdb.h> 48 #include <pwd.h> 49 #include <signal.h> 50 #include <stdio.h> 51 #include <stdlib.h> 52 #include <string.h> 53 #include <unistd.h> 54 #include <limits.h> 55 56 #include "pathnames.h" 57 #include "mt.h" 58 59 #define TS_CLOSED 0 60 #define TS_OPEN 1 61 62 static int rmtstate = TS_CLOSED; 63 static int rmtape; 64 static char *rmtpeer; 65 66 static int okname(char *); 67 static int rmtcall(char *, char *); 68 static void rmtconnaborted(void); 69 static void sigrmtconnaborted(int); 70 static int rmtgetb(void); 71 static void rmtgetconn(void); 72 static void rmtgets(char *, int); 73 static int rmtreply(char *); 74 75 int 76 rmthost(char *host) 77 { 78 if ((rmtpeer = strdup(host)) == NULL) 79 err(1, "strdup"); 80 signal(SIGPIPE, sigrmtconnaborted); 81 rmtgetconn(); 82 if (rmtape < 0) 83 return (0); 84 return (1); 85 } 86 87 static void 88 sigrmtconnaborted(int signo) 89 { 90 91 warnx("Lost connection to remote host."); 92 _exit(1); 93 } 94 95 static void 96 rmtconnaborted(void) 97 { 98 99 errx(1, "Lost connection to remote host."); 100 } 101 102 void 103 rmtgetconn(void) 104 { 105 char *cp; 106 static struct passwd *pwd = NULL; 107 #ifdef notdef 108 static int on = 1; 109 #endif 110 char *tuser; 111 int size; 112 int maxseg; 113 114 if ((cp = strchr(rmtpeer, '@')) != NULL) { 115 tuser = rmtpeer; 116 *cp = '\0'; 117 if (!okname(tuser)) 118 exit(1); 119 rmtpeer = ++cp; 120 } else 121 tuser = pwd->pw_name; 122 123 rmtape = rcmdsh(&rmtpeer, -1, pwd->pw_name, tuser, 124 _PATH_RMT, NULL); 125 if (rmtape == -1) 126 exit(1); /* rcmd already printed error message */ 127 128 size = TP_BSIZE; 129 if (size > 60 * 1024) /* XXX */ 130 size = 60 * 1024; 131 /* Leave some space for rmt request/response protocol */ 132 size += 2 * 1024; 133 134 while (size > TP_BSIZE && 135 setsockopt(rmtape, SOL_SOCKET, SO_SNDBUF, &size, sizeof (size)) == -1) 136 size -= TP_BSIZE; 137 (void)setsockopt(rmtape, SOL_SOCKET, SO_RCVBUF, &size, sizeof (size)); 138 139 maxseg = 1024; 140 (void)setsockopt(rmtape, IPPROTO_TCP, TCP_MAXSEG, &maxseg, 141 sizeof (maxseg)); 142 143 #ifdef notdef 144 if (setsockopt(rmtape, IPPROTO_TCP, TCP_NODELAY, &on, sizeof (on)) == -1) 145 perror("TCP_NODELAY setsockopt"); 146 #endif 147 if (pledge("stdio", NULL) == -1) 148 err(1, "pledge"); 149 } 150 151 static int 152 okname(char *cp0) 153 { 154 unsigned char *cp; 155 int c; 156 157 for (cp = cp0; *cp; cp++) { 158 c = (unsigned char)*cp; 159 if (!isascii(c) || !(isalnum(c) || c == '_' || c == '-')) { 160 warnx("invalid user name: %s", cp0); 161 return (0); 162 } 163 } 164 return (1); 165 } 166 167 int 168 rmtopen(char *tape, int mode) 169 { 170 char buf[1 + PATH_MAX+1 + 10+1 +1]; 171 int r; 172 173 r = snprintf(buf, sizeof (buf), "O%s\n%d\n", tape, mode); 174 if (r < 0 || r >= sizeof buf) 175 errx(1, "tape name too long"); 176 rmtstate = TS_OPEN; 177 return (rmtcall(tape, buf)); 178 } 179 180 void 181 rmtclose(void) 182 { 183 184 if (rmtstate != TS_OPEN) 185 return; 186 rmtcall("close", "C\n"); 187 rmtstate = TS_CLOSED; 188 } 189 190 struct mtget mts; 191 192 struct mtget * 193 rmtstatus(void) 194 { 195 int i; 196 char *cp; 197 198 if (rmtstate != TS_OPEN) 199 return (NULL); 200 rmtcall("status", "S\n"); 201 for (i = 0, cp = (char *)&mts; i < sizeof(mts); i++) 202 *cp++ = rmtgetb(); 203 return (&mts); 204 } 205 206 int 207 rmtioctl(int cmd, int count) 208 { 209 char buf[1 + 10+1 + 10+1 +1]; 210 int r; 211 212 if (count < 0) 213 return (-1); 214 r = snprintf(buf, sizeof (buf), "I%d\n%d\n", cmd, count); 215 if (r < 0 || r >= sizeof buf) 216 errx(1, "string error during ioctl"); 217 return (rmtcall("ioctl", buf)); 218 } 219 220 static int 221 rmtcall(char *cmd, char *buf) 222 { 223 224 if (write(rmtape, buf, strlen(buf)) != strlen(buf)) 225 rmtconnaborted(); 226 return (rmtreply(cmd)); 227 } 228 229 static int 230 rmtreply(char *cmd) 231 { 232 char *cp; 233 char code[30], emsg[BUFSIZ]; 234 235 rmtgets(code, sizeof (code)); 236 if (*code == 'E' || *code == 'F') { 237 rmtgets(emsg, sizeof (emsg)); 238 warnx("%s: %s", cmd, emsg); 239 if (*code == 'F') { 240 rmtstate = TS_CLOSED; 241 return (-1); 242 } 243 return (-1); 244 } 245 if (*code != 'A') { 246 /* Kill trailing newline */ 247 cp = code + strlen(code); 248 if (cp > code && *--cp == '\n') 249 *cp = '\0'; 250 251 warnx("Protocol to remote tape server botched (code \"%s\").", 252 code); 253 rmtconnaborted(); 254 } 255 return (atoi(code + 1)); 256 } 257 258 int 259 rmtgetb(void) 260 { 261 char c; 262 263 if (read(rmtape, &c, 1) != 1) 264 rmtconnaborted(); 265 return (c); 266 } 267 268 /* Get a line (guaranteed to have a trailing newline). */ 269 void 270 rmtgets(char *line, int len) 271 { 272 char *cp = line; 273 274 while (len > 1) { 275 *cp = rmtgetb(); 276 if (*cp == '\n') { 277 cp[1] = '\0'; 278 return; 279 } 280 cp++; 281 len--; 282 } 283 *cp = '\0'; 284 warnx("Protocol to remote tape server botched."); 285 warnx("(rmtgets got \"%s\").", line); 286 rmtconnaborted(); 287 } 288