1*7c478bd9Sstevel@tonic-gate /*LINTLIBRARY*/ 2*7c478bd9Sstevel@tonic-gate /*PROTOLIB1*/ 3*7c478bd9Sstevel@tonic-gate /* 4*7c478bd9Sstevel@tonic-gate * Copyright 1998, 2002-2003 Sun Microsystems, Inc. All rights reserved. 5*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 6*7c478bd9Sstevel@tonic-gate */ 7*7c478bd9Sstevel@tonic-gate /* 8*7c478bd9Sstevel@tonic-gate * Copyright (c) 1980 Regents of the University of California. 9*7c478bd9Sstevel@tonic-gate * All rights reserved. The Berkeley software License Agreement 10*7c478bd9Sstevel@tonic-gate * specifies the terms and conditions for redistribution. 11*7c478bd9Sstevel@tonic-gate */ 12*7c478bd9Sstevel@tonic-gate 13*7c478bd9Sstevel@tonic-gate /* line below is from UCB 5.4 12/11/85 */ 14*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 15*7c478bd9Sstevel@tonic-gate 16*7c478bd9Sstevel@tonic-gate #include <myrcmd.h> 17*7c478bd9Sstevel@tonic-gate #include <stdio.h> 18*7c478bd9Sstevel@tonic-gate #include <locale.h> 19*7c478bd9Sstevel@tonic-gate #include <ctype.h> 20*7c478bd9Sstevel@tonic-gate #include <pwd.h> 21*7c478bd9Sstevel@tonic-gate #include <string.h> 22*7c478bd9Sstevel@tonic-gate #include <signal.h> 23*7c478bd9Sstevel@tonic-gate #include <sys/mtio.h> 24*7c478bd9Sstevel@tonic-gate #include <sys/socket.h> 25*7c478bd9Sstevel@tonic-gate #include <unistd.h> 26*7c478bd9Sstevel@tonic-gate #include <netdb.h> 27*7c478bd9Sstevel@tonic-gate #include <locale.h> 28*7c478bd9Sstevel@tonic-gate #include <stdlib.h> 29*7c478bd9Sstevel@tonic-gate #include <errno.h> 30*7c478bd9Sstevel@tonic-gate #include <rmt.h> 31*7c478bd9Sstevel@tonic-gate #include <libintl.h> 32*7c478bd9Sstevel@tonic-gate 33*7c478bd9Sstevel@tonic-gate #define sigvec sigaction 34*7c478bd9Sstevel@tonic-gate #define sv_handler sa_handler 35*7c478bd9Sstevel@tonic-gate 36*7c478bd9Sstevel@tonic-gate #include <netinet/in.h> 37*7c478bd9Sstevel@tonic-gate 38*7c478bd9Sstevel@tonic-gate extern int32_t tp_bsize; 39*7c478bd9Sstevel@tonic-gate 40*7c478bd9Sstevel@tonic-gate #define TS_CLOSED 0 41*7c478bd9Sstevel@tonic-gate #define TS_OPEN 1 42*7c478bd9Sstevel@tonic-gate 43*7c478bd9Sstevel@tonic-gate static int rmtstate = TS_CLOSED; 44*7c478bd9Sstevel@tonic-gate static int rmtape = -1; 45*7c478bd9Sstevel@tonic-gate static int rmtversion = 0; 46*7c478bd9Sstevel@tonic-gate static char *rmtpeer, *rmtpeer_malloc; 47*7c478bd9Sstevel@tonic-gate static uint_t ntrec; /* blocking factor on tape */ 48*7c478bd9Sstevel@tonic-gate 49*7c478bd9Sstevel@tonic-gate static char *domainname = "hsm_libdump"; /* for dgettext() */ 50*7c478bd9Sstevel@tonic-gate 51*7c478bd9Sstevel@tonic-gate #ifdef __STDC__ 52*7c478bd9Sstevel@tonic-gate static void rmtmsg(const char *, ...); /* package print routine */ 53*7c478bd9Sstevel@tonic-gate static void rmtconnaborted(int); 54*7c478bd9Sstevel@tonic-gate static void rmtgetconn(void); 55*7c478bd9Sstevel@tonic-gate static int rmtstatus_extended(struct mtget *); 56*7c478bd9Sstevel@tonic-gate static int rmtioctl_extended(int, long); 57*7c478bd9Sstevel@tonic-gate static int map_extended_ioctl(int); 58*7c478bd9Sstevel@tonic-gate static int okname(char *); 59*7c478bd9Sstevel@tonic-gate static int rmtcall(char *, char *); 60*7c478bd9Sstevel@tonic-gate static int rmtreply(char *); 61*7c478bd9Sstevel@tonic-gate static int rmtpush(char *, uint_t); 62*7c478bd9Sstevel@tonic-gate static void rmtgets(char *, int); 63*7c478bd9Sstevel@tonic-gate 64*7c478bd9Sstevel@tonic-gate static void (*print)(const char *, ...); /* print routine */ 65*7c478bd9Sstevel@tonic-gate static void (*Exit)(int); /* exit routine */ 66*7c478bd9Sstevel@tonic-gate #else 67*7c478bd9Sstevel@tonic-gate static void rmtmsg(); 68*7c478bd9Sstevel@tonic-gate static void rmtconnaborted(); 69*7c478bd9Sstevel@tonic-gate static void rmtgetconn(); 70*7c478bd9Sstevel@tonic-gate static int okname(); 71*7c478bd9Sstevel@tonic-gate static int rmtstatus_extended(); 72*7c478bd9Sstevel@tonic-gate static int rmtioctl_extended(); 73*7c478bd9Sstevel@tonic-gate static int map_extended_ioctl(); 74*7c478bd9Sstevel@tonic-gate static int rmtcall(); 75*7c478bd9Sstevel@tonic-gate static int rmtreply(); 76*7c478bd9Sstevel@tonic-gate static int rmtpush(); 77*7c478bd9Sstevel@tonic-gate static void rmtgets(); 78*7c478bd9Sstevel@tonic-gate 79*7c478bd9Sstevel@tonic-gate static void (*print)(); 80*7c478bd9Sstevel@tonic-gate static void (*Exit)(); 81*7c478bd9Sstevel@tonic-gate #endif 82*7c478bd9Sstevel@tonic-gate 83*7c478bd9Sstevel@tonic-gate /* 84*7c478bd9Sstevel@tonic-gate * Get a program-specific print and exit routine into 85*7c478bd9Sstevel@tonic-gate * the package. This is primarily for dump's benefit. 86*7c478bd9Sstevel@tonic-gate * This routine is optional -- if not called the two 87*7c478bd9Sstevel@tonic-gate * default to fprintf(stderr) and exit. 88*7c478bd9Sstevel@tonic-gate */ 89*7c478bd9Sstevel@tonic-gate #ifdef __STDC__ 90*7c478bd9Sstevel@tonic-gate void 91*7c478bd9Sstevel@tonic-gate rmtinit( 92*7c478bd9Sstevel@tonic-gate void (*errmsg)(const char *, ...), /* print routine */ 93*7c478bd9Sstevel@tonic-gate void (*errexit)(int)) /* exit routine */ 94*7c478bd9Sstevel@tonic-gate #else 95*7c478bd9Sstevel@tonic-gate void 96*7c478bd9Sstevel@tonic-gate rmtinit(errmsg, errexit) 97*7c478bd9Sstevel@tonic-gate void (*errmsg)(); /* print routine */ 98*7c478bd9Sstevel@tonic-gate void (*errexit)(); /* exit routine */ 99*7c478bd9Sstevel@tonic-gate #endif 100*7c478bd9Sstevel@tonic-gate { 101*7c478bd9Sstevel@tonic-gate print = errmsg; 102*7c478bd9Sstevel@tonic-gate Exit = errexit; 103*7c478bd9Sstevel@tonic-gate } 104*7c478bd9Sstevel@tonic-gate 105*7c478bd9Sstevel@tonic-gate rmthost(host, blocksize) 106*7c478bd9Sstevel@tonic-gate char *host; 107*7c478bd9Sstevel@tonic-gate uint_t blocksize; /* in Kbytes per tape block */ 108*7c478bd9Sstevel@tonic-gate { 109*7c478bd9Sstevel@tonic-gate struct sigvec sv; 110*7c478bd9Sstevel@tonic-gate 111*7c478bd9Sstevel@tonic-gate #ifdef __STDC__ 112*7c478bd9Sstevel@tonic-gate if (print == (void (*)(const char *, ...))0) 113*7c478bd9Sstevel@tonic-gate #else 114*7c478bd9Sstevel@tonic-gate if (print == (void (*)())0) 115*7c478bd9Sstevel@tonic-gate #endif 116*7c478bd9Sstevel@tonic-gate print = rmtmsg; 117*7c478bd9Sstevel@tonic-gate #ifdef __STDC__ 118*7c478bd9Sstevel@tonic-gate if (Exit == (void (*)(int))0) 119*7c478bd9Sstevel@tonic-gate #else 120*7c478bd9Sstevel@tonic-gate if (Exit == (void (*)())0) 121*7c478bd9Sstevel@tonic-gate #endif 122*7c478bd9Sstevel@tonic-gate Exit = exit; 123*7c478bd9Sstevel@tonic-gate if (rmtape >= 0 && rmtstate != TS_OPEN) { 124*7c478bd9Sstevel@tonic-gate (void) close(rmtape); 125*7c478bd9Sstevel@tonic-gate rmtape = -1; 126*7c478bd9Sstevel@tonic-gate } 127*7c478bd9Sstevel@tonic-gate if (rmtpeer_malloc) 128*7c478bd9Sstevel@tonic-gate (void) free(rmtpeer_malloc); 129*7c478bd9Sstevel@tonic-gate rmtpeer = rmtpeer_malloc = strdup(host); 130*7c478bd9Sstevel@tonic-gate if (rmtpeer == (char *)0) 131*7c478bd9Sstevel@tonic-gate return (0); 132*7c478bd9Sstevel@tonic-gate ntrec = blocksize; 133*7c478bd9Sstevel@tonic-gate sv.sa_flags = SA_RESTART; 134*7c478bd9Sstevel@tonic-gate (void) sigemptyset(&sv.sa_mask); 135*7c478bd9Sstevel@tonic-gate sv.sv_handler = rmtconnaborted; 136*7c478bd9Sstevel@tonic-gate (void) sigvec(SIGPIPE, &sv, (struct sigvec *)0); 137*7c478bd9Sstevel@tonic-gate rmtgetconn(); 138*7c478bd9Sstevel@tonic-gate if (rmtape < 0) 139*7c478bd9Sstevel@tonic-gate return (0); 140*7c478bd9Sstevel@tonic-gate return (1); 141*7c478bd9Sstevel@tonic-gate } 142*7c478bd9Sstevel@tonic-gate 143*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 144*7c478bd9Sstevel@tonic-gate static void 145*7c478bd9Sstevel@tonic-gate rmtconnaborted(sig) 146*7c478bd9Sstevel@tonic-gate int sig; 147*7c478bd9Sstevel@tonic-gate { 148*7c478bd9Sstevel@tonic-gate print(dgettext(domainname, "Lost connection to remote host.\n")); 149*7c478bd9Sstevel@tonic-gate Exit(1); 150*7c478bd9Sstevel@tonic-gate } 151*7c478bd9Sstevel@tonic-gate 152*7c478bd9Sstevel@tonic-gate static void 153*7c478bd9Sstevel@tonic-gate #ifdef __STDC__ 154*7c478bd9Sstevel@tonic-gate rmtgetconn(void) 155*7c478bd9Sstevel@tonic-gate #else 156*7c478bd9Sstevel@tonic-gate rmtgetconn() 157*7c478bd9Sstevel@tonic-gate #endif 158*7c478bd9Sstevel@tonic-gate { 159*7c478bd9Sstevel@tonic-gate static struct servent *sp = 0; 160*7c478bd9Sstevel@tonic-gate static struct passwd *pwd = 0; 161*7c478bd9Sstevel@tonic-gate char *tuser, *host, *device; 162*7c478bd9Sstevel@tonic-gate uint_t size; 163*7c478bd9Sstevel@tonic-gate 164*7c478bd9Sstevel@tonic-gate if (sp == 0) { 165*7c478bd9Sstevel@tonic-gate sp = getservbyname("shell", "tcp"); 166*7c478bd9Sstevel@tonic-gate if (sp == 0) { 167*7c478bd9Sstevel@tonic-gate print(dgettext(domainname, 168*7c478bd9Sstevel@tonic-gate "shell/tcp: unknown service\n")); 169*7c478bd9Sstevel@tonic-gate Exit(1); 170*7c478bd9Sstevel@tonic-gate } 171*7c478bd9Sstevel@tonic-gate pwd = getpwuid(getuid()); 172*7c478bd9Sstevel@tonic-gate if (pwd == 0) { 173*7c478bd9Sstevel@tonic-gate print(dgettext(domainname, 174*7c478bd9Sstevel@tonic-gate "Cannot find password entry for uid %d\n"), 175*7c478bd9Sstevel@tonic-gate getuid()); 176*7c478bd9Sstevel@tonic-gate Exit(1); 177*7c478bd9Sstevel@tonic-gate } 178*7c478bd9Sstevel@tonic-gate } 179*7c478bd9Sstevel@tonic-gate /* Was strrchr(), be consistent with dump */ 180*7c478bd9Sstevel@tonic-gate host = strchr(rmtpeer, '@'); 181*7c478bd9Sstevel@tonic-gate if (host) { 182*7c478bd9Sstevel@tonic-gate tuser = rmtpeer; 183*7c478bd9Sstevel@tonic-gate *host++ = 0; 184*7c478bd9Sstevel@tonic-gate rmtpeer = host; 185*7c478bd9Sstevel@tonic-gate if (!okname(tuser)) 186*7c478bd9Sstevel@tonic-gate Exit(1); 187*7c478bd9Sstevel@tonic-gate } else { 188*7c478bd9Sstevel@tonic-gate host = rmtpeer; 189*7c478bd9Sstevel@tonic-gate tuser = pwd->pw_name; 190*7c478bd9Sstevel@tonic-gate } 191*7c478bd9Sstevel@tonic-gate /* Was strrchr() - be consistent with dump and restore */ 192*7c478bd9Sstevel@tonic-gate device = strchr(host, ':'); 193*7c478bd9Sstevel@tonic-gate if (device) 194*7c478bd9Sstevel@tonic-gate *device = 0; /* throw away device name */ 195*7c478bd9Sstevel@tonic-gate /* 196*7c478bd9Sstevel@tonic-gate * myrcmd() replaces the contents of rmtpeer with a pointer 197*7c478bd9Sstevel@tonic-gate * to a static copy of the canonical host name. However, 198*7c478bd9Sstevel@tonic-gate * since we never refer to rmtpeer again (other than to 199*7c478bd9Sstevel@tonic-gate * overwrite it in the next rmthost() invocation), we don't 200*7c478bd9Sstevel@tonic-gate * really care. 201*7c478bd9Sstevel@tonic-gate */ 202*7c478bd9Sstevel@tonic-gate /* LINTED sp->s_port is an int, even though port numbers are 1..65535 */ 203*7c478bd9Sstevel@tonic-gate rmtape = myrcmd(&rmtpeer, (ushort_t)sp->s_port, pwd->pw_name, 204*7c478bd9Sstevel@tonic-gate tuser, "/etc/rmt"); 205*7c478bd9Sstevel@tonic-gate if (rmtape < 0) { 206*7c478bd9Sstevel@tonic-gate if (*myrcmd_stderr) 207*7c478bd9Sstevel@tonic-gate print("%s", myrcmd_stderr); 208*7c478bd9Sstevel@tonic-gate } else { 209*7c478bd9Sstevel@tonic-gate size = ntrec * tp_bsize; 210*7c478bd9Sstevel@tonic-gate while (size > tp_bsize && 211*7c478bd9Sstevel@tonic-gate setsockopt(rmtape, SOL_SOCKET, SO_SNDBUF, (char *)&size, 212*7c478bd9Sstevel@tonic-gate sizeof (size)) < 0) 213*7c478bd9Sstevel@tonic-gate size -= tp_bsize; 214*7c478bd9Sstevel@tonic-gate } 215*7c478bd9Sstevel@tonic-gate } 216*7c478bd9Sstevel@tonic-gate 217*7c478bd9Sstevel@tonic-gate static int 218*7c478bd9Sstevel@tonic-gate okname(cp0) 219*7c478bd9Sstevel@tonic-gate char *cp0; 220*7c478bd9Sstevel@tonic-gate { 221*7c478bd9Sstevel@tonic-gate char *cp; 222*7c478bd9Sstevel@tonic-gate uchar_t c; 223*7c478bd9Sstevel@tonic-gate 224*7c478bd9Sstevel@tonic-gate for (cp = cp0; *cp; cp++) { 225*7c478bd9Sstevel@tonic-gate c = (uchar_t)*cp; 226*7c478bd9Sstevel@tonic-gate if (!isascii(c) || !(isalnum(c) || c == '_' || c == '-')) { 227*7c478bd9Sstevel@tonic-gate print(dgettext(domainname, 228*7c478bd9Sstevel@tonic-gate "invalid user name %s\n"), cp0); 229*7c478bd9Sstevel@tonic-gate return (0); 230*7c478bd9Sstevel@tonic-gate } 231*7c478bd9Sstevel@tonic-gate } 232*7c478bd9Sstevel@tonic-gate return (1); 233*7c478bd9Sstevel@tonic-gate } 234*7c478bd9Sstevel@tonic-gate 235*7c478bd9Sstevel@tonic-gate rmtopen(tape, mode) 236*7c478bd9Sstevel@tonic-gate char *tape; 237*7c478bd9Sstevel@tonic-gate int mode; 238*7c478bd9Sstevel@tonic-gate { 239*7c478bd9Sstevel@tonic-gate struct mtget mt; 240*7c478bd9Sstevel@tonic-gate char buf[256]; 241*7c478bd9Sstevel@tonic-gate int fd; 242*7c478bd9Sstevel@tonic-gate 243*7c478bd9Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf), "O%s\n%d\n", tape, mode); 244*7c478bd9Sstevel@tonic-gate rmtstate = TS_OPEN; 245*7c478bd9Sstevel@tonic-gate fd = rmtcall(tape, buf); 246*7c478bd9Sstevel@tonic-gate if (fd != -1) { 247*7c478bd9Sstevel@tonic-gate /* see if the rmt server supports the extended protocol */ 248*7c478bd9Sstevel@tonic-gate rmtversion = rmtioctl(-1, 0); 249*7c478bd9Sstevel@tonic-gate 250*7c478bd9Sstevel@tonic-gate /* 251*7c478bd9Sstevel@tonic-gate * Some rmt daemons apparently close the connection 252*7c478bd9Sstevel@tonic-gate * when they get a bogus ioctl. See 1210852 (ignore 253*7c478bd9Sstevel@tonic-gate * the evaluation). Make sure we can still talk to 254*7c478bd9Sstevel@tonic-gate * the device, re-opening it if necessary. 255*7c478bd9Sstevel@tonic-gate */ 256*7c478bd9Sstevel@tonic-gate if (rmtversion < 1) { 257*7c478bd9Sstevel@tonic-gate if (rmtstatus(&mt) < 0) { 258*7c478bd9Sstevel@tonic-gate rmtclose(); 259*7c478bd9Sstevel@tonic-gate rmtgetconn(); 260*7c478bd9Sstevel@tonic-gate rmtversion = 0; 261*7c478bd9Sstevel@tonic-gate } 262*7c478bd9Sstevel@tonic-gate } 263*7c478bd9Sstevel@tonic-gate } 264*7c478bd9Sstevel@tonic-gate return (fd); 265*7c478bd9Sstevel@tonic-gate } 266*7c478bd9Sstevel@tonic-gate 267*7c478bd9Sstevel@tonic-gate void 268*7c478bd9Sstevel@tonic-gate #ifdef __STDC__ 269*7c478bd9Sstevel@tonic-gate rmtclose(void) 270*7c478bd9Sstevel@tonic-gate #else 271*7c478bd9Sstevel@tonic-gate rmtclose() 272*7c478bd9Sstevel@tonic-gate #endif 273*7c478bd9Sstevel@tonic-gate { 274*7c478bd9Sstevel@tonic-gate if (rmtstate != TS_OPEN) 275*7c478bd9Sstevel@tonic-gate return; 276*7c478bd9Sstevel@tonic-gate (void) rmtcall("close", "C\n"); 277*7c478bd9Sstevel@tonic-gate rmtstate = TS_CLOSED; 278*7c478bd9Sstevel@tonic-gate } 279*7c478bd9Sstevel@tonic-gate 280*7c478bd9Sstevel@tonic-gate rmtstatus(mt) 281*7c478bd9Sstevel@tonic-gate struct mtget *mt; 282*7c478bd9Sstevel@tonic-gate { 283*7c478bd9Sstevel@tonic-gate char *buf = (char *)mt; 284*7c478bd9Sstevel@tonic-gate int n, i, cc; 285*7c478bd9Sstevel@tonic-gate 286*7c478bd9Sstevel@tonic-gate if (rmtversion > 0) 287*7c478bd9Sstevel@tonic-gate return (rmtstatus_extended(mt)); 288*7c478bd9Sstevel@tonic-gate 289*7c478bd9Sstevel@tonic-gate n = rmtcall("status", "S"); 290*7c478bd9Sstevel@tonic-gate if (n < 0) { 291*7c478bd9Sstevel@tonic-gate return (-1); 292*7c478bd9Sstevel@tonic-gate } 293*7c478bd9Sstevel@tonic-gate if ((unsigned)n > sizeof (*mt)) { 294*7c478bd9Sstevel@tonic-gate print(dgettext(domainname, 295*7c478bd9Sstevel@tonic-gate "rmtstatus: expected response size %d, got %d\n"), 296*7c478bd9Sstevel@tonic-gate sizeof (struct mtget), n); 297*7c478bd9Sstevel@tonic-gate print(dgettext(domainname, 298*7c478bd9Sstevel@tonic-gate "This means the remote rmt daemon is not compatible.\n")); 299*7c478bd9Sstevel@tonic-gate rmtconnaborted(0); 300*7c478bd9Sstevel@tonic-gate } 301*7c478bd9Sstevel@tonic-gate i = 0; 302*7c478bd9Sstevel@tonic-gate while (i < n) { 303*7c478bd9Sstevel@tonic-gate cc = read(rmtape, buf+i, n - i); 304*7c478bd9Sstevel@tonic-gate if (cc <= 0) 305*7c478bd9Sstevel@tonic-gate rmtconnaborted(0); 306*7c478bd9Sstevel@tonic-gate i += cc; 307*7c478bd9Sstevel@tonic-gate } 308*7c478bd9Sstevel@tonic-gate return (n); 309*7c478bd9Sstevel@tonic-gate } 310*7c478bd9Sstevel@tonic-gate 311*7c478bd9Sstevel@tonic-gate static int 312*7c478bd9Sstevel@tonic-gate rmtstatus_extended(mt) 313*7c478bd9Sstevel@tonic-gate struct mtget *mt; 314*7c478bd9Sstevel@tonic-gate { 315*7c478bd9Sstevel@tonic-gate if ((mt->mt_type = rmtcall("status", "sT")) == -1) 316*7c478bd9Sstevel@tonic-gate return (-1); 317*7c478bd9Sstevel@tonic-gate mt->mt_dsreg = rmtcall("status", "sD"); 318*7c478bd9Sstevel@tonic-gate mt->mt_erreg = rmtcall("status", "sE"); 319*7c478bd9Sstevel@tonic-gate mt->mt_resid = rmtcall("status", "sR"); 320*7c478bd9Sstevel@tonic-gate mt->mt_fileno = rmtcall("status", "sF"); 321*7c478bd9Sstevel@tonic-gate mt->mt_blkno = rmtcall("status", "sB"); 322*7c478bd9Sstevel@tonic-gate mt->mt_flags = rmtcall("status", "sf"); 323*7c478bd9Sstevel@tonic-gate mt->mt_bf = rmtcall("status", "sb"); 324*7c478bd9Sstevel@tonic-gate return (0); 325*7c478bd9Sstevel@tonic-gate } 326*7c478bd9Sstevel@tonic-gate 327*7c478bd9Sstevel@tonic-gate rmtread(buf, count) 328*7c478bd9Sstevel@tonic-gate char *buf; 329*7c478bd9Sstevel@tonic-gate uint_t count; 330*7c478bd9Sstevel@tonic-gate { 331*7c478bd9Sstevel@tonic-gate char line[30]; 332*7c478bd9Sstevel@tonic-gate int n, i, cc; 333*7c478bd9Sstevel@tonic-gate 334*7c478bd9Sstevel@tonic-gate (void) snprintf(line, sizeof (line), "R%d\n", count); 335*7c478bd9Sstevel@tonic-gate n = rmtcall("read", line); 336*7c478bd9Sstevel@tonic-gate if (n < 0) { 337*7c478bd9Sstevel@tonic-gate return (-1); 338*7c478bd9Sstevel@tonic-gate } 339*7c478bd9Sstevel@tonic-gate if (n > count) { 340*7c478bd9Sstevel@tonic-gate print(dgettext(domainname, 341*7c478bd9Sstevel@tonic-gate "rmtread: expected response size %d, got %d\n"), 342*7c478bd9Sstevel@tonic-gate count, n); 343*7c478bd9Sstevel@tonic-gate print(dgettext(domainname, 344*7c478bd9Sstevel@tonic-gate "This means the remote rmt daemon is not compatible.\n")); 345*7c478bd9Sstevel@tonic-gate rmtconnaborted(0); 346*7c478bd9Sstevel@tonic-gate } 347*7c478bd9Sstevel@tonic-gate i = 0; 348*7c478bd9Sstevel@tonic-gate while (i < n) { 349*7c478bd9Sstevel@tonic-gate cc = read(rmtape, buf+i, n - i); 350*7c478bd9Sstevel@tonic-gate if (cc <= 0) 351*7c478bd9Sstevel@tonic-gate rmtconnaborted(0); 352*7c478bd9Sstevel@tonic-gate i += cc; 353*7c478bd9Sstevel@tonic-gate } 354*7c478bd9Sstevel@tonic-gate return (n); 355*7c478bd9Sstevel@tonic-gate } 356*7c478bd9Sstevel@tonic-gate 357*7c478bd9Sstevel@tonic-gate rmtwrite(buf, count) 358*7c478bd9Sstevel@tonic-gate char *buf; 359*7c478bd9Sstevel@tonic-gate uint_t count; 360*7c478bd9Sstevel@tonic-gate { 361*7c478bd9Sstevel@tonic-gate int retval; 362*7c478bd9Sstevel@tonic-gate char line[64]; /* numbers can get big */ 363*7c478bd9Sstevel@tonic-gate 364*7c478bd9Sstevel@tonic-gate (void) snprintf(line, sizeof (line), "W%d\n", count); 365*7c478bd9Sstevel@tonic-gate retval = rmtpush(line, strlen(line)); 366*7c478bd9Sstevel@tonic-gate if (retval <= 0) 367*7c478bd9Sstevel@tonic-gate return (-1); 368*7c478bd9Sstevel@tonic-gate 369*7c478bd9Sstevel@tonic-gate retval = rmtpush(buf, count); 370*7c478bd9Sstevel@tonic-gate if (retval <= 0) 371*7c478bd9Sstevel@tonic-gate return (-1); 372*7c478bd9Sstevel@tonic-gate 373*7c478bd9Sstevel@tonic-gate return (rmtreply("write")); 374*7c478bd9Sstevel@tonic-gate } 375*7c478bd9Sstevel@tonic-gate 376*7c478bd9Sstevel@tonic-gate int 377*7c478bd9Sstevel@tonic-gate rmtpush(buf, count) 378*7c478bd9Sstevel@tonic-gate char *buf; 379*7c478bd9Sstevel@tonic-gate uint_t count; 380*7c478bd9Sstevel@tonic-gate { 381*7c478bd9Sstevel@tonic-gate int retval; 382*7c478bd9Sstevel@tonic-gate 383*7c478bd9Sstevel@tonic-gate do { 384*7c478bd9Sstevel@tonic-gate retval = write(rmtape, buf, count); 385*7c478bd9Sstevel@tonic-gate buf += retval; 386*7c478bd9Sstevel@tonic-gate count -= retval; 387*7c478bd9Sstevel@tonic-gate } while (count && retval > 0); 388*7c478bd9Sstevel@tonic-gate 389*7c478bd9Sstevel@tonic-gate return (retval); 390*7c478bd9Sstevel@tonic-gate } 391*7c478bd9Sstevel@tonic-gate 392*7c478bd9Sstevel@tonic-gate int 393*7c478bd9Sstevel@tonic-gate rmtseek(offset, pos) 394*7c478bd9Sstevel@tonic-gate int offset, pos; 395*7c478bd9Sstevel@tonic-gate { 396*7c478bd9Sstevel@tonic-gate char line[80]; 397*7c478bd9Sstevel@tonic-gate 398*7c478bd9Sstevel@tonic-gate (void) snprintf(line, sizeof (line), "L%d\n%d\n", offset, pos); 399*7c478bd9Sstevel@tonic-gate return (rmtcall("seek", line)); 400*7c478bd9Sstevel@tonic-gate } 401*7c478bd9Sstevel@tonic-gate 402*7c478bd9Sstevel@tonic-gate int 403*7c478bd9Sstevel@tonic-gate rmtioctl(cmd, count) 404*7c478bd9Sstevel@tonic-gate int cmd; 405*7c478bd9Sstevel@tonic-gate long count; 406*7c478bd9Sstevel@tonic-gate { 407*7c478bd9Sstevel@tonic-gate char buf[256]; 408*7c478bd9Sstevel@tonic-gate int xcmd; 409*7c478bd9Sstevel@tonic-gate 410*7c478bd9Sstevel@tonic-gate if (count < 0) 411*7c478bd9Sstevel@tonic-gate return (-1); 412*7c478bd9Sstevel@tonic-gate 413*7c478bd9Sstevel@tonic-gate if ((xcmd = map_extended_ioctl(cmd)) != -1) 414*7c478bd9Sstevel@tonic-gate return (rmtioctl_extended(xcmd, count)); 415*7c478bd9Sstevel@tonic-gate 416*7c478bd9Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf), "I%d\n%ld\n", cmd, count); 417*7c478bd9Sstevel@tonic-gate return (rmtcall("ioctl", buf)); 418*7c478bd9Sstevel@tonic-gate } 419*7c478bd9Sstevel@tonic-gate 420*7c478bd9Sstevel@tonic-gate /* 421*7c478bd9Sstevel@tonic-gate * Map from the standard Sun ioctl commands into the extended version, 422*7c478bd9Sstevel@tonic-gate * if possible. 423*7c478bd9Sstevel@tonic-gate */ 424*7c478bd9Sstevel@tonic-gate static int 425*7c478bd9Sstevel@tonic-gate map_extended_ioctl(cmd) 426*7c478bd9Sstevel@tonic-gate int cmd; 427*7c478bd9Sstevel@tonic-gate { 428*7c478bd9Sstevel@tonic-gate int xcmd; 429*7c478bd9Sstevel@tonic-gate 430*7c478bd9Sstevel@tonic-gate if (rmtversion <= 0) 431*7c478bd9Sstevel@tonic-gate return (-1); /* extended protocol not supported */ 432*7c478bd9Sstevel@tonic-gate 433*7c478bd9Sstevel@tonic-gate switch (cmd) { 434*7c478bd9Sstevel@tonic-gate case MTRETEN: 435*7c478bd9Sstevel@tonic-gate xcmd = 2; 436*7c478bd9Sstevel@tonic-gate break; 437*7c478bd9Sstevel@tonic-gate case MTERASE: 438*7c478bd9Sstevel@tonic-gate xcmd = 3; 439*7c478bd9Sstevel@tonic-gate break; 440*7c478bd9Sstevel@tonic-gate case MTEOM: 441*7c478bd9Sstevel@tonic-gate xcmd = 4; 442*7c478bd9Sstevel@tonic-gate break; 443*7c478bd9Sstevel@tonic-gate case MTNBSF: 444*7c478bd9Sstevel@tonic-gate xcmd = 5; 445*7c478bd9Sstevel@tonic-gate break; 446*7c478bd9Sstevel@tonic-gate default: 447*7c478bd9Sstevel@tonic-gate xcmd = -1; /* not supported */ 448*7c478bd9Sstevel@tonic-gate break; 449*7c478bd9Sstevel@tonic-gate } 450*7c478bd9Sstevel@tonic-gate return (xcmd); 451*7c478bd9Sstevel@tonic-gate } 452*7c478bd9Sstevel@tonic-gate 453*7c478bd9Sstevel@tonic-gate static int 454*7c478bd9Sstevel@tonic-gate rmtioctl_extended(cmd, count) 455*7c478bd9Sstevel@tonic-gate int cmd; 456*7c478bd9Sstevel@tonic-gate long count; 457*7c478bd9Sstevel@tonic-gate { 458*7c478bd9Sstevel@tonic-gate char buf[256]; 459*7c478bd9Sstevel@tonic-gate 460*7c478bd9Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf), "i%d\n%ld\n", cmd, count); 461*7c478bd9Sstevel@tonic-gate return (rmtcall("ioctl", buf)); 462*7c478bd9Sstevel@tonic-gate } 463*7c478bd9Sstevel@tonic-gate 464*7c478bd9Sstevel@tonic-gate static int 465*7c478bd9Sstevel@tonic-gate rmtcall(cmd, buf) 466*7c478bd9Sstevel@tonic-gate char *cmd, *buf; 467*7c478bd9Sstevel@tonic-gate { 468*7c478bd9Sstevel@tonic-gate if (rmtpush(buf, strlen(buf)) != strlen(buf)) 469*7c478bd9Sstevel@tonic-gate rmtconnaborted(0); 470*7c478bd9Sstevel@tonic-gate return (rmtreply(cmd)); 471*7c478bd9Sstevel@tonic-gate } 472*7c478bd9Sstevel@tonic-gate 473*7c478bd9Sstevel@tonic-gate static int 474*7c478bd9Sstevel@tonic-gate rmtreply(cmd) 475*7c478bd9Sstevel@tonic-gate char *cmd; 476*7c478bd9Sstevel@tonic-gate { 477*7c478bd9Sstevel@tonic-gate char code[30], emsg[BUFSIZ]; 478*7c478bd9Sstevel@tonic-gate 479*7c478bd9Sstevel@tonic-gate rmtgets(code, sizeof (code)); 480*7c478bd9Sstevel@tonic-gate if (*code == 'E' || *code == 'F') { 481*7c478bd9Sstevel@tonic-gate rmtgets(emsg, sizeof (emsg)); 482*7c478bd9Sstevel@tonic-gate /* 483*7c478bd9Sstevel@tonic-gate * don't print error message for ioctl or status; 484*7c478bd9Sstevel@tonic-gate * or if we are opening up a full path (i.e. device) 485*7c478bd9Sstevel@tonic-gate * and the tape is not loaded (EIO error) 486*7c478bd9Sstevel@tonic-gate */ 487*7c478bd9Sstevel@tonic-gate if (strcmp(cmd, "ioctl") != 0 && 488*7c478bd9Sstevel@tonic-gate strcmp(cmd, "status") != 0 && 489*7c478bd9Sstevel@tonic-gate !(cmd[0] == '/' && atoi(code + 1) == EIO)) 490*7c478bd9Sstevel@tonic-gate print("%s: %s\n", cmd, emsg); 491*7c478bd9Sstevel@tonic-gate errno = atoi(code + 1); 492*7c478bd9Sstevel@tonic-gate if (*code == 'F') { 493*7c478bd9Sstevel@tonic-gate rmtstate = TS_CLOSED; 494*7c478bd9Sstevel@tonic-gate return (-1); 495*7c478bd9Sstevel@tonic-gate } 496*7c478bd9Sstevel@tonic-gate return (-1); 497*7c478bd9Sstevel@tonic-gate } 498*7c478bd9Sstevel@tonic-gate if (*code != 'A') { 499*7c478bd9Sstevel@tonic-gate print(dgettext(domainname, 500*7c478bd9Sstevel@tonic-gate "Protocol to remote tape server botched (code %s?).\n"), 501*7c478bd9Sstevel@tonic-gate code); 502*7c478bd9Sstevel@tonic-gate rmtconnaborted(0); 503*7c478bd9Sstevel@tonic-gate } 504*7c478bd9Sstevel@tonic-gate return (atoi(code + 1)); 505*7c478bd9Sstevel@tonic-gate } 506*7c478bd9Sstevel@tonic-gate 507*7c478bd9Sstevel@tonic-gate static void 508*7c478bd9Sstevel@tonic-gate rmtgets(cp, len) 509*7c478bd9Sstevel@tonic-gate char *cp; 510*7c478bd9Sstevel@tonic-gate int len; 511*7c478bd9Sstevel@tonic-gate { 512*7c478bd9Sstevel@tonic-gate int i, n; 513*7c478bd9Sstevel@tonic-gate 514*7c478bd9Sstevel@tonic-gate n = recv(rmtape, cp, len-1, MSG_PEEK); 515*7c478bd9Sstevel@tonic-gate for (i = 0; i < n; i++) 516*7c478bd9Sstevel@tonic-gate if (cp[i] == '\n') 517*7c478bd9Sstevel@tonic-gate break; 518*7c478bd9Sstevel@tonic-gate n = i + 1; /* characters to read at once */ 519*7c478bd9Sstevel@tonic-gate for (i = 0; i < len; i += n, n = 1) { 520*7c478bd9Sstevel@tonic-gate n = read(rmtape, cp, n); 521*7c478bd9Sstevel@tonic-gate if (n <= 0) 522*7c478bd9Sstevel@tonic-gate rmtconnaborted(0); 523*7c478bd9Sstevel@tonic-gate cp += n; 524*7c478bd9Sstevel@tonic-gate if (cp[-1] == '\n') { 525*7c478bd9Sstevel@tonic-gate cp[-1] = '\0'; 526*7c478bd9Sstevel@tonic-gate return; 527*7c478bd9Sstevel@tonic-gate } 528*7c478bd9Sstevel@tonic-gate } 529*7c478bd9Sstevel@tonic-gate print(dgettext(domainname, 530*7c478bd9Sstevel@tonic-gate "Protocol to remote tape server botched (in rmtgets).\n")); 531*7c478bd9Sstevel@tonic-gate rmtconnaborted(0); 532*7c478bd9Sstevel@tonic-gate } 533*7c478bd9Sstevel@tonic-gate 534*7c478bd9Sstevel@tonic-gate #ifdef __STDC__ 535*7c478bd9Sstevel@tonic-gate #include <stdarg.h> 536*7c478bd9Sstevel@tonic-gate 537*7c478bd9Sstevel@tonic-gate /* VARARGS1 */ 538*7c478bd9Sstevel@tonic-gate static void 539*7c478bd9Sstevel@tonic-gate rmtmsg(const char *fmt, ...) 540*7c478bd9Sstevel@tonic-gate { 541*7c478bd9Sstevel@tonic-gate va_list args; 542*7c478bd9Sstevel@tonic-gate 543*7c478bd9Sstevel@tonic-gate va_start(args, fmt); 544*7c478bd9Sstevel@tonic-gate (void) vfprintf(stderr, fmt, args); 545*7c478bd9Sstevel@tonic-gate (void) fflush(stderr); 546*7c478bd9Sstevel@tonic-gate } 547*7c478bd9Sstevel@tonic-gate #else 548*7c478bd9Sstevel@tonic-gate #include <varargs.h> 549*7c478bd9Sstevel@tonic-gate 550*7c478bd9Sstevel@tonic-gate /* VARARGS */ 551*7c478bd9Sstevel@tonic-gate static void 552*7c478bd9Sstevel@tonic-gate rmtmsg(va_alist) 553*7c478bd9Sstevel@tonic-gate va_dcl 554*7c478bd9Sstevel@tonic-gate { 555*7c478bd9Sstevel@tonic-gate va_list args; 556*7c478bd9Sstevel@tonic-gate char *fmt; 557*7c478bd9Sstevel@tonic-gate 558*7c478bd9Sstevel@tonic-gate va_start(args); 559*7c478bd9Sstevel@tonic-gate fmt = va_arg(args, char *); 560*7c478bd9Sstevel@tonic-gate (void) vfprintf(stderr, fmt, args); 561*7c478bd9Sstevel@tonic-gate (void) fflush(stderr); 562*7c478bd9Sstevel@tonic-gate } 563*7c478bd9Sstevel@tonic-gate #endif 564