1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright 2003 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*7c478bd9Sstevel@tonic-gate */ 26*7c478bd9Sstevel@tonic-gate 27*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*7c478bd9Sstevel@tonic-gate 29*7c478bd9Sstevel@tonic-gate /* 30*7c478bd9Sstevel@tonic-gate * Multi-process streaming 4.3bsd /etc/rmt server. 31*7c478bd9Sstevel@tonic-gate * Has three locks (for stdin, stdout, and the tape) 32*7c478bd9Sstevel@tonic-gate * that are passed by signals and received by sigpause(). 33*7c478bd9Sstevel@tonic-gate */ 34*7c478bd9Sstevel@tonic-gate 35*7c478bd9Sstevel@tonic-gate #include <stdio.h> 36*7c478bd9Sstevel@tonic-gate #include <locale.h> 37*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 38*7c478bd9Sstevel@tonic-gate #include <errno.h> 39*7c478bd9Sstevel@tonic-gate #include <fcntl.h> 40*7c478bd9Sstevel@tonic-gate #include <string.h> 41*7c478bd9Sstevel@tonic-gate #include <signal.h> 42*7c478bd9Sstevel@tonic-gate #include <setjmp.h> 43*7c478bd9Sstevel@tonic-gate #include <sys/ioctl.h> 44*7c478bd9Sstevel@tonic-gate #include <sys/mtio.h> 45*7c478bd9Sstevel@tonic-gate #include <sys/wait.h> 46*7c478bd9Sstevel@tonic-gate #include <stdlib.h> 47*7c478bd9Sstevel@tonic-gate #include <unistd.h> 48*7c478bd9Sstevel@tonic-gate #include <sys/param.h> 49*7c478bd9Sstevel@tonic-gate 50*7c478bd9Sstevel@tonic-gate static sigset_t cmdmask, maskall, newmask; 51*7c478bd9Sstevel@tonic-gate static sigset_t sendmask, tapemask; 52*7c478bd9Sstevel@tonic-gate 53*7c478bd9Sstevel@tonic-gate static struct mtop mtop; 54*7c478bd9Sstevel@tonic-gate static struct mtget mtget; 55*7c478bd9Sstevel@tonic-gate static jmp_buf sjbuf; 56*7c478bd9Sstevel@tonic-gate 57*7c478bd9Sstevel@tonic-gate #define RECV SIGIO 58*7c478bd9Sstevel@tonic-gate #define TAPE SIGURG 59*7c478bd9Sstevel@tonic-gate #define SEND SIGALRM 60*7c478bd9Sstevel@tonic-gate #define ERROR SIGTERM 61*7c478bd9Sstevel@tonic-gate #define OPEN SIGUSR1 62*7c478bd9Sstevel@tonic-gate #define CLOSE SIGUSR2 63*7c478bd9Sstevel@tonic-gate 64*7c478bd9Sstevel@tonic-gate /* 65*7c478bd9Sstevel@tonic-gate * Support for Version 1 of the extended RMT protocol: 66*7c478bd9Sstevel@tonic-gate * Placing RMTIVERSION (-1) into the mt_op field of the ioctl ('I') 67*7c478bd9Sstevel@tonic-gate * request will return the current version of the RMT protocol that 68*7c478bd9Sstevel@tonic-gate * the server supports. For servers that don't support Version 1, 69*7c478bd9Sstevel@tonic-gate * an error is returned and the client knows to only use Version 0 70*7c478bd9Sstevel@tonic-gate * (stock BSD) calls, which include mt_op values in the range of [0-7]. 71*7c478bd9Sstevel@tonic-gate * 72*7c478bd9Sstevel@tonic-gate * Note: The RMTIVERSION request must be made in order for the extended 73*7c478bd9Sstevel@tonic-gate * protocol commands to be recognized. 74*7c478bd9Sstevel@tonic-gate */ 75*7c478bd9Sstevel@tonic-gate #define RMTIVERSION -1 76*7c478bd9Sstevel@tonic-gate #define RMT_VERSION 1 77*7c478bd9Sstevel@tonic-gate 78*7c478bd9Sstevel@tonic-gate /* 79*7c478bd9Sstevel@tonic-gate * These requests are made to the extended RMT protocol by specifying the 80*7c478bd9Sstevel@tonic-gate * new 'i' command of RMT Protocol Version 1. They are intended to allow 81*7c478bd9Sstevel@tonic-gate * an intelligent client to communicate with both BSD and Solaris RMT 82*7c478bd9Sstevel@tonic-gate * servers heterogeneously. The 'i' command taks an mtop structure as 83*7c478bd9Sstevel@tonic-gate * argument, exactly like the 'I' command does. 84*7c478bd9Sstevel@tonic-gate */ 85*7c478bd9Sstevel@tonic-gate #define RMTICACHE 0 86*7c478bd9Sstevel@tonic-gate #define RMTINOCACHE 1 87*7c478bd9Sstevel@tonic-gate #define RMTIRETEN 2 88*7c478bd9Sstevel@tonic-gate #define RMTIERASE 3 89*7c478bd9Sstevel@tonic-gate #define RMTIEOM 4 90*7c478bd9Sstevel@tonic-gate #define RMTINBSF 5 91*7c478bd9Sstevel@tonic-gate 92*7c478bd9Sstevel@tonic-gate /* 93*7c478bd9Sstevel@tonic-gate * These requests are made to the extended RMT protocol by specifying the 94*7c478bd9Sstevel@tonic-gate * new 's' command of RMT Protocol Version 1. They are intended to allow 95*7c478bd9Sstevel@tonic-gate * an intelligent client to obtain "mt status" information with both BSD 96*7c478bd9Sstevel@tonic-gate * and Solaris RMT servers heterogeneously. They return the requested 97*7c478bd9Sstevel@tonic-gate * piece of the mtget structure as an ascii integer. The request is made 98*7c478bd9Sstevel@tonic-gate * by sending the required character immediately after the 's' character 99*7c478bd9Sstevel@tonic-gate * without any trailing newline. A single ascii integer is returned, else 100*7c478bd9Sstevel@tonic-gate * an error is returned. 101*7c478bd9Sstevel@tonic-gate */ 102*7c478bd9Sstevel@tonic-gate #define MTS_TYPE 'T' /* mtget.mt_type */ 103*7c478bd9Sstevel@tonic-gate #define MTS_DSREG 'D' /* mtget.mt_dsreg */ 104*7c478bd9Sstevel@tonic-gate #define MTS_ERREG 'E' /* mtget.mt_erreg */ 105*7c478bd9Sstevel@tonic-gate #define MTS_RESID 'R' /* mtget.mt_resid */ 106*7c478bd9Sstevel@tonic-gate #define MTS_FILENO 'F' /* mtget.mt_fileno */ 107*7c478bd9Sstevel@tonic-gate #define MTS_BLKNO 'B' /* mtget.mt_blkno */ 108*7c478bd9Sstevel@tonic-gate #define MTS_FLAGS 'f' /* mtget.mt_flags */ 109*7c478bd9Sstevel@tonic-gate #define MTS_BF 'b' /* mtget.mt_bf */ 110*7c478bd9Sstevel@tonic-gate 111*7c478bd9Sstevel@tonic-gate #define MAXCHILD 1 112*7c478bd9Sstevel@tonic-gate static pid_t childpid[MAXCHILD]; 113*7c478bd9Sstevel@tonic-gate static int children; 114*7c478bd9Sstevel@tonic-gate 115*7c478bd9Sstevel@tonic-gate static int tape = -1; 116*7c478bd9Sstevel@tonic-gate static size_t maxrecsize = 0; 117*7c478bd9Sstevel@tonic-gate static char *record; 118*7c478bd9Sstevel@tonic-gate 119*7c478bd9Sstevel@tonic-gate #define SSIZE 64 120*7c478bd9Sstevel@tonic-gate static char pos[SSIZE], op[SSIZE], mode[SSIZE], count[SSIZE]; 121*7c478bd9Sstevel@tonic-gate static char device[MAXPATHLEN]; 122*7c478bd9Sstevel@tonic-gate 123*7c478bd9Sstevel@tonic-gate static FILE *debug; 124*7c478bd9Sstevel@tonic-gate #define DEBUG(f) if (debug) (void) fprintf(debug, (f)) 125*7c478bd9Sstevel@tonic-gate #define DEBUG1(f, a) if (debug) (void) fprintf(debug, (f), (a)) 126*7c478bd9Sstevel@tonic-gate #define DEBUG2(f, a, b) if (debug) (void) fprintf(debug, (f), (a), (b)) 127*7c478bd9Sstevel@tonic-gate #define DEBUG3(f, a, b, c) if (debug) \ 128*7c478bd9Sstevel@tonic-gate (void) fprintf(debug, (f), (a), (b), (c)) 129*7c478bd9Sstevel@tonic-gate 130*7c478bd9Sstevel@tonic-gate static char key; 131*7c478bd9Sstevel@tonic-gate 132*7c478bd9Sstevel@tonic-gate #ifdef __STDC__ 133*7c478bd9Sstevel@tonic-gate static void respond(offset_t, int); 134*7c478bd9Sstevel@tonic-gate static void getstring(char *, size_t); 135*7c478bd9Sstevel@tonic-gate static void checkbuf(size_t); 136*7c478bd9Sstevel@tonic-gate #else 137*7c478bd9Sstevel@tonic-gate static void respond(); 138*7c478bd9Sstevel@tonic-gate static void getstring(); 139*7c478bd9Sstevel@tonic-gate static void checkbuf(); 140*7c478bd9Sstevel@tonic-gate #endif 141*7c478bd9Sstevel@tonic-gate 142*7c478bd9Sstevel@tonic-gate static void 143*7c478bd9Sstevel@tonic-gate catch(sig) 144*7c478bd9Sstevel@tonic-gate int sig; 145*7c478bd9Sstevel@tonic-gate { 146*7c478bd9Sstevel@tonic-gate switch (sig) { 147*7c478bd9Sstevel@tonic-gate default: return; 148*7c478bd9Sstevel@tonic-gate case OPEN: key = 'O'; break; 149*7c478bd9Sstevel@tonic-gate case CLOSE: key = 'C'; break; 150*7c478bd9Sstevel@tonic-gate case ERROR: key = 'E'; break; 151*7c478bd9Sstevel@tonic-gate } 152*7c478bd9Sstevel@tonic-gate (void) sigprocmask(SIG_SETMASK, &maskall, (sigset_t *)0); 153*7c478bd9Sstevel@tonic-gate longjmp(sjbuf, 1); 154*7c478bd9Sstevel@tonic-gate } 155*7c478bd9Sstevel@tonic-gate 156*7c478bd9Sstevel@tonic-gate main(argc, argv) 157*7c478bd9Sstevel@tonic-gate int argc; 158*7c478bd9Sstevel@tonic-gate char *argv[]; 159*7c478bd9Sstevel@tonic-gate { 160*7c478bd9Sstevel@tonic-gate struct sigaction sa; 161*7c478bd9Sstevel@tonic-gate pid_t parent = getpid(), next = parent; 162*7c478bd9Sstevel@tonic-gate int saverr; 163*7c478bd9Sstevel@tonic-gate offset_t rval; 164*7c478bd9Sstevel@tonic-gate ssize_t cc; 165*7c478bd9Sstevel@tonic-gate size_t n, i; 166*7c478bd9Sstevel@tonic-gate 167*7c478bd9Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 168*7c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ 169*7c478bd9Sstevel@tonic-gate #define TEXT_DOMAIN "SYS_TEST" 170*7c478bd9Sstevel@tonic-gate #endif 171*7c478bd9Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN); 172*7c478bd9Sstevel@tonic-gate 173*7c478bd9Sstevel@tonic-gate if (argc > 1) { 174*7c478bd9Sstevel@tonic-gate if ((debug = fopen(argv[1], "w")) == NULL) 175*7c478bd9Sstevel@tonic-gate exit(1); 176*7c478bd9Sstevel@tonic-gate setbuf(debug, NULL); 177*7c478bd9Sstevel@tonic-gate } 178*7c478bd9Sstevel@tonic-gate (void) sigemptyset(&maskall); 179*7c478bd9Sstevel@tonic-gate (void) sigaddset(&maskall, RECV); 180*7c478bd9Sstevel@tonic-gate (void) sigaddset(&maskall, OPEN); 181*7c478bd9Sstevel@tonic-gate (void) sigaddset(&maskall, CLOSE); 182*7c478bd9Sstevel@tonic-gate (void) sigaddset(&maskall, ERROR); 183*7c478bd9Sstevel@tonic-gate (void) sigaddset(&maskall, TAPE); 184*7c478bd9Sstevel@tonic-gate (void) sigaddset(&maskall, SEND); 185*7c478bd9Sstevel@tonic-gate 186*7c478bd9Sstevel@tonic-gate tapemask = maskall; 187*7c478bd9Sstevel@tonic-gate (void) sigdelset(&tapemask, TAPE); 188*7c478bd9Sstevel@tonic-gate 189*7c478bd9Sstevel@tonic-gate sendmask = maskall; 190*7c478bd9Sstevel@tonic-gate (void) sigdelset(&sendmask, SEND); 191*7c478bd9Sstevel@tonic-gate 192*7c478bd9Sstevel@tonic-gate (void) sigemptyset(&cmdmask); 193*7c478bd9Sstevel@tonic-gate (void) sigaddset(&cmdmask, TAPE); 194*7c478bd9Sstevel@tonic-gate (void) sigaddset(&cmdmask, SEND); 195*7c478bd9Sstevel@tonic-gate 196*7c478bd9Sstevel@tonic-gate (void) sigemptyset(&sa.sa_mask); 197*7c478bd9Sstevel@tonic-gate 198*7c478bd9Sstevel@tonic-gate sa.sa_handler = catch; 199*7c478bd9Sstevel@tonic-gate sa.sa_flags = SA_RESTART; 200*7c478bd9Sstevel@tonic-gate (void) sigaction(RECV, &sa, (struct sigaction *)0); 201*7c478bd9Sstevel@tonic-gate (void) sigaction(SEND, &sa, (struct sigaction *)0); 202*7c478bd9Sstevel@tonic-gate (void) sigaction(TAPE, &sa, (struct sigaction *)0); 203*7c478bd9Sstevel@tonic-gate (void) sigaction(OPEN, &sa, (struct sigaction *)0); 204*7c478bd9Sstevel@tonic-gate (void) sigaction(CLOSE, &sa, (struct sigaction *)0); 205*7c478bd9Sstevel@tonic-gate (void) sigaction(ERROR, &sa, (struct sigaction *)0); 206*7c478bd9Sstevel@tonic-gate 207*7c478bd9Sstevel@tonic-gate (void) sigprocmask(SIG_SETMASK, &maskall, (sigset_t *)0); 208*7c478bd9Sstevel@tonic-gate 209*7c478bd9Sstevel@tonic-gate (void) kill(parent, TAPE); 210*7c478bd9Sstevel@tonic-gate (void) kill(parent, SEND); 211*7c478bd9Sstevel@tonic-gate 212*7c478bd9Sstevel@tonic-gate while (read(0, &key, 1) == 1) { 213*7c478bd9Sstevel@tonic-gate switch (key) { 214*7c478bd9Sstevel@tonic-gate case 'L': /* lseek */ 215*7c478bd9Sstevel@tonic-gate getstring(count, sizeof (count)); 216*7c478bd9Sstevel@tonic-gate getstring(pos, sizeof (pos)); 217*7c478bd9Sstevel@tonic-gate DEBUG2("rmtd: L %s %s\n", count, pos); 218*7c478bd9Sstevel@tonic-gate (void) kill(next, RECV); 219*7c478bd9Sstevel@tonic-gate (void) sigsuspend(&tapemask); 220*7c478bd9Sstevel@tonic-gate rval = llseek(tape, atoll(count), atoi(pos)); 221*7c478bd9Sstevel@tonic-gate saverr = errno; 222*7c478bd9Sstevel@tonic-gate (void) kill(next, TAPE); 223*7c478bd9Sstevel@tonic-gate (void) sigsuspend(&sendmask); 224*7c478bd9Sstevel@tonic-gate respond(rval, saverr); 225*7c478bd9Sstevel@tonic-gate break; 226*7c478bd9Sstevel@tonic-gate 227*7c478bd9Sstevel@tonic-gate case 'I': /* ioctl */ 228*7c478bd9Sstevel@tonic-gate case 'i': { /* extended version ioctl */ 229*7c478bd9Sstevel@tonic-gate int bad = 0; 230*7c478bd9Sstevel@tonic-gate 231*7c478bd9Sstevel@tonic-gate getstring(op, sizeof (op)); 232*7c478bd9Sstevel@tonic-gate getstring(count, sizeof (count)); 233*7c478bd9Sstevel@tonic-gate DEBUG3("rmtd: %c %s %s\n", key, op, count); 234*7c478bd9Sstevel@tonic-gate mtop.mt_op = atoi(op); 235*7c478bd9Sstevel@tonic-gate mtop.mt_count = atoi(count); 236*7c478bd9Sstevel@tonic-gate if (key == 'i') { 237*7c478bd9Sstevel@tonic-gate /* 238*7c478bd9Sstevel@tonic-gate * Map the supported compatibility defines 239*7c478bd9Sstevel@tonic-gate * into real ioctl values. 240*7c478bd9Sstevel@tonic-gate */ 241*7c478bd9Sstevel@tonic-gate switch (mtop.mt_op) { 242*7c478bd9Sstevel@tonic-gate case RMTICACHE: 243*7c478bd9Sstevel@tonic-gate case RMTINOCACHE: /* not support on Sun */ 244*7c478bd9Sstevel@tonic-gate bad = 1; 245*7c478bd9Sstevel@tonic-gate break; 246*7c478bd9Sstevel@tonic-gate case RMTIRETEN: 247*7c478bd9Sstevel@tonic-gate mtop.mt_op = MTRETEN; 248*7c478bd9Sstevel@tonic-gate break; 249*7c478bd9Sstevel@tonic-gate case RMTIERASE: 250*7c478bd9Sstevel@tonic-gate mtop.mt_op = MTERASE; 251*7c478bd9Sstevel@tonic-gate break; 252*7c478bd9Sstevel@tonic-gate case RMTIEOM: 253*7c478bd9Sstevel@tonic-gate mtop.mt_op = MTEOM; 254*7c478bd9Sstevel@tonic-gate break; 255*7c478bd9Sstevel@tonic-gate case RMTINBSF: 256*7c478bd9Sstevel@tonic-gate mtop.mt_op = MTNBSF; 257*7c478bd9Sstevel@tonic-gate break; 258*7c478bd9Sstevel@tonic-gate default: 259*7c478bd9Sstevel@tonic-gate bad = 1; 260*7c478bd9Sstevel@tonic-gate break; 261*7c478bd9Sstevel@tonic-gate } 262*7c478bd9Sstevel@tonic-gate } 263*7c478bd9Sstevel@tonic-gate if (bad) { 264*7c478bd9Sstevel@tonic-gate respond(-1LL, EINVAL); 265*7c478bd9Sstevel@tonic-gate } else { 266*7c478bd9Sstevel@tonic-gate (void) kill(next, RECV); 267*7c478bd9Sstevel@tonic-gate (void) sigsuspend(&tapemask); 268*7c478bd9Sstevel@tonic-gate if (mtop.mt_op == RMTIVERSION) { 269*7c478bd9Sstevel@tonic-gate mtop.mt_count = RMT_VERSION; 270*7c478bd9Sstevel@tonic-gate rval = (offset_t)mtop.mt_count; 271*7c478bd9Sstevel@tonic-gate } else { 272*7c478bd9Sstevel@tonic-gate rval = (offset_t)ioctl(tape, MTIOCTOP, 273*7c478bd9Sstevel@tonic-gate (char *)&mtop); 274*7c478bd9Sstevel@tonic-gate } 275*7c478bd9Sstevel@tonic-gate saverr = errno; 276*7c478bd9Sstevel@tonic-gate (void) kill(next, TAPE); 277*7c478bd9Sstevel@tonic-gate (void) sigsuspend(&sendmask); 278*7c478bd9Sstevel@tonic-gate respond(rval < 0 ? 279*7c478bd9Sstevel@tonic-gate rval : (offset_t)mtop.mt_count, 280*7c478bd9Sstevel@tonic-gate saverr); 281*7c478bd9Sstevel@tonic-gate } 282*7c478bd9Sstevel@tonic-gate break; 283*7c478bd9Sstevel@tonic-gate } 284*7c478bd9Sstevel@tonic-gate 285*7c478bd9Sstevel@tonic-gate case 'S': /* status */ 286*7c478bd9Sstevel@tonic-gate case 's': { /* extended status */ 287*7c478bd9Sstevel@tonic-gate char skey; 288*7c478bd9Sstevel@tonic-gate 289*7c478bd9Sstevel@tonic-gate DEBUG1("rmtd: %c\n", key); 290*7c478bd9Sstevel@tonic-gate if (key == 's') { 291*7c478bd9Sstevel@tonic-gate if (read(0, &skey, 1) != 1) 292*7c478bd9Sstevel@tonic-gate continue; 293*7c478bd9Sstevel@tonic-gate } 294*7c478bd9Sstevel@tonic-gate (void) kill(next, RECV); 295*7c478bd9Sstevel@tonic-gate (void) sigsuspend(&tapemask); 296*7c478bd9Sstevel@tonic-gate errno = 0; 297*7c478bd9Sstevel@tonic-gate rval = (offset_t)ioctl(tape, MTIOCGET, (char *)&mtget); 298*7c478bd9Sstevel@tonic-gate saverr = errno; 299*7c478bd9Sstevel@tonic-gate (void) kill(next, TAPE); 300*7c478bd9Sstevel@tonic-gate (void) sigsuspend(&sendmask); 301*7c478bd9Sstevel@tonic-gate if (rval < 0) 302*7c478bd9Sstevel@tonic-gate respond(rval, saverr); 303*7c478bd9Sstevel@tonic-gate else { 304*7c478bd9Sstevel@tonic-gate if (key == 's') { /* extended status */ 305*7c478bd9Sstevel@tonic-gate DEBUG1("rmtd: s%c\n", key); 306*7c478bd9Sstevel@tonic-gate switch (skey) { 307*7c478bd9Sstevel@tonic-gate case MTS_TYPE: 308*7c478bd9Sstevel@tonic-gate respond( 309*7c478bd9Sstevel@tonic-gate (offset_t)mtget.mt_type, 310*7c478bd9Sstevel@tonic-gate saverr); 311*7c478bd9Sstevel@tonic-gate break; 312*7c478bd9Sstevel@tonic-gate case MTS_DSREG: 313*7c478bd9Sstevel@tonic-gate respond( 314*7c478bd9Sstevel@tonic-gate (offset_t)mtget.mt_dsreg, 315*7c478bd9Sstevel@tonic-gate saverr); 316*7c478bd9Sstevel@tonic-gate break; 317*7c478bd9Sstevel@tonic-gate case MTS_ERREG: 318*7c478bd9Sstevel@tonic-gate respond( 319*7c478bd9Sstevel@tonic-gate (offset_t)mtget.mt_erreg, 320*7c478bd9Sstevel@tonic-gate saverr); 321*7c478bd9Sstevel@tonic-gate break; 322*7c478bd9Sstevel@tonic-gate case MTS_RESID: 323*7c478bd9Sstevel@tonic-gate respond( 324*7c478bd9Sstevel@tonic-gate (offset_t)mtget.mt_resid, 325*7c478bd9Sstevel@tonic-gate saverr); 326*7c478bd9Sstevel@tonic-gate break; 327*7c478bd9Sstevel@tonic-gate case MTS_FILENO: 328*7c478bd9Sstevel@tonic-gate respond( 329*7c478bd9Sstevel@tonic-gate (offset_t)mtget.mt_fileno, 330*7c478bd9Sstevel@tonic-gate saverr); 331*7c478bd9Sstevel@tonic-gate break; 332*7c478bd9Sstevel@tonic-gate case MTS_BLKNO: 333*7c478bd9Sstevel@tonic-gate respond( 334*7c478bd9Sstevel@tonic-gate (offset_t)mtget.mt_blkno, 335*7c478bd9Sstevel@tonic-gate saverr); 336*7c478bd9Sstevel@tonic-gate break; 337*7c478bd9Sstevel@tonic-gate case MTS_FLAGS: 338*7c478bd9Sstevel@tonic-gate respond( 339*7c478bd9Sstevel@tonic-gate (offset_t)mtget.mt_flags, 340*7c478bd9Sstevel@tonic-gate saverr); 341*7c478bd9Sstevel@tonic-gate break; 342*7c478bd9Sstevel@tonic-gate case MTS_BF: 343*7c478bd9Sstevel@tonic-gate respond((offset_t)mtget.mt_bf, 344*7c478bd9Sstevel@tonic-gate saverr); 345*7c478bd9Sstevel@tonic-gate break; 346*7c478bd9Sstevel@tonic-gate default: 347*7c478bd9Sstevel@tonic-gate respond(-1LL, EINVAL); 348*7c478bd9Sstevel@tonic-gate break; 349*7c478bd9Sstevel@tonic-gate } 350*7c478bd9Sstevel@tonic-gate } else { 351*7c478bd9Sstevel@tonic-gate respond((offset_t)sizeof (mtget), 352*7c478bd9Sstevel@tonic-gate saverr); 353*7c478bd9Sstevel@tonic-gate (void) write(1, (char *)&mtget, 354*7c478bd9Sstevel@tonic-gate sizeof (mtget)); 355*7c478bd9Sstevel@tonic-gate } 356*7c478bd9Sstevel@tonic-gate } 357*7c478bd9Sstevel@tonic-gate break; 358*7c478bd9Sstevel@tonic-gate } 359*7c478bd9Sstevel@tonic-gate 360*7c478bd9Sstevel@tonic-gate case 'W': 361*7c478bd9Sstevel@tonic-gate getstring(count, sizeof (count)); 362*7c478bd9Sstevel@tonic-gate n = (size_t)atol(count); 363*7c478bd9Sstevel@tonic-gate checkbuf(n); 364*7c478bd9Sstevel@tonic-gate DEBUG1("rmtd: W %s\n", count); 365*7c478bd9Sstevel@tonic-gate #ifdef lint 366*7c478bd9Sstevel@tonic-gate cc = 0; 367*7c478bd9Sstevel@tonic-gate #endif 368*7c478bd9Sstevel@tonic-gate for (i = 0; i < n; i += (size_t)cc) { 369*7c478bd9Sstevel@tonic-gate cc = read(0, &record[i], n - i); 370*7c478bd9Sstevel@tonic-gate if (cc <= 0) { 371*7c478bd9Sstevel@tonic-gate DEBUG1(gettext("%s: premature eof\n"), 372*7c478bd9Sstevel@tonic-gate "rmtd"); 373*7c478bd9Sstevel@tonic-gate exit(2); 374*7c478bd9Sstevel@tonic-gate } 375*7c478bd9Sstevel@tonic-gate } 376*7c478bd9Sstevel@tonic-gate (void) kill(next, RECV); 377*7c478bd9Sstevel@tonic-gate (void) sigsuspend(&tapemask); 378*7c478bd9Sstevel@tonic-gate rval = (offset_t)write(tape, record, n); 379*7c478bd9Sstevel@tonic-gate saverr = errno; 380*7c478bd9Sstevel@tonic-gate (void) kill(next, TAPE); 381*7c478bd9Sstevel@tonic-gate (void) sigsuspend(&sendmask); 382*7c478bd9Sstevel@tonic-gate respond(rval, saverr); 383*7c478bd9Sstevel@tonic-gate break; 384*7c478bd9Sstevel@tonic-gate 385*7c478bd9Sstevel@tonic-gate case 'R': 386*7c478bd9Sstevel@tonic-gate getstring(count, sizeof (count)); 387*7c478bd9Sstevel@tonic-gate n = (size_t)atol(count); 388*7c478bd9Sstevel@tonic-gate checkbuf(n); 389*7c478bd9Sstevel@tonic-gate DEBUG1("rmtd: R %s\n", count); 390*7c478bd9Sstevel@tonic-gate (void) kill(next, RECV); 391*7c478bd9Sstevel@tonic-gate (void) sigsuspend(&tapemask); 392*7c478bd9Sstevel@tonic-gate rval = (offset_t)read(tape, record, n); 393*7c478bd9Sstevel@tonic-gate saverr = errno; 394*7c478bd9Sstevel@tonic-gate (void) kill(next, TAPE); 395*7c478bd9Sstevel@tonic-gate (void) sigsuspend(&sendmask); 396*7c478bd9Sstevel@tonic-gate respond(rval, saverr); 397*7c478bd9Sstevel@tonic-gate (void) write(1, record, (size_t)rval); 398*7c478bd9Sstevel@tonic-gate break; 399*7c478bd9Sstevel@tonic-gate 400*7c478bd9Sstevel@tonic-gate default: 401*7c478bd9Sstevel@tonic-gate DEBUG2(gettext("%s: garbage command '%c'\n"), 402*7c478bd9Sstevel@tonic-gate "rmtd", key); 403*7c478bd9Sstevel@tonic-gate /*FALLTHROUGH*/ 404*7c478bd9Sstevel@tonic-gate 405*7c478bd9Sstevel@tonic-gate case 'C': 406*7c478bd9Sstevel@tonic-gate case 'O': 407*7c478bd9Sstevel@tonic-gate /* rendezvous back into a single process */ 408*7c478bd9Sstevel@tonic-gate if (setjmp(sjbuf) == 0 || getpid() != parent) { 409*7c478bd9Sstevel@tonic-gate (void) sigsuspend(&tapemask); 410*7c478bd9Sstevel@tonic-gate (void) sigsuspend(&sendmask); 411*7c478bd9Sstevel@tonic-gate (void) kill(parent, key == 'O' ? OPEN : 412*7c478bd9Sstevel@tonic-gate key == 'C' ? CLOSE : ERROR); 413*7c478bd9Sstevel@tonic-gate (void) sigemptyset(&newmask); 414*7c478bd9Sstevel@tonic-gate (void) sigsuspend(&newmask); 415*7c478bd9Sstevel@tonic-gate } 416*7c478bd9Sstevel@tonic-gate while (children > 0) { 417*7c478bd9Sstevel@tonic-gate (void) kill(childpid[--children], SIGKILL); 418*7c478bd9Sstevel@tonic-gate while (wait(NULL) != childpid[children]) 419*7c478bd9Sstevel@tonic-gate ; 420*7c478bd9Sstevel@tonic-gate } 421*7c478bd9Sstevel@tonic-gate next = parent; 422*7c478bd9Sstevel@tonic-gate if (key == 'C') { 423*7c478bd9Sstevel@tonic-gate getstring(device, sizeof (device)); 424*7c478bd9Sstevel@tonic-gate DEBUG1("rmtd: C %s\n", device); 425*7c478bd9Sstevel@tonic-gate rval = (offset_t)close(tape); 426*7c478bd9Sstevel@tonic-gate respond(rval, errno); 427*7c478bd9Sstevel@tonic-gate (void) kill(parent, TAPE); 428*7c478bd9Sstevel@tonic-gate (void) kill(parent, SEND); 429*7c478bd9Sstevel@tonic-gate continue; 430*7c478bd9Sstevel@tonic-gate } 431*7c478bd9Sstevel@tonic-gate if (key != 'O') /* garbage command */ 432*7c478bd9Sstevel@tonic-gate exit(3); 433*7c478bd9Sstevel@tonic-gate (void) close(tape); 434*7c478bd9Sstevel@tonic-gate getstring(device, sizeof (device)); 435*7c478bd9Sstevel@tonic-gate getstring(mode, sizeof (mode)); 436*7c478bd9Sstevel@tonic-gate DEBUG2("rmtd: O %s %s\n", device, mode); 437*7c478bd9Sstevel@tonic-gate /* 438*7c478bd9Sstevel@tonic-gate * Due to incompatibilities in the 439*7c478bd9Sstevel@tonic-gate * assignment of mode bits between 440*7c478bd9Sstevel@tonic-gate * BSD and System V, we strip all 441*7c478bd9Sstevel@tonic-gate * but the read/write bits. However, 442*7c478bd9Sstevel@tonic-gate * we also want to handle things larger 443*7c478bd9Sstevel@tonic-gate * than 2GB, so we also force O_LARGEFILE. 444*7c478bd9Sstevel@tonic-gate */ 445*7c478bd9Sstevel@tonic-gate tape = open(device, O_LARGEFILE | 446*7c478bd9Sstevel@tonic-gate (atoi(mode) & (O_RDONLY|O_WRONLY|O_RDWR))); 447*7c478bd9Sstevel@tonic-gate respond((offset_t)tape, errno); 448*7c478bd9Sstevel@tonic-gate if (tape >= 0) /* fork off */ 449*7c478bd9Sstevel@tonic-gate while (children < MAXCHILD && 450*7c478bd9Sstevel@tonic-gate (childpid[children] = fork()) > 0) 451*7c478bd9Sstevel@tonic-gate next = childpid[children++]; 452*7c478bd9Sstevel@tonic-gate if (next == parent) { 453*7c478bd9Sstevel@tonic-gate (void) kill(parent, RECV); 454*7c478bd9Sstevel@tonic-gate (void) kill(parent, TAPE); 455*7c478bd9Sstevel@tonic-gate (void) kill(parent, SEND); 456*7c478bd9Sstevel@tonic-gate } 457*7c478bd9Sstevel@tonic-gate (void) sigsuspend(&cmdmask); 458*7c478bd9Sstevel@tonic-gate continue; 459*7c478bd9Sstevel@tonic-gate } 460*7c478bd9Sstevel@tonic-gate (void) kill(next, SEND); 461*7c478bd9Sstevel@tonic-gate (void) sigsuspend(&cmdmask); 462*7c478bd9Sstevel@tonic-gate } 463*7c478bd9Sstevel@tonic-gate (void) kill(next, RECV); 464*7c478bd9Sstevel@tonic-gate exit(0); 465*7c478bd9Sstevel@tonic-gate #ifdef lint 466*7c478bd9Sstevel@tonic-gate return (0); 467*7c478bd9Sstevel@tonic-gate #endif 468*7c478bd9Sstevel@tonic-gate } 469*7c478bd9Sstevel@tonic-gate 470*7c478bd9Sstevel@tonic-gate static void 471*7c478bd9Sstevel@tonic-gate respond(rval, Errno) 472*7c478bd9Sstevel@tonic-gate offset_t rval; 473*7c478bd9Sstevel@tonic-gate int Errno; 474*7c478bd9Sstevel@tonic-gate { 475*7c478bd9Sstevel@tonic-gate char resp[SSIZE]; 476*7c478bd9Sstevel@tonic-gate char *errstr = strerror(Errno); 477*7c478bd9Sstevel@tonic-gate 478*7c478bd9Sstevel@tonic-gate if (rval < 0) { 479*7c478bd9Sstevel@tonic-gate (void) snprintf(resp, SSIZE, "E%d\n%s\n", Errno, errstr); 480*7c478bd9Sstevel@tonic-gate DEBUG2("rmtd: E %d (%s)\n", Errno, errstr); 481*7c478bd9Sstevel@tonic-gate } else { 482*7c478bd9Sstevel@tonic-gate (void) snprintf(resp, SSIZE, "A%lld\n", rval); 483*7c478bd9Sstevel@tonic-gate DEBUG1("rmtd: A %lld\n", rval); 484*7c478bd9Sstevel@tonic-gate } 485*7c478bd9Sstevel@tonic-gate resp[SSIZE - 1] = '\0'; 486*7c478bd9Sstevel@tonic-gate (void) write(1, resp, (int)strlen(resp)); 487*7c478bd9Sstevel@tonic-gate } 488*7c478bd9Sstevel@tonic-gate 489*7c478bd9Sstevel@tonic-gate static void 490*7c478bd9Sstevel@tonic-gate getstring(cp, size) 491*7c478bd9Sstevel@tonic-gate char *cp; 492*7c478bd9Sstevel@tonic-gate size_t size; 493*7c478bd9Sstevel@tonic-gate { 494*7c478bd9Sstevel@tonic-gate char *limit = cp + size - 1; 495*7c478bd9Sstevel@tonic-gate 496*7c478bd9Sstevel@tonic-gate cp--; /* nullify first increment */ 497*7c478bd9Sstevel@tonic-gate do { 498*7c478bd9Sstevel@tonic-gate cp++; 499*7c478bd9Sstevel@tonic-gate if (read(0, cp, 1) != 1) 500*7c478bd9Sstevel@tonic-gate exit(0); 501*7c478bd9Sstevel@tonic-gate } while ((*cp != '\n') && (cp < limit)); 502*7c478bd9Sstevel@tonic-gate *cp = '\0'; 503*7c478bd9Sstevel@tonic-gate } 504*7c478bd9Sstevel@tonic-gate 505*7c478bd9Sstevel@tonic-gate static void 506*7c478bd9Sstevel@tonic-gate checkbuf(size) 507*7c478bd9Sstevel@tonic-gate size_t size; 508*7c478bd9Sstevel@tonic-gate { 509*7c478bd9Sstevel@tonic-gate if (size <= maxrecsize) 510*7c478bd9Sstevel@tonic-gate return; 511*7c478bd9Sstevel@tonic-gate if (record != 0) 512*7c478bd9Sstevel@tonic-gate free(record); 513*7c478bd9Sstevel@tonic-gate if ((record = malloc(size)) == NULL) { 514*7c478bd9Sstevel@tonic-gate DEBUG2(gettext("%s: cannot allocate %ld-byte buffer\n"), 515*7c478bd9Sstevel@tonic-gate size, "rmtd"); 516*7c478bd9Sstevel@tonic-gate exit(4); 517*7c478bd9Sstevel@tonic-gate } 518*7c478bd9Sstevel@tonic-gate maxrecsize = size; 519*7c478bd9Sstevel@tonic-gate } 520