1 #define	USE_REMOTE
2 /* @(#)scsi-remote.c	1.16 04/08/24 Copyright 1990,2000-2003 J. Schilling */
3 #ifndef lint
4 static	char __sccsid[] =
5 	"@(#)scsi-remote.c	1.16 04/08/24 Copyright 1990,2000-2003 J. Schilling";
6 #endif
7 /*
8  *	Remote SCSI user level command transport routines
9  *
10  *	Warning: you may change this source, but if you do that
11  *	you need to change the _scg_version and _scg_auth* string below.
12  *	You may not return "schily" for an SCG_AUTHOR request anymore.
13  *	Choose your name instead of "schily" and make clear that the version
14  *	string is related to a modified source.
15  *
16  *	Copyright (c) 1990,2000-2003 J. Schilling
17  */
18 /*
19  * This program is free software; you can redistribute it and/or modify
20  * it under the terms of the GNU General Public License as published by
21  * the Free Software Foundation; either version 2, or (at your option)
22  * any later version.
23  *
24  * This program is distributed in the hope that it will be useful,
25  * but WITHOUT ANY WARRANTY; without even the implied warranty of
26  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
27  * GNU General Public License for more details.
28  *
29  * You should have received a copy of the GNU General Public License along with
30  * this program; see the file COPYING.  If not, write to the Free Software
31  * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
32  */
33 
34 #include <mconfig.h>
35 
36 #if !defined(HAVE_FORK) || !defined(HAVE_SOCKETPAIR) || !defined(HAVE_DUP2)
37 #undef	USE_RCMD_RSH
38 #endif
39 /*
40  * We may work without getservbyname() if we restructure the code not to
41  * use the port number if we only use _rcmdrsh().
42  */
43 #if !defined(HAVE_GETSERVBYNAME)
44 #undef	USE_REMOTE				/* Cannot get rcmd() port # */
45 #endif
46 #if (!defined(HAVE_NETDB_H) || !defined(HAVE_RCMD)) && !defined(USE_RCMD_RSH)
47 #undef	USE_REMOTE				/* There is no rcmd() */
48 #endif
49 
50 #ifdef	USE_REMOTE
51 #include <stdio.h>
52 #include <sys/types.h>
53 #include <fctldefs.h>
54 #ifdef	HAVE_SYS_SOCKET_H
55 #include <sys/socket.h>
56 #endif
57 #include <errno.h>
58 #include <signal.h>
59 #ifdef	HAVE_NETDB_H
60 #include <netdb.h>
61 #endif
62 #ifdef	HAVE_PWD_H
63 #include <pwd.h>
64 #endif
65 #include <standard.h>
66 #include <stdxlib.h>
67 #include <unixstd.h>
68 #include <strdefs.h>
69 #include <schily.h>
70 
71 #include <scg/scgcmd.h>
72 #include <scg/scsitransp.h>
73 
74 #if	defined(SIGDEFER) || defined(SVR4)
75 #define	signal	sigset
76 #endif
77 
78 /*
79  * On Cygwin, there are no privilleged ports.
80  * On UNIX, rcmd() uses privilleged port that only work for root.
81  */
82 #ifdef	IS_CYGWIN
83 #define	privport_ok()	(1)
84 #else
85 #define	privport_ok()	(geteuid() == 0)
86 #endif
87 
88 #define	CMD_SIZE	80
89 
90 #define	MAX_SCG		16	/* Max # of SCSI controllers */
91 #define	MAX_TGT		16
92 #define	MAX_LUN		8
93 
94 /*extern	BOOL	debug;*/
95 LOCAL	BOOL	debug = 1;
96 
97 LOCAL	char	_scg_trans_version[] = "remote-1.16";	/* The version for remote SCSI	*/
98 LOCAL	char	_scg_auth_schily[]	= "schily";	/* The author for this module	*/
99 
100 LOCAL	int	scgo_rsend		__PR((SCSI *scgp));
101 LOCAL	char *	scgo_rversion		__PR((SCSI *scgp, int what));
102 LOCAL	int	scgo_rhelp		__PR((SCSI *scgp, FILE *f));
103 LOCAL	int	scgo_ropen		__PR((SCSI *scgp, char *device));
104 LOCAL	int	scgo_rclose		__PR((SCSI *scgp));
105 LOCAL	long	scgo_rmaxdma		__PR((SCSI *scgp, long amt));
106 LOCAL	void *	scgo_rgetbuf		__PR((SCSI *scgp, long amt));
107 LOCAL	void	scgo_rfreebuf		__PR((SCSI *scgp));
108 LOCAL	BOOL	scgo_rhavebus		__PR((SCSI *scgp, int busno));
109 LOCAL	int	scgo_rfileno		__PR((SCSI *scgp, int busno, int tgt, int tlun));
110 LOCAL	int	scgo_rinitiator_id	__PR((SCSI *scgp));
111 LOCAL	int	scgo_risatapi		__PR((SCSI *scgp));
112 LOCAL	int	scgo_rreset		__PR((SCSI *scgp, int what));
113 
114 /*
115  * XXX We should rethink the fd parameter now that we introduced
116  * XXX the rscsirchar() function and most access of remfd is done
117  * XXX via scglocal(scgp)->remfd.
118  */
119 LOCAL	void	rscsiabrt		__PR((int sig));
120 LOCAL	int	rscsigetconn		__PR((SCSI *scgp, char *host));
121 LOCAL	char	*rscsiversion		__PR((SCSI *scgp, int fd, int what));
122 LOCAL	int	rscsiopen		__PR((SCSI *scgp, int fd, char *fname));
123 LOCAL	int	rscsiclose		__PR((SCSI *scgp, int fd));
124 LOCAL	int	rscsimaxdma		__PR((SCSI *scgp, int fd, long amt));
125 LOCAL	int	rscsigetbuf		__PR((SCSI *scgp, int fd, long amt));
126 LOCAL	int	rscsifreebuf		__PR((SCSI *scgp, int fd));
127 LOCAL	int	rscsihavebus		__PR((SCSI *scgp, int fd, int bus));
128 LOCAL	int	rscsifileno		__PR((SCSI *scgp, int fd, int busno, int tgt, int tlun));
129 LOCAL	int	rscsiinitiator_id	__PR((SCSI *scgp, int fd));
130 LOCAL	int	rscsiisatapi		__PR((SCSI *scgp, int fd));
131 LOCAL	int	rscsireset		__PR((SCSI *scgp, int fd, int what));
132 LOCAL	int	rscsiscmd		__PR((SCSI *scgp, int fd, struct scg_cmd *sp));
133 LOCAL	int	rscsifillrbuf		__PR((SCSI *scgp));
134 LOCAL	int	rscsirchar		__PR((SCSI *scgp, char *cp));
135 LOCAL	int	rscsireadbuf		__PR((SCSI *scgp, int fd, char *buf, int count));
136 LOCAL	void	rscsivoidarg		__PR((SCSI *scgp, int fd, int count));
137 LOCAL	int	rscsicmd		__PR((SCSI *scgp, int fd, char *name, char *cbuf));
138 LOCAL	void	rscsisendcmd		__PR((SCSI *scgp, int fd, char *name, char *cbuf));
139 LOCAL	int	rscsigetline		__PR((SCSI *scgp, int fd, char *line, int count));
140 LOCAL	int	rscsireadnum		__PR((SCSI *scgp, int fd));
141 LOCAL	int	rscsigetstatus		__PR((SCSI *scgp, int fd, char *name));
142 LOCAL	int	rscsiaborted		__PR((SCSI *scgp, int fd));
143 #ifdef	USE_RCMD_RSH
144 LOCAL	int	_rcmdrsh		__PR((char **ahost, int inport,
145 						const char *locuser,
146 						const char *remuser,
147 						const char *cmd,
148 						const char *rsh));
149 #endif
150 
151 /*--------------------------------------------------------------------------*/
152 
153 #define	READBUF_SIZE	128
154 
155 struct scg_local {
156 	int	remfd;
157 	char	readbuf[READBUF_SIZE];
158 	char	*readbptr;
159 	int	readbcnt;
160 	BOOL	isopen;
161 	int	rsize;
162 	int	wsize;
163 	char	*v_version;
164 	char	*v_author;
165 	char	*v_sccs_id;
166 };
167 
168 
169 #define	scglocal(p)	((struct scg_local *)((p)->local))
170 
171 scg_ops_t remote_ops = {
172 	scgo_rsend,		/* "S" end	*/
173 	scgo_rversion,		/* "V" ersion	*/
174 	scgo_rhelp,		/*     help	*/
175 	scgo_ropen,		/* "O" pen	*/
176 	scgo_rclose,		/* "C" lose	*/
177 	scgo_rmaxdma,		/* "D" MA	*/
178 	scgo_rgetbuf,		/* "M" alloc	*/
179 	scgo_rfreebuf,		/* "F" free	*/
180 	scgo_rhavebus,		/* "B" us	*/
181 	scgo_rfileno,		/* "T" arget	*/
182 	scgo_rinitiator_id,	/* "I" nitiator	*/
183 	scgo_risatapi,		/* "A" tapi	*/
184 	scgo_rreset,		/* "R" eset	*/
185 };
186 
187 /*
188  * Return our ops ptr.
189  */
190 scg_ops_t *
scg_remote()191 scg_remote()
192 {
193 	return (&remote_ops);
194 }
195 
196 /*
197  * Return version information for the low level SCSI transport code.
198  * This has been introduced to make it easier to trace down problems
199  * in applications.
200  */
201 LOCAL char *
scgo_rversion(scgp,what)202 scgo_rversion(scgp, what)
203 	SCSI	*scgp;
204 	int	what;
205 {
206 	int	f;
207 
208 	if (scgp->local == NULL)
209 		return ((char *)0);
210 
211 	f = scglocal(scgp)->remfd;
212 	if (scgp != (SCSI *)0) {
213 		switch (what) {
214 
215 		case SCG_VERSION:
216 			return (_scg_trans_version);
217 		/*
218 		 * If you changed this source, you are not allowed to
219 		 * return "schily" for the SCG_AUTHOR request.
220 		 */
221 		case SCG_AUTHOR:
222 			return (_scg_auth_schily);
223 		case SCG_SCCS_ID:
224 			return (__sccsid);
225 
226 		case SCG_RVERSION:
227 			if (scglocal(scgp)->v_version == NULL)
228 				scglocal(scgp)->v_version = rscsiversion(scgp, f, SCG_VERSION);
229 			return (scglocal(scgp)->v_version);
230 		/*
231 		 * If you changed this source, you are not allowed to
232 		 * return "schily" for the SCG_AUTHOR request.
233 		 */
234 		case SCG_RAUTHOR:
235 			if (scglocal(scgp)->v_author == NULL)
236 				scglocal(scgp)->v_author = rscsiversion(scgp, f, SCG_AUTHOR);
237 			return (scglocal(scgp)->v_author);
238 		case SCG_RSCCS_ID:
239 			if (scglocal(scgp)->v_sccs_id == NULL)
240 				scglocal(scgp)->v_sccs_id = rscsiversion(scgp, f, SCG_SCCS_ID);
241 			return (scglocal(scgp)->v_sccs_id);
242 		}
243 	}
244 	return ((char *)0);
245 }
246 
247 LOCAL int
scgo_rhelp(scgp,f)248 scgo_rhelp(scgp, f)
249 	SCSI	*scgp;
250 	FILE	*f;
251 {
252 	__scg_help(f, "RSCSI", "Remote SCSI",
253 		"REMOTE:", "rscsi@host:bus,target,lun", "REMOTE:rscsi@host:1,2,0", TRUE, FALSE);
254 	return (0);
255 }
256 
257 LOCAL int
scgo_ropen(scgp,device)258 scgo_ropen(scgp, device)
259 	SCSI	*scgp;
260 	char	*device;
261 {
262 		int	busno	= scg_scsibus(scgp);
263 		int	tgt	= scg_target(scgp);
264 		int	tlun	= scg_lun(scgp);
265 	register int	f;
266 	register int	nopen = 0;
267 	char		devname[128];
268 	char		*p;
269 
270 	if (scgp->overbose)
271 		error("Warning: Using remote SCSI interface.\n");
272 
273 	if (busno >= MAX_SCG || tgt >= MAX_TGT || tlun >= MAX_LUN) {
274 		errno = EINVAL;
275 		if (scgp->errstr)
276 			js_snprintf(scgp->errstr, SCSI_ERRSTR_SIZE,
277 			"Illegal value for busno, target or lun '%d,%d,%d'",
278 			busno, tgt, tlun);
279 
280 		return (-1);
281 	}
282 	if (scgp->local == NULL) {
283 		scgp->local = malloc(sizeof (struct scg_local));
284 		if (scgp->local == NULL)
285 			return (0);
286 		scglocal(scgp)->remfd = -1;
287 		scglocal(scgp)->readbptr = scglocal(scgp)->readbuf;
288 		scglocal(scgp)->readbcnt = 0;
289 		scglocal(scgp)->isopen = FALSE;
290 		scglocal(scgp)->rsize = 0;
291 		scglocal(scgp)->wsize = 0;
292 		scglocal(scgp)->v_version = NULL;
293 		scglocal(scgp)->v_author  = NULL;
294 		scglocal(scgp)->v_sccs_id = NULL;
295 	}
296 
297 	if (device == NULL || (strncmp(device, "REMOTE", 6) != 0) ||
298 				(device = strchr(device, ':')) == NULL) {
299 		if (scgp->errstr)
300 			js_snprintf(scgp->errstr, SCSI_ERRSTR_SIZE,
301 				"Illegal remote device syntax");
302 		return (-1);
303 	}
304 	device++;
305 	/*
306 	 * Save non user@host:device
307 	 */
308 	js_snprintf(devname, sizeof (devname), "%s", device);
309 
310 	if ((p = strchr(devname, ':')) != NULL)
311 		*p++ = '\0';
312 
313 	f = rscsigetconn(scgp, devname);
314 	if (f < 0) {
315 		if (scgp->errstr)
316 			js_snprintf(scgp->errstr, SCSI_ERRSTR_SIZE,
317 				"Cannot get connection to remote host");
318 		return (-1);
319 	}
320 	scglocal(scgp)->remfd = f;
321 	debug = scgp->debug;
322 	if (rscsiopen(scgp, f, p) >= 0) {
323 		nopen++;
324 		scglocal(scgp)->isopen = TRUE;
325 	}
326 	return (nopen);
327 }
328 
329 LOCAL int
scgo_rclose(scgp)330 scgo_rclose(scgp)
331 	SCSI	*scgp;
332 {
333 	register int	f;
334 		int	ret;
335 
336 	if (scgp->local == NULL)
337 		return (-1);
338 
339 	if (scglocal(scgp)->v_version != NULL) {
340 		free(scglocal(scgp)->v_version);
341 		scglocal(scgp)->v_version = NULL;
342 	}
343 	if (scglocal(scgp)->v_author != NULL) {
344 		free(scglocal(scgp)->v_author);
345 		scglocal(scgp)->v_author  = NULL;
346 	}
347 	if (scglocal(scgp)->v_sccs_id != NULL) {
348 		free(scglocal(scgp)->v_sccs_id);
349 		scglocal(scgp)->v_sccs_id = NULL;
350 	}
351 
352 	f = scglocal(scgp)->remfd;
353 	if (f < 0 || !scglocal(scgp)->isopen)
354 		return (0);
355 	ret = rscsiclose(scgp, f);
356 	scglocal(scgp)->isopen = FALSE;
357 	close(f);
358 	scglocal(scgp)->remfd = -1;
359 	return (ret);
360 }
361 
362 LOCAL long
scgo_rmaxdma(scgp,amt)363 scgo_rmaxdma(scgp, amt)
364 	SCSI	*scgp;
365 	long	amt;
366 {
367 	if (scgp->local == NULL)
368 		return (-1L);
369 
370 	return (rscsimaxdma(scgp, scglocal(scgp)->remfd, amt));
371 }
372 
373 LOCAL void *
scgo_rgetbuf(scgp,amt)374 scgo_rgetbuf(scgp, amt)
375 	SCSI	*scgp;
376 	long	amt;
377 {
378 	int	ret;
379 
380 	if (scgp->local == NULL)
381 		return ((void *)0);
382 
383 	ret = rscsigetbuf(scgp, scglocal(scgp)->remfd, amt);
384 	if (ret < 0)
385 		return ((void *)0);
386 
387 #ifdef	HAVE_VALLOC
388 	scgp->bufbase = (void *)valloc((size_t)amt);
389 #else
390 	scgp->bufbase = (void *)malloc((size_t)amt);
391 #endif
392 	if (scgp->bufbase == NULL) {
393 		scgo_rfreebuf(scgp);
394 		return ((void *)0);
395 	}
396 	return (scgp->bufbase);
397 }
398 
399 LOCAL void
scgo_rfreebuf(scgp)400 scgo_rfreebuf(scgp)
401 	SCSI	*scgp;
402 {
403 	int	f;
404 
405 	if (scgp->bufbase)
406 		free(scgp->bufbase);
407 	scgp->bufbase = NULL;
408 
409 	if (scgp->local == NULL)
410 		return;
411 
412 	f = scglocal(scgp)->remfd;
413 	if (f < 0 || !scglocal(scgp)->isopen)
414 		return;
415 	rscsifreebuf(scgp, f);
416 }
417 
418 LOCAL BOOL
scgo_rhavebus(scgp,busno)419 scgo_rhavebus(scgp, busno)
420 	SCSI	*scgp;
421 	int	busno;
422 {
423 	if (scgp->local == NULL || busno < 0 || busno >= MAX_SCG)
424 		return (FALSE);
425 
426 	return (rscsihavebus(scgp, scglocal(scgp)->remfd, busno));
427 }
428 
429 LOCAL int
scgo_rfileno(scgp,busno,tgt,tlun)430 scgo_rfileno(scgp, busno, tgt, tlun)
431 	SCSI	*scgp;
432 	int	busno;
433 	int	tgt;
434 	int	tlun;
435 {
436 	int	f;
437 
438 	if (scgp->local == NULL ||
439 	    busno < 0 || busno >= MAX_SCG ||
440 	    tgt < 0 || tgt >= MAX_TGT ||
441 	    tlun < 0 || tlun >= MAX_LUN)
442 		return (-1);
443 
444 	f = scglocal(scgp)->remfd;
445 	if (f < 0 || !scglocal(scgp)->isopen)
446 		return (-1);
447 	return (rscsifileno(scgp, f, busno, tgt, tlun));
448 }
449 
450 LOCAL int
scgo_rinitiator_id(scgp)451 scgo_rinitiator_id(scgp)
452 	SCSI	*scgp;
453 {
454 	if (scgp->local == NULL)
455 		return (-1);
456 
457 	return (rscsiinitiator_id(scgp, scglocal(scgp)->remfd));
458 }
459 
460 LOCAL int
scgo_risatapi(scgp)461 scgo_risatapi(scgp)
462 	SCSI	*scgp;
463 {
464 	if (scgp->local == NULL)
465 		return (-1);
466 
467 	return (rscsiisatapi(scgp, scglocal(scgp)->remfd));
468 }
469 
470 LOCAL int
scgo_rreset(scgp,what)471 scgo_rreset(scgp, what)
472 	SCSI	*scgp;
473 	int	what;
474 {
475 	if (scgp->local == NULL)
476 		return (-1);
477 
478 	return (rscsireset(scgp, scglocal(scgp)->remfd, what));
479 }
480 
481 LOCAL int
scgo_rsend(scgp)482 scgo_rsend(scgp)
483 	SCSI		*scgp;
484 {
485 	struct scg_cmd	*sp = scgp->scmd;
486 	int		ret;
487 
488 	if (scgp->local == NULL)
489 		return (-1);
490 
491 	if (scgp->fd < 0) {
492 		sp->error = SCG_FATAL;
493 		return (0);
494 	}
495 	ret = rscsiscmd(scgp, scglocal(scgp)->remfd, scgp->scmd);
496 
497 	return (ret);
498 }
499 
500 /*--------------------------------------------------------------------------*/
501 LOCAL void
rscsiabrt(sig)502 rscsiabrt(sig)
503 	int	sig;
504 {
505 	rscsiaborted((SCSI *)0, -1);
506 }
507 
508 LOCAL int
rscsigetconn(scgp,host)509 rscsigetconn(scgp, host)
510 	SCSI	*scgp;
511 	char	*host;
512 {
513 	static	struct servent	*sp = 0;
514 	static	struct passwd	*pw = 0;
515 		char		*name = "root";
516 		char		*p;
517 		char		*rscsi;
518 		char		*rsh;
519 		int		rscsisock;
520 		char		*rscsipeer;
521 		char		rscsiuser[128];
522 
523 
524 	signal(SIGPIPE, rscsiabrt);
525 	if (sp == 0) {
526 		sp = getservbyname("shell", "tcp");
527 		if (sp == 0) {
528 			comerrno(EX_BAD, "shell/tcp: unknown service\n");
529 			/* NOTREACHED */
530 		}
531 		pw = getpwuid(getuid());
532 		if (pw == 0) {
533 			comerrno(EX_BAD, "who are you? No passwd entry found.\n");
534 			/* NOTREACHED */
535 		}
536 	}
537 	if ((p = strchr(host, '@')) != NULL) {
538 		size_t d = p - host;
539 
540 		if (d > sizeof (rscsiuser))
541 			d = sizeof (rscsiuser);
542 		js_snprintf(rscsiuser, sizeof (rscsiuser), "%.*s", (int)d, host);
543 		name = rscsiuser;
544 		host = &p[1];
545 	} else {
546 		name = pw->pw_name;
547 	}
548 	if (scgp->debug > 0)
549 		errmsgno(EX_BAD, "locuser: '%s' rscsiuser: '%s' host: '%s'\n",
550 						pw->pw_name, name, host);
551 	rscsipeer = host;
552 
553 	if ((rscsi = getenv("RSCSI")) == NULL)
554 		rscsi = "/opt/schily/sbin/rscsi";
555 	rsh = getenv("RSH");
556 
557 #ifdef	USE_RCMD_RSH
558 	if (!privport_ok() || rsh != NULL)
559 		rscsisock = _rcmdrsh(&rscsipeer, (unsigned short)sp->s_port,
560 					pw->pw_name, name, rscsi, rsh);
561 	else
562 #endif
563 #ifdef	HAVE_RCMD
564 		rscsisock = rcmd(&rscsipeer, (unsigned short)sp->s_port,
565 					pw->pw_name, name, rscsi, 0);
566 #else
567 		rscsisock = _rcmdrsh(&rscsipeer, (unsigned short)sp->s_port,
568 					pw->pw_name, name, rscsi, rsh);
569 #endif
570 
571 	return (rscsisock);
572 }
573 
574 LOCAL char *
rscsiversion(scgp,fd,what)575 rscsiversion(scgp, fd, what)
576 	SCSI	*scgp;
577 	int	fd;
578 	int	what;
579 {
580 	char	cbuf[CMD_SIZE];
581 	char	*p;
582 	int	ret;
583 
584 	js_snprintf(cbuf, sizeof (cbuf), "V%d\n", what);
585 	ret = rscsicmd(scgp, fd, "version", cbuf);
586 	p = malloc(ret);
587 	if (p == NULL)
588 		return (p);
589 	rscsireadbuf(scgp, fd, p, ret);
590 	return (p);
591 }
592 
593 LOCAL int
rscsiopen(scgp,fd,fname)594 rscsiopen(scgp, fd, fname)
595 	SCSI	*scgp;
596 	int	fd;
597 	char	*fname;
598 {
599 	char	cbuf[CMD_SIZE];
600 	int	ret;
601 	int	bus;
602 	int	chan;
603 	int	tgt;
604 	int	lun;
605 
606 	js_snprintf(cbuf, sizeof (cbuf), "O%s\n", fname?fname:"");
607 	ret = rscsicmd(scgp, fd, "open", cbuf);
608 	if (ret < 0)
609 		return (ret);
610 
611 	bus = rscsireadnum(scgp, fd);
612 	chan = rscsireadnum(scgp, fd);
613 	tgt = rscsireadnum(scgp, fd);
614 	lun = rscsireadnum(scgp, fd);
615 
616 	scg_settarget(scgp, bus, tgt, lun);
617 	return (ret);
618 }
619 
620 LOCAL int
rscsiclose(scgp,fd)621 rscsiclose(scgp, fd)
622 	SCSI	*scgp;
623 	int	fd;
624 {
625 	return (rscsicmd(scgp, fd, "close", "C\n"));
626 }
627 
628 LOCAL int
rscsimaxdma(scgp,fd,amt)629 rscsimaxdma(scgp, fd, amt)
630 	SCSI	*scgp;
631 	int	fd;
632 	long	amt;
633 {
634 	char	cbuf[CMD_SIZE];
635 
636 	js_snprintf(cbuf, sizeof (cbuf), "D%ld\n", amt);
637 	return (rscsicmd(scgp, fd, "maxdma", cbuf));
638 }
639 
640 LOCAL int
rscsigetbuf(scgp,fd,amt)641 rscsigetbuf(scgp, fd, amt)
642 	SCSI	*scgp;
643 	int	fd;
644 	long	amt;
645 {
646 	char	cbuf[CMD_SIZE];
647 	int	size;
648 	int	ret;
649 
650 	js_snprintf(cbuf, sizeof (cbuf), "M%ld\n", amt);
651 	ret = rscsicmd(scgp, fd, "getbuf", cbuf);
652 	if (ret < 0)
653 		return (ret);
654 
655 	size = ret + 1024;	/* Add protocol overhead */
656 
657 #ifdef	SO_SNDBUF
658 	if (size > scglocal(scgp)->wsize) while (size > 512 &&
659 		setsockopt(fd, SOL_SOCKET, SO_SNDBUF,
660 					(char *)&size, sizeof (size)) < 0) {
661 		size -= 512;
662 	}
663 	if (size > scglocal(scgp)->wsize) {
664 		scglocal(scgp)->wsize = size;
665 		if (scgp->debug > 0)
666 			errmsgno(EX_BAD, "sndsize: %d\n", size);
667 	}
668 #endif
669 #ifdef	SO_RCVBUF
670 	if (size > scglocal(scgp)->rsize) while (size > 512 &&
671 		setsockopt(fd, SOL_SOCKET, SO_RCVBUF,
672 					(char *)&size, sizeof (size)) < 0) {
673 		size -= 512;
674 	}
675 	if (size > scglocal(scgp)->rsize) {
676 		scglocal(scgp)->rsize = size;
677 		if (scgp->debug > 0)
678 			errmsgno(EX_BAD, "rcvsize: %d\n", size);
679 	}
680 #endif
681 	return (ret);
682 }
683 
684 LOCAL int
rscsifreebuf(scgp,fd)685 rscsifreebuf(scgp, fd)
686 	SCSI	*scgp;
687 	int	fd;
688 {
689 	return (rscsicmd(scgp, fd, "freebuf", "F\n"));
690 }
691 
692 LOCAL int
rscsihavebus(scgp,fd,busno)693 rscsihavebus(scgp, fd, busno)
694 	SCSI	*scgp;
695 	int	fd;
696 	int	busno;
697 {
698 	char	cbuf[2*CMD_SIZE];
699 
700 	js_snprintf(cbuf, sizeof (cbuf), "B%d\n%d\n",
701 		busno,
702 		0);
703 	return (rscsicmd(scgp, fd, "havebus", cbuf));
704 }
705 
706 LOCAL int
rscsifileno(scgp,fd,busno,tgt,tlun)707 rscsifileno(scgp, fd, busno, tgt, tlun)
708 	SCSI	*scgp;
709 	int	fd;
710 	int	busno;
711 	int	tgt;
712 	int	tlun;
713 {
714 	char	cbuf[3*CMD_SIZE];
715 
716 	js_snprintf(cbuf, sizeof (cbuf), "T%d\n%d\n%d\n%d\n",
717 		busno,
718 		0,
719 		tgt,
720 		tlun);
721 	return (rscsicmd(scgp, fd, "fileno", cbuf));
722 }
723 
724 LOCAL int
rscsiinitiator_id(scgp,fd)725 rscsiinitiator_id(scgp, fd)
726 	SCSI	*scgp;
727 	int	fd;
728 {
729 	return (rscsicmd(scgp, fd, "initiator id", "I\n"));
730 }
731 
732 LOCAL int
rscsiisatapi(scgp,fd)733 rscsiisatapi(scgp, fd)
734 	SCSI	*scgp;
735 	int	fd;
736 {
737 	return (rscsicmd(scgp, fd, "isatapi", "A\n"));
738 }
739 
740 LOCAL int
rscsireset(scgp,fd,what)741 rscsireset(scgp, fd, what)
742 	SCSI	*scgp;
743 	int	fd;
744 	int	what;
745 {
746 	char	cbuf[CMD_SIZE];
747 
748 	js_snprintf(cbuf, sizeof (cbuf), "R%d\n", what);
749 	return (rscsicmd(scgp, fd, "reset", cbuf));
750 }
751 
752 LOCAL int
rscsiscmd(scgp,fd,sp)753 rscsiscmd(scgp, fd, sp)
754 	SCSI	*scgp;
755 	int	fd;
756 	struct scg_cmd  *sp;
757 {
758 	char	cbuf[1600];
759 	int	ret;
760 	int	amt = 0;
761 	int	voidsize = 0;
762 
763 	ret = js_snprintf(cbuf, sizeof (cbuf), "S%d\n%d\n%d\n%d\n%d\n",
764 		sp->size, sp->flags,
765 		sp->cdb_len, sp->sense_len,
766 		sp->timeout);
767 	movebytes(sp->cdb.cmd_cdb, &cbuf[ret], sp->cdb_len);
768 	ret += sp->cdb_len;
769 
770 	if ((sp->flags & SCG_RECV_DATA) == 0 && sp->size > 0) {
771 		amt = sp->size;
772 		if ((ret + amt) <= sizeof (cbuf)) {
773 			movebytes(sp->addr, &cbuf[ret], amt);
774 			ret += amt;
775 			amt = 0;
776 		}
777 	}
778 	errno = 0;
779 	if (_nixwrite(fd, cbuf, ret) != ret)
780 		rscsiaborted(scgp, fd);
781 
782 	if (amt > 0) {
783 		if (_nixwrite(fd, sp->addr, amt) != amt)
784 			rscsiaborted(scgp, fd);
785 	}
786 
787 	ret = rscsigetstatus(scgp, fd, "sendcmd");
788 	if (ret < 0)
789 		return (ret);
790 
791 	sp->resid = sp->size - ret;
792 	sp->error = rscsireadnum(scgp, fd);
793 	sp->ux_errno = rscsireadnum(scgp, fd);
794 	*(Uchar *)&sp->scb = rscsireadnum(scgp, fd);
795 	sp->sense_count = rscsireadnum(scgp, fd);
796 
797 	if (sp->sense_count > SCG_MAX_SENSE) {
798 		voidsize = sp->sense_count - SCG_MAX_SENSE;
799 		sp->sense_count = SCG_MAX_SENSE;
800 	}
801 	if (sp->sense_count > 0) {
802 		rscsireadbuf(scgp, fd, (char *)sp->u_sense.cmd_sense, sp->sense_count);
803 		rscsivoidarg(scgp, fd, voidsize);
804 	}
805 
806 	if ((sp->flags & SCG_RECV_DATA) != 0 && ret > 0)
807 		rscsireadbuf(scgp, fd, sp->addr, ret);
808 
809 	return (0);
810 }
811 
812 LOCAL int
rscsifillrbuf(scgp)813 rscsifillrbuf(scgp)
814 	SCSI	*scgp;
815 {
816 	scglocal(scgp)->readbptr = scglocal(scgp)->readbuf;
817 
818 	return (scglocal(scgp)->readbcnt =
819 			_niread(scglocal(scgp)->remfd,
820 			    scglocal(scgp)->readbuf, READBUF_SIZE));
821 }
822 
823 LOCAL int
rscsirchar(scgp,cp)824 rscsirchar(scgp, cp)
825 	SCSI	*scgp;
826 	char	*cp;
827 {
828 	if (--(scglocal(scgp)->readbcnt) < 0) {
829 		if (rscsifillrbuf(scgp) <= 0)
830 			return (scglocal(scgp)->readbcnt);
831 		--(scglocal(scgp)->readbcnt);
832 	}
833 	*cp = *(scglocal(scgp)->readbptr)++;
834 	return (1);
835 }
836 
837 LOCAL int
rscsireadbuf(scgp,fd,buf,count)838 rscsireadbuf(scgp, fd, buf, count)
839 	SCSI	*scgp;
840 	int	fd;
841 	char	*buf;
842 	int	count;
843 {
844 	register int	n = count;
845 	register int	amt = 0;
846 	register int	cnt;
847 
848 	if (scglocal(scgp)->readbcnt > 0) {
849 		cnt = scglocal(scgp)->readbcnt;
850 		if (cnt > n)
851 			cnt = n;
852 		movebytes(scglocal(scgp)->readbptr, buf, cnt);
853 		scglocal(scgp)->readbptr += cnt;
854 		scglocal(scgp)->readbcnt -= cnt;
855 		amt += cnt;
856 	}
857 	while (amt < n) {
858 		if ((cnt = _niread(fd, &buf[amt], n - amt)) <= 0) {
859 			return (rscsiaborted(scgp, fd));
860 		}
861 		amt += cnt;
862 	}
863 	return (amt);
864 }
865 
866 LOCAL void
rscsivoidarg(scgp,fd,n)867 rscsivoidarg(scgp, fd, n)
868 	SCSI	*scgp;
869 	int	fd;
870 	register int	n;
871 {
872 	register int	i;
873 	register int	amt;
874 		char	buf[512];
875 
876 	for (i = 0; i < n; i += amt) {
877 		amt = sizeof (buf);
878 		if ((n - i) < amt)
879 			amt = n - i;
880 		rscsireadbuf(scgp, fd, buf, amt);
881 	}
882 }
883 
884 LOCAL int
rscsicmd(scgp,fd,name,cbuf)885 rscsicmd(scgp, fd, name, cbuf)
886 	SCSI	*scgp;
887 	int	fd;
888 	char	*name;
889 	char	*cbuf;
890 {
891 	rscsisendcmd(scgp, fd, name, cbuf);
892 	return (rscsigetstatus(scgp, fd, name));
893 }
894 
895 LOCAL void
rscsisendcmd(scgp,fd,name,cbuf)896 rscsisendcmd(scgp, fd, name, cbuf)
897 	SCSI	*scgp;
898 	int	fd;
899 	char	*name;
900 	char	*cbuf;
901 {
902 	int	buflen = strlen(cbuf);
903 
904 	errno = 0;
905 	if (_nixwrite(fd, cbuf, buflen) != buflen)
906 		rscsiaborted(scgp, fd);
907 }
908 
909 LOCAL int
rscsigetline(scgp,fd,line,count)910 rscsigetline(scgp, fd, line, count)
911 	SCSI	*scgp;
912 	int	fd;
913 	char	*line;
914 	int	count;
915 {
916 	register char	*cp;
917 
918 	for (cp = line; cp < &line[count]; cp++) {
919 		if (rscsirchar(scgp, cp) != 1)
920 			return (rscsiaborted(scgp, fd));
921 
922 		if (*cp == '\n') {
923 			*cp = '\0';
924 			return (cp - line);
925 		}
926 	}
927 	return (rscsiaborted(scgp, fd));
928 }
929 
930 LOCAL int
rscsireadnum(scgp,fd)931 rscsireadnum(scgp, fd)
932 	SCSI	*scgp;
933 	int	fd;
934 {
935 	char	cbuf[CMD_SIZE];
936 
937 	rscsigetline(scgp, fd, cbuf, sizeof (cbuf));
938 	return (atoi(cbuf));
939 }
940 
941 LOCAL int
rscsigetstatus(scgp,fd,name)942 rscsigetstatus(scgp, fd, name)
943 	SCSI	*scgp;
944 	int	fd;
945 	char	*name;
946 {
947 	char	cbuf[CMD_SIZE];
948 	char	code;
949 	int	number;
950 	int	count;
951 	int	voidsize = 0;
952 
953 	rscsigetline(scgp, fd, cbuf, sizeof (cbuf));
954 	code = cbuf[0];
955 	number = atoi(&cbuf[1]);
956 
957 	if (code == 'E' || code == 'F') {
958 		rscsigetline(scgp, fd, cbuf, sizeof (cbuf));
959 		if (code == 'F')	/* should close file ??? */
960 			rscsiaborted(scgp, fd);
961 
962 		rscsigetline(scgp, fd, cbuf, sizeof (cbuf));
963 		count = atoi(cbuf);
964 		if (count > 0) {
965 			if (scgp->errstr == NULL) {
966 				voidsize = count;
967 				count = 0;
968 			} else if (count > SCSI_ERRSTR_SIZE) {
969 				voidsize = count - SCSI_ERRSTR_SIZE;
970 				count = SCSI_ERRSTR_SIZE;
971 			}
972 			rscsireadbuf(scgp, fd, scgp->errstr, count);
973 			rscsivoidarg(scgp, fd, voidsize);
974 		}
975 		if (scgp->debug > 0)
976 			errmsgno(number, "Remote status(%s): %d '%s'.\n",
977 							name, number, cbuf);
978 		errno = number;
979 		return (-1);
980 	}
981 	if (code != 'A') {
982 		/* XXX Hier kommt evt Command not found ... */
983 		if (scgp->debug > 0)
984 			errmsgno(EX_BAD, "Protocol error (got %s).\n", cbuf);
985 		return (rscsiaborted(scgp, fd));
986 	}
987 	return (number);
988 }
989 
990 LOCAL int
rscsiaborted(scgp,fd)991 rscsiaborted(scgp, fd)
992 	SCSI	*scgp;
993 	int	fd;
994 {
995 	if ((scgp && scgp->debug > 0) || debug)
996 		errmsgno(EX_BAD, "Lost connection to remote host ??\n");
997 	/* if fd >= 0 */
998 	/* close file */
999 	if (errno == 0)
1000 		errno = EIO;
1001 	return (-1);
1002 }
1003 
1004 /*--------------------------------------------------------------------------*/
1005 #ifdef	USE_RCMD_RSH
1006 /*
1007  * If we make a separate file for libschily, we would need these include files:
1008  *
1009  * socketpair():	sys/types.h + sys/socket.h
1010  * dup2():		unixstd.h (hat auch sys/types.h)
1011  * strrchr():		strdefs.h
1012  *
1013  * and make sure that we use sigset() instead of signal() if possible.
1014  */
1015 #include <waitdefs.h>
1016 LOCAL int
_rcmdrsh(ahost,inport,locuser,remuser,cmd,rsh)1017 _rcmdrsh(ahost, inport, locuser, remuser, cmd, rsh)
1018 	char		**ahost;
1019 	int		inport;		/* port is ignored */
1020 	const char	*locuser;
1021 	const char	*remuser;
1022 	const char	*cmd;
1023 	const char	*rsh;
1024 {
1025 	struct passwd	*pw;
1026 	int	pp[2];
1027 	int	pid;
1028 
1029 	if (rsh == 0)
1030 		rsh = "rsh";
1031 
1032 	/*
1033 	 * Verify that 'locuser' is present on local host.
1034 	 */
1035 	if ((pw = getpwnam(locuser)) == NULL) {
1036 		errmsgno(EX_BAD, "Unknown user: %s\n", locuser);
1037 		return (-1);
1038 	}
1039 	/* XXX Check the existence for 'ahost' here? */
1040 
1041 	/*
1042 	 * rcmd(3) creates a single socket to be used for communication.
1043 	 * We need a bi-directional pipe to implement the same interface.
1044 	 * On newer OS that implement bi-directional we could use pipe(2)
1045 	 * but it makes no sense unless we find an OS that implements a
1046 	 * bi-directional pipe(2) but no socketpair().
1047 	 */
1048 	if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pp) == -1) {
1049 		errmsg("Cannot create socketpair.\n");
1050 		return (-1);
1051 	}
1052 
1053 	pid = fork();
1054 	if (pid < 0) {
1055 		return (-1);
1056 	} else if (pid == 0) {
1057 		const char	*p;
1058 		const char	*av0;
1059 		int		xpid;
1060 
1061 		(void) close(pp[0]);
1062 		if (dup2(pp[1], 0) == -1 ||	/* Pipe becomes 'stdin'  */
1063 		    dup2(0, 1) == -1) {		/* Pipe becomes 'stdout' */
1064 
1065 			errmsg("dup2 failed.\n");
1066 			_exit(EX_BAD);
1067 			/* NOTREACHED */
1068 		}
1069 		(void) close(pp[1]);		/* We don't need this anymore*/
1070 
1071 		/*
1072 		 * Become 'locuser' to tell the rsh program the local user id.
1073 		 */
1074 		if (getuid() != pw->pw_uid &&
1075 		    setuid(pw->pw_uid) == -1) {
1076 			errmsg("setuid(%lld) failed.\n",
1077 							(Llong)pw->pw_uid);
1078 			_exit(EX_BAD);
1079 			/* NOTREACHED */
1080 		}
1081 		if (getuid() != geteuid() &&
1082 		    seteuid(pw->pw_uid) == -1) {
1083 			errmsg("seteuid(%lld) failed.\n",
1084 							(Llong)pw->pw_uid);
1085 			_exit(EX_BAD);
1086 			/* NOTREACHED */
1087 		}
1088 
1089 		/*
1090 		 * Fork again to completely detach from parent
1091 		 * and avoid the need to wait(2).
1092 		 */
1093 		if ((xpid = fork()) == -1) {
1094 			errmsg("rcmdsh: fork to lose parent failed.\n");
1095 			_exit(EX_BAD);
1096 			/* NOTREACHED */
1097 		}
1098 		if (xpid > 0) {
1099 			_exit(0);
1100 			/* NOTREACHED */
1101 		}
1102 
1103 		/*
1104 		 * Always use remote shell programm (even for localhost).
1105 		 * The client command may call getpeername() for security
1106 		 * reasons and this would fail on a simple pipe.
1107 		 */
1108 
1109 
1110 		/*
1111 		 * By default, 'rsh' handles terminal created signals
1112 		 * but this is not what we like.
1113 		 * For this reason, we tell 'rsh' to ignore these signals.
1114 		 * Ignoring these signals is important to allow 'star' / 'sdd'
1115 		 * to e.g. implement SIGQUIT as signal to trigger intermediate
1116 		 * status printing.
1117 		 *
1118 		 * For now (late 2002), we know that the following programs
1119 		 * are broken and do not implement signal handling correctly:
1120 		 *
1121 		 *	rsh	on SunOS-5.0...SunOS-5.9
1122 		 *	ssh	from ssh.com
1123 		 *	ssh	from openssh.org
1124 		 *
1125 		 * Sun already did accept a bug report for 'rsh'. For the ssh
1126 		 * commands we need to send out bug reports. Meanwhile it could
1127 		 * help to call setsid() if we are running under X so the ssh
1128 		 * X pop up for passwd reading will work.
1129 		 */
1130 		signal(SIGINT, SIG_IGN);
1131 		signal(SIGQUIT, SIG_IGN);
1132 #ifdef	SIGTSTP
1133 		signal(SIGTSTP, SIG_IGN); /* We would not be able to continue*/
1134 #endif
1135 
1136 		av0 = rsh;
1137 		if ((p = strrchr(rsh, '/')) != NULL)
1138 			av0 = ++p;
1139 		execlp(rsh, av0, *ahost, "-l", remuser, cmd, (char *)NULL);
1140 
1141 		errmsg("execlp '%s' failed.\n", rsh);
1142 		_exit(EX_BAD);
1143 		/* NOTREACHED */
1144 	} else {
1145 		(void) close(pp[1]);
1146 		/*
1147 		 * Wait for the intermediate child.
1148 		 * The real 'rsh' program is completely detached from us.
1149 		 */
1150 		wait(0);
1151 		return (pp[0]);
1152 	}
1153 	return (-1);	/* keep gcc happy */
1154 }
1155 #endif	/* USE_RCMD_RSH */
1156 
1157 #endif	/* USE_REMOTE */
1158