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