xref: /titanic_52/usr/src/cmd/backup/lib/rmtlib.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
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