summaryrefslogtreecommitdiff
path: root/libusal/scsi-remote.c
diff options
context:
space:
mode:
Diffstat (limited to 'libusal/scsi-remote.c')
-rw-r--r--libusal/scsi-remote.c1213
1 files changed, 1213 insertions, 0 deletions
diff --git a/libusal/scsi-remote.c b/libusal/scsi-remote.c
new file mode 100644
index 0000000..f9b40d6
--- /dev/null
+++ b/libusal/scsi-remote.c
@@ -0,0 +1,1213 @@
+/*
+ * This file has been modified for the cdrkit suite.
+ *
+ * The behaviour and appearence of the program code below can differ to a major
+ * extent from the version distributed by the original author(s).
+ *
+ * For details, see Changelog file distributed with the cdrkit package. If you
+ * received this file from another source then ask the distributing person for
+ * a log of modifications.
+ *
+ */
+
+#define USE_REMOTE
+/* @(#)scsi-remote.c 1.18 06/01/12 Copyright 1990,2000-2003 J. Schilling */
+/*
+ * Remote SCSI user level command transport routines
+ *
+ * Warning: you may change this source, but if you do that
+ * you need to change the _usal_version and _usal_auth* string below.
+ * You may not return "schily" for an SCG_AUTHOR request anymore.
+ * Choose your name instead of "schily" and make clear that the version
+ * string is related to a modified source.
+ *
+ * Copyright (c) 1990,2000-2003 J. Schilling
+ */
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; see the file COPYING. If not, write to the Free Software
+ * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <mconfig.h>
+
+#if !defined(HAVE_FORK) || !defined(HAVE_SOCKETPAIR) || !defined(HAVE_DUP2)
+#undef USE_RCMD_RSH
+#endif
+/*
+ * We may work without getservbyname() if we restructure the code not to
+ * use the port number if we only use _rcmdrsh().
+ */
+#if !defined(HAVE_GETSERVBYNAME)
+#undef USE_REMOTE /* Cannot get rcmd() port # */
+#endif
+#if (!defined(HAVE_NETDB_H) || !defined(HAVE_RCMD)) && !defined(USE_RCMD_RSH)
+#undef USE_REMOTE /* There is no rcmd() */
+#endif
+
+#ifdef USE_REMOTE
+#include <stdio.h>
+#include <sys/types.h>
+#include <fctldefs.h>
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#include <errno.h>
+#include <signal.h>
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef HAVE_PWD_H
+#include <pwd.h>
+#endif
+#include <standard.h>
+#include <stdxlib.h>
+#include <unixstd.h>
+#include <strdefs.h>
+#include <schily.h>
+
+#include <usal/usalcmd.h>
+#include <usal/scsitransp.h>
+
+#if defined(SIGDEFER) || defined(SVR4)
+#define signal sigset
+#endif
+
+/*
+ * On Cygwin, there are no privilleged ports.
+ * On UNIX, rcmd() uses privilleged port that only work for root.
+ */
+#ifdef IS_CYGWIN
+#define privport_ok() (1)
+#else
+#ifdef HAVE_GETPPRIV
+#define privport_ok() ppriv_ok()
+#else
+#define privport_ok() (geteuid() == 0)
+#endif
+#endif
+
+#define CMD_SIZE 80
+
+#define MAX_SCG 16 /* Max # of SCSI controllers */
+#define MAX_TGT 16
+#define MAX_LUN 8
+
+/*extern BOOL debug;*/
+LOCAL BOOL debug = 1;
+
+LOCAL char _usal_trans_version[] = "remote-1.18"; /* The version for remote SCSI */
+LOCAL char _usal_auth_cdrkit[] = "cdrkit-team"; /* The author for this module */
+
+LOCAL int usalo_rsend __PR((SCSI *usalp));
+LOCAL char * usalo_rversion __PR((SCSI *usalp, int what));
+LOCAL int usalo_rhelp __PR((SCSI *usalp, FILE *f));
+LOCAL int usalo_ropen __PR((SCSI *usalp, char *device));
+LOCAL int usalo_rclose __PR((SCSI *usalp));
+LOCAL long usalo_rmaxdma __PR((SCSI *usalp, long amt));
+LOCAL void * usalo_rgetbuf __PR((SCSI *usalp, long amt));
+LOCAL void usalo_rfreebuf __PR((SCSI *usalp));
+LOCAL BOOL usalo_rhavebus __PR((SCSI *usalp, int busno));
+LOCAL int usalo_rfileno __PR((SCSI *usalp, int busno, int tgt, int tlun));
+LOCAL int usalo_rinitiator_id __PR((SCSI *usalp));
+LOCAL int usalo_risatapi __PR((SCSI *usalp));
+LOCAL int usalo_rreset __PR((SCSI *usalp, int what));
+
+/*
+ * XXX We should rethink the fd parameter now that we introduced
+ * XXX the rscsirchar() function and most access of remfd is done
+ * XXX via usallocal(usalp)->remfd.
+ */
+LOCAL void rscsiabrt __PR((int sig));
+LOCAL int rscsigetconn __PR((SCSI *usalp, char *host));
+LOCAL char *rscsiversion __PR((SCSI *usalp, int fd, int what));
+LOCAL int rscsiopen __PR((SCSI *usalp, int fd, char *fname));
+LOCAL int rscsiclose __PR((SCSI *usalp, int fd));
+LOCAL int rscsimaxdma __PR((SCSI *usalp, int fd, long amt));
+LOCAL int rscsigetbuf __PR((SCSI *usalp, int fd, long amt));
+LOCAL int rscsifreebuf __PR((SCSI *usalp, int fd));
+LOCAL int rscsihavebus __PR((SCSI *usalp, int fd, int bus));
+LOCAL int rscsifileno __PR((SCSI *usalp, int fd, int busno, int tgt, int tlun));
+LOCAL int rscsiinitiator_id __PR((SCSI *usalp, int fd));
+LOCAL int rscsiisatapi __PR((SCSI *usalp, int fd));
+LOCAL int rscsireset __PR((SCSI *usalp, int fd, int what));
+LOCAL int rscsiscmd __PR((SCSI *usalp, int fd, struct usal_cmd *sp));
+LOCAL int rscsifillrbuf __PR((SCSI *usalp));
+LOCAL int rscsirchar __PR((SCSI *usalp, char *cp));
+LOCAL int rscsireadbuf __PR((SCSI *usalp, int fd, char *buf, int count));
+LOCAL void rscsivoidarg __PR((SCSI *usalp, int fd, int count));
+LOCAL int rscsicmd __PR((SCSI *usalp, int fd, char *name, char *cbuf));
+LOCAL void rscsisendcmd __PR((SCSI *usalp, int fd, char *name, char *cbuf));
+LOCAL int rscsigetline __PR((SCSI *usalp, int fd, char *line, int count));
+LOCAL int rscsireadnum __PR((SCSI *usalp, int fd));
+LOCAL int rscsigetstatus __PR((SCSI *usalp, int fd, char *name));
+LOCAL int rscsiaborted __PR((SCSI *usalp, int fd));
+#ifdef USE_RCMD_RSH
+LOCAL int _rcmdrsh __PR((char **ahost, int inport,
+ const char *locuser,
+ const char *remuser,
+ const char *cmd,
+ const char *rsh));
+#ifdef HAVE_GETPPRIV
+LOCAL BOOL ppriv_ok __PR((void));
+#endif
+#endif
+
+/*--------------------------------------------------------------------------*/
+
+#define READBUF_SIZE 128
+
+struct usal_local {
+ int remfd;
+ char readbuf[READBUF_SIZE];
+ char *readbptr;
+ int readbcnt;
+ BOOL isopen;
+ int rsize;
+ int wsize;
+ char *v_version;
+ char *v_author;
+ char *v_sccs_id;
+};
+
+
+#define usallocal(p) ((struct usal_local *)((p)->local))
+
+usal_ops_t remote_ops = {
+ usalo_rsend, /* "S" end */
+ usalo_rversion, /* "V" ersion */
+ usalo_rhelp, /* help */
+ usalo_ropen, /* "O" pen */
+ usalo_rclose, /* "C" lose */
+ usalo_rmaxdma, /* "D" MA */
+ usalo_rgetbuf, /* "M" alloc */
+ usalo_rfreebuf, /* "F" free */
+ usalo_rhavebus, /* "B" us */
+ usalo_rfileno, /* "T" arget */
+ usalo_rinitiator_id, /* "I" nitiator */
+ usalo_risatapi, /* "A" tapi */
+ usalo_rreset, /* "R" eset */
+};
+
+/*
+ * Return our ops ptr.
+ */
+usal_ops_t *
+usal_remote()
+{
+ return (&remote_ops);
+}
+
+/*
+ * Return version information for the low level SCSI transport code.
+ * This has been introduced to make it easier to trace down problems
+ * in applications.
+ */
+LOCAL char *
+usalo_rversion(usalp, what)
+ SCSI *usalp;
+ int what;
+{
+ int f;
+
+ if (usalp->local == NULL)
+ return ((char *)0);
+
+ f = usallocal(usalp)->remfd;
+ if (usalp != (SCSI *)0) {
+ switch (what) {
+
+ case SCG_VERSION:
+ return (_usal_trans_version);
+ /*
+ * If you changed this source, you are not allowed to
+ * return "schily" for the SCG_AUTHOR request.
+ */
+ case SCG_AUTHOR:
+ return (_usal_auth_cdrkit);
+ case SCG_SCCS_ID:
+ return (__sccsid);
+
+ case SCG_RVERSION:
+ if (usallocal(usalp)->v_version == NULL)
+ usallocal(usalp)->v_version = rscsiversion(usalp, f, SCG_VERSION);
+ return (usallocal(usalp)->v_version);
+ /*
+ * If you changed this source, you are not allowed to
+ * return "schily" for the SCG_AUTHOR request.
+ */
+ case SCG_RAUTHOR:
+ if (usallocal(usalp)->v_author == NULL)
+ usallocal(usalp)->v_author = rscsiversion(usalp, f, SCG_AUTHOR);
+ return (usallocal(usalp)->v_author);
+ case SCG_RSCCS_ID:
+ if (usallocal(usalp)->v_sccs_id == NULL)
+ usallocal(usalp)->v_sccs_id = rscsiversion(usalp, f, SCG_SCCS_ID);
+ return (usallocal(usalp)->v_sccs_id);
+ }
+ }
+ return ((char *)0);
+}
+
+LOCAL int
+usalo_rhelp(usalp, f)
+ SCSI *usalp;
+ FILE *f;
+{
+ __usal_help(f, "RSCSI", "Remote SCSI",
+ "REMOTE:", "rscsi@host:bus,target,lun", "REMOTE:rscsi@host:1,2,0", TRUE, FALSE);
+ return (0);
+}
+
+LOCAL int
+usalo_ropen(usalp, device)
+ SCSI *usalp;
+ char *device;
+{
+ int busno = usal_scsibus(usalp);
+ int tgt = usal_target(usalp);
+ int tlun = usal_lun(usalp);
+ register int f;
+ register int nopen = 0;
+ char devname[128];
+ char *p;
+
+ if (usalp->overbose)
+ fprintf(stderr, "Warning: Using remote SCSI interface.\n");
+
+ if (busno >= MAX_SCG || tgt >= MAX_TGT || tlun >= MAX_LUN) {
+ errno = EINVAL;
+ if (usalp->errstr)
+ snprintf(usalp->errstr, SCSI_ERRSTR_SIZE,
+ "Illegal value for busno, target or lun '%d,%d,%d'",
+ busno, tgt, tlun);
+
+ return (-1);
+ }
+ if (usalp->local == NULL) {
+ usalp->local = malloc(sizeof (struct usal_local));
+ if (usalp->local == NULL)
+ return (0);
+ usallocal(usalp)->remfd = -1;
+ usallocal(usalp)->readbptr = usallocal(usalp)->readbuf;
+ usallocal(usalp)->readbcnt = 0;
+ usallocal(usalp)->isopen = FALSE;
+ usallocal(usalp)->rsize = 0;
+ usallocal(usalp)->wsize = 0;
+ usallocal(usalp)->v_version = NULL;
+ usallocal(usalp)->v_author = NULL;
+ usallocal(usalp)->v_sccs_id = NULL;
+ }
+
+ if (device == NULL || (strncmp(device, "REMOTE", 6) != 0) ||
+ (device = strchr(device, ':')) == NULL) {
+ if (usalp->errstr)
+ snprintf(usalp->errstr, SCSI_ERRSTR_SIZE,
+ "Illegal remote device syntax");
+ return (-1);
+ }
+ device++;
+ /*
+ * Save non user@host:device
+ */
+ snprintf(devname, sizeof (devname), "%s", device);
+
+ if ((p = strchr(devname, ':')) != NULL)
+ *p++ = '\0';
+
+ f = rscsigetconn(usalp, devname);
+ if (f < 0) {
+ if (usalp->errstr)
+ snprintf(usalp->errstr, SCSI_ERRSTR_SIZE,
+ "Cannot get connection to remote host");
+ return (-1);
+ }
+ usallocal(usalp)->remfd = f;
+ debug = usalp->debug;
+ if (rscsiopen(usalp, f, p) >= 0) {
+ nopen++;
+ usallocal(usalp)->isopen = TRUE;
+ }
+ return (nopen);
+}
+
+LOCAL int
+usalo_rclose(usalp)
+ SCSI *usalp;
+{
+ register int f;
+ int ret;
+
+ if (usalp->local == NULL)
+ return (-1);
+
+ if (usallocal(usalp)->v_version != NULL) {
+ free(usallocal(usalp)->v_version);
+ usallocal(usalp)->v_version = NULL;
+ }
+ if (usallocal(usalp)->v_author != NULL) {
+ free(usallocal(usalp)->v_author);
+ usallocal(usalp)->v_author = NULL;
+ }
+ if (usallocal(usalp)->v_sccs_id != NULL) {
+ free(usallocal(usalp)->v_sccs_id);
+ usallocal(usalp)->v_sccs_id = NULL;
+ }
+
+ f = usallocal(usalp)->remfd;
+ if (f < 0 || !usallocal(usalp)->isopen)
+ return (0);
+ ret = rscsiclose(usalp, f);
+ usallocal(usalp)->isopen = FALSE;
+ close(f);
+ usallocal(usalp)->remfd = -1;
+ return (ret);
+}
+
+LOCAL long
+usalo_rmaxdma(usalp, amt)
+ SCSI *usalp;
+ long amt;
+{
+ if (usalp->local == NULL)
+ return (-1L);
+
+ return (rscsimaxdma(usalp, usallocal(usalp)->remfd, amt));
+}
+
+LOCAL void *
+usalo_rgetbuf(usalp, amt)
+ SCSI *usalp;
+ long amt;
+{
+ int ret;
+
+ if (usalp->local == NULL)
+ return ((void *)0);
+
+ ret = rscsigetbuf(usalp, usallocal(usalp)->remfd, amt);
+ if (ret < 0)
+ return ((void *)0);
+
+#ifdef HAVE_VALLOC
+ usalp->bufbase = (void *)valloc((size_t)amt);
+#else
+ usalp->bufbase = (void *)malloc((size_t)amt);
+#endif
+ if (usalp->bufbase == NULL) {
+ usalo_rfreebuf(usalp);
+ return ((void *)0);
+ }
+ return (usalp->bufbase);
+}
+
+LOCAL void
+usalo_rfreebuf(usalp)
+ SCSI *usalp;
+{
+ int f;
+
+ if (usalp->bufbase)
+ free(usalp->bufbase);
+ usalp->bufbase = NULL;
+
+ if (usalp->local == NULL)
+ return;
+
+ f = usallocal(usalp)->remfd;
+ if (f < 0 || !usallocal(usalp)->isopen)
+ return;
+ rscsifreebuf(usalp, f);
+}
+
+LOCAL BOOL
+usalo_rhavebus(usalp, busno)
+ SCSI *usalp;
+ int busno;
+{
+ if (usalp->local == NULL || busno < 0 || busno >= MAX_SCG)
+ return (FALSE);
+
+ return (rscsihavebus(usalp, usallocal(usalp)->remfd, busno));
+}
+
+LOCAL int
+usalo_rfileno(usalp, busno, tgt, tlun)
+ SCSI *usalp;
+ int busno;
+ int tgt;
+ int tlun;
+{
+ int f;
+
+ if (usalp->local == NULL ||
+ busno < 0 || busno >= MAX_SCG ||
+ tgt < 0 || tgt >= MAX_TGT ||
+ tlun < 0 || tlun >= MAX_LUN)
+ return (-1);
+
+ f = usallocal(usalp)->remfd;
+ if (f < 0 || !usallocal(usalp)->isopen)
+ return (-1);
+ return (rscsifileno(usalp, f, busno, tgt, tlun));
+}
+
+LOCAL int
+usalo_rinitiator_id(usalp)
+ SCSI *usalp;
+{
+ if (usalp->local == NULL)
+ return (-1);
+
+ return (rscsiinitiator_id(usalp, usallocal(usalp)->remfd));
+}
+
+LOCAL int
+usalo_risatapi(usalp)
+ SCSI *usalp;
+{
+ if (usalp->local == NULL)
+ return (-1);
+
+ return (rscsiisatapi(usalp, usallocal(usalp)->remfd));
+}
+
+LOCAL int
+usalo_rreset(usalp, what)
+ SCSI *usalp;
+ int what;
+{
+ if (usalp->local == NULL)
+ return (-1);
+
+ return (rscsireset(usalp, usallocal(usalp)->remfd, what));
+}
+
+LOCAL int
+usalo_rsend(usalp)
+ SCSI *usalp;
+{
+ struct usal_cmd *sp = usalp->scmd;
+ int ret;
+
+ if (usalp->local == NULL)
+ return (-1);
+
+ if (usalp->fd < 0) {
+ sp->error = SCG_FATAL;
+ return (0);
+ }
+ ret = rscsiscmd(usalp, usallocal(usalp)->remfd, usalp->scmd);
+
+ return (ret);
+}
+
+/*--------------------------------------------------------------------------*/
+LOCAL void
+rscsiabrt(sig)
+ int sig;
+{
+ rscsiaborted((SCSI *)0, -1);
+}
+
+LOCAL int
+rscsigetconn(usalp, host)
+ SCSI *usalp;
+ char *host;
+{
+ static struct servent *sp = 0;
+ static struct passwd *pw = 0;
+ char *name = "root";
+ char *p;
+ char *rscsi;
+ char *rsh;
+ int rscsisock;
+ char *rscsipeer;
+ char rscsiuser[128];
+
+
+ signal(SIGPIPE, rscsiabrt);
+ if (sp == 0) {
+ sp = getservbyname("shell", "tcp");
+ if (sp == 0) {
+ comerrno(EX_BAD, "shell/tcp: unknown service\n");
+ /* NOTREACHED */
+ }
+ pw = getpwuid(getuid());
+ if (pw == 0) {
+ comerrno(EX_BAD, "who are you? No passwd entry found.\n");
+ /* NOTREACHED */
+ }
+ }
+ if ((p = strchr(host, '@')) != NULL) {
+ size_t d = p - host;
+
+ if (d > sizeof (rscsiuser))
+ d = sizeof (rscsiuser);
+ snprintf(rscsiuser, sizeof (rscsiuser), "%.*s", (int)d, host);
+ name = rscsiuser;
+ host = &p[1];
+ } else {
+ name = pw->pw_name;
+ }
+ if (usalp->debug > 0)
+ errmsgno(EX_BAD, "locuser: '%s' rscsiuser: '%s' host: '%s'\n",
+ pw->pw_name, name, host);
+ rscsipeer = host;
+
+ if ((rscsi = getenv("RSCSI")) == NULL)
+ rscsi = "/usr/sbin/netscsid";
+ rsh = getenv("RSH");
+
+#ifdef USE_RCMD_RSH
+ if (!privport_ok() || rsh != NULL)
+ rscsisock = _rcmdrsh(&rscsipeer, (unsigned short)sp->s_port,
+ pw->pw_name, name, rscsi, rsh);
+ else
+#endif
+#ifdef HAVE_RCMD
+ rscsisock = rcmd(&rscsipeer, (unsigned short)sp->s_port,
+ pw->pw_name, name, rscsi, 0);
+#else
+ rscsisock = _rcmdrsh(&rscsipeer, (unsigned short)sp->s_port,
+ pw->pw_name, name, rscsi, rsh);
+#endif
+
+ return (rscsisock);
+}
+
+LOCAL char *
+rscsiversion(usalp, fd, what)
+ SCSI *usalp;
+ int fd;
+ int what;
+{
+ char cbuf[CMD_SIZE];
+ char *p;
+ int ret;
+
+ snprintf(cbuf, sizeof (cbuf), "V%d\n", what);
+ ret = rscsicmd(usalp, fd, "version", cbuf);
+ p = malloc(ret);
+ if (p == NULL)
+ return (p);
+ rscsireadbuf(usalp, fd, p, ret);
+ return (p);
+}
+
+LOCAL int
+rscsiopen(usalp, fd, fname)
+ SCSI *usalp;
+ int fd;
+ char *fname;
+{
+ char cbuf[CMD_SIZE];
+ int ret;
+ int bus;
+ int chan;
+ int tgt;
+ int lun;
+
+ snprintf(cbuf, sizeof (cbuf), "O%s\n", fname?fname:"");
+ ret = rscsicmd(usalp, fd, "open", cbuf);
+ if (ret < 0)
+ return (ret);
+
+ bus = rscsireadnum(usalp, fd);
+ chan = rscsireadnum(usalp, fd);
+ tgt = rscsireadnum(usalp, fd);
+ lun = rscsireadnum(usalp, fd);
+
+ usal_settarget(usalp, bus, tgt, lun);
+ return (ret);
+}
+
+LOCAL int
+rscsiclose(usalp, fd)
+ SCSI *usalp;
+ int fd;
+{
+ return (rscsicmd(usalp, fd, "close", "C\n"));
+}
+
+LOCAL int
+rscsimaxdma(usalp, fd, amt)
+ SCSI *usalp;
+ int fd;
+ long amt;
+{
+ char cbuf[CMD_SIZE];
+
+ snprintf(cbuf, sizeof (cbuf), "D%ld\n", amt);
+ return (rscsicmd(usalp, fd, "maxdma", cbuf));
+}
+
+LOCAL int
+rscsigetbuf(usalp, fd, amt)
+ SCSI *usalp;
+ int fd;
+ long amt;
+{
+ char cbuf[CMD_SIZE];
+ int size;
+ int ret;
+
+ snprintf(cbuf, sizeof (cbuf), "M%ld\n", amt);
+ ret = rscsicmd(usalp, fd, "getbuf", cbuf);
+ if (ret < 0)
+ return (ret);
+
+ size = ret + 1024; /* Add protocol overhead */
+
+#ifdef SO_SNDBUF
+ if (size > usallocal(usalp)->wsize) while (size > 512 &&
+ setsockopt(fd, SOL_SOCKET, SO_SNDBUF,
+ (char *)&size, sizeof (size)) < 0) {
+ size -= 512;
+ }
+ if (size > usallocal(usalp)->wsize) {
+ usallocal(usalp)->wsize = size;
+ if (usalp->debug > 0)
+ errmsgno(EX_BAD, "sndsize: %d\n", size);
+ }
+#endif
+#ifdef SO_RCVBUF
+ if (size > usallocal(usalp)->rsize) while (size > 512 &&
+ setsockopt(fd, SOL_SOCKET, SO_RCVBUF,
+ (char *)&size, sizeof (size)) < 0) {
+ size -= 512;
+ }
+ if (size > usallocal(usalp)->rsize) {
+ usallocal(usalp)->rsize = size;
+ if (usalp->debug > 0)
+ errmsgno(EX_BAD, "rcvsize: %d\n", size);
+ }
+#endif
+ return (ret);
+}
+
+LOCAL int
+rscsifreebuf(usalp, fd)
+ SCSI *usalp;
+ int fd;
+{
+ return (rscsicmd(usalp, fd, "freebuf", "F\n"));
+}
+
+LOCAL int
+rscsihavebus(usalp, fd, busno)
+ SCSI *usalp;
+ int fd;
+ int busno;
+{
+ char cbuf[2*CMD_SIZE];
+
+ snprintf(cbuf, sizeof (cbuf), "B%d\n%d\n",
+ busno,
+ 0);
+ return (rscsicmd(usalp, fd, "havebus", cbuf));
+}
+
+LOCAL int
+rscsifileno(usalp, fd, busno, tgt, tlun)
+ SCSI *usalp;
+ int fd;
+ int busno;
+ int tgt;
+ int tlun;
+{
+ char cbuf[3*CMD_SIZE];
+
+ snprintf(cbuf, sizeof (cbuf), "T%d\n%d\n%d\n%d\n",
+ busno,
+ 0,
+ tgt,
+ tlun);
+ return (rscsicmd(usalp, fd, "fileno", cbuf));
+}
+
+LOCAL int
+rscsiinitiator_id(usalp, fd)
+ SCSI *usalp;
+ int fd;
+{
+ return (rscsicmd(usalp, fd, "initiator id", "I\n"));
+}
+
+LOCAL int
+rscsiisatapi(usalp, fd)
+ SCSI *usalp;
+ int fd;
+{
+ return (rscsicmd(usalp, fd, "isatapi", "A\n"));
+}
+
+LOCAL int
+rscsireset(usalp, fd, what)
+ SCSI *usalp;
+ int fd;
+ int what;
+{
+ char cbuf[CMD_SIZE];
+
+ snprintf(cbuf, sizeof (cbuf), "R%d\n", what);
+ return (rscsicmd(usalp, fd, "reset", cbuf));
+}
+
+LOCAL int
+rscsiscmd(usalp, fd, sp)
+ SCSI *usalp;
+ int fd;
+ struct usal_cmd *sp;
+{
+ char cbuf[1600];
+ int ret;
+ int amt = 0;
+ int voidsize = 0;
+
+ ret = snprintf(cbuf, sizeof (cbuf), "S%d\n%d\n%d\n%d\n%d\n",
+ sp->size, sp->flags,
+ sp->cdb_len, sp->sense_len,
+ sp->timeout);
+ movebytes(sp->cdb.cmd_cdb, &cbuf[ret], sp->cdb_len);
+ ret += sp->cdb_len;
+
+ if ((sp->flags & SCG_RECV_DATA) == 0 && sp->size > 0) {
+ amt = sp->size;
+ if ((ret + amt) <= sizeof (cbuf)) {
+ movebytes(sp->addr, &cbuf[ret], amt);
+ ret += amt;
+ amt = 0;
+ }
+ }
+ errno = 0;
+ if (_nixwrite(fd, cbuf, ret) != ret)
+ rscsiaborted(usalp, fd);
+
+ if (amt > 0) {
+ if (_nixwrite(fd, sp->addr, amt) != amt)
+ rscsiaborted(usalp, fd);
+ }
+
+ ret = rscsigetstatus(usalp, fd, "sendcmd");
+ if (ret < 0)
+ return (ret);
+
+ sp->resid = sp->size - ret;
+ sp->error = rscsireadnum(usalp, fd);
+ sp->ux_errno = rscsireadnum(usalp, fd);
+ *(Uchar *)&sp->scb = rscsireadnum(usalp, fd);
+ sp->sense_count = rscsireadnum(usalp, fd);
+
+ if (sp->sense_count > SCG_MAX_SENSE) {
+ voidsize = sp->sense_count - SCG_MAX_SENSE;
+ sp->sense_count = SCG_MAX_SENSE;
+ }
+ if (sp->sense_count > 0) {
+ rscsireadbuf(usalp, fd, (char *)sp->u_sense.cmd_sense, sp->sense_count);
+ rscsivoidarg(usalp, fd, voidsize);
+ }
+
+ if ((sp->flags & SCG_RECV_DATA) != 0 && ret > 0)
+ rscsireadbuf(usalp, fd, sp->addr, ret);
+
+ return (0);
+}
+
+LOCAL int
+rscsifillrbuf(usalp)
+ SCSI *usalp;
+{
+ usallocal(usalp)->readbptr = usallocal(usalp)->readbuf;
+
+ return (usallocal(usalp)->readbcnt =
+ _niread(usallocal(usalp)->remfd,
+ usallocal(usalp)->readbuf, READBUF_SIZE));
+}
+
+LOCAL int
+rscsirchar(usalp, cp)
+ SCSI *usalp;
+ char *cp;
+{
+ if (--(usallocal(usalp)->readbcnt) < 0) {
+ if (rscsifillrbuf(usalp) <= 0)
+ return (usallocal(usalp)->readbcnt);
+ --(usallocal(usalp)->readbcnt);
+ }
+ *cp = *(usallocal(usalp)->readbptr)++;
+ return (1);
+}
+
+LOCAL int
+rscsireadbuf(usalp, fd, buf, count)
+ SCSI *usalp;
+ int fd;
+ char *buf;
+ int count;
+{
+ register int n = count;
+ register int amt = 0;
+ register int cnt;
+
+ if (usallocal(usalp)->readbcnt > 0) {
+ cnt = usallocal(usalp)->readbcnt;
+ if (cnt > n)
+ cnt = n;
+ movebytes(usallocal(usalp)->readbptr, buf, cnt);
+ usallocal(usalp)->readbptr += cnt;
+ usallocal(usalp)->readbcnt -= cnt;
+ amt += cnt;
+ }
+ while (amt < n) {
+ if ((cnt = _niread(fd, &buf[amt], n - amt)) <= 0) {
+ return (rscsiaborted(usalp, fd));
+ }
+ amt += cnt;
+ }
+ return (amt);
+}
+
+LOCAL void
+rscsivoidarg(usalp, fd, n)
+ SCSI *usalp;
+ int fd;
+ register int n;
+{
+ register int i;
+ register int amt;
+ char buf[512];
+
+ for (i = 0; i < n; i += amt) {
+ amt = sizeof (buf);
+ if ((n - i) < amt)
+ amt = n - i;
+ rscsireadbuf(usalp, fd, buf, amt);
+ }
+}
+
+LOCAL int
+rscsicmd(usalp, fd, name, cbuf)
+ SCSI *usalp;
+ int fd;
+ char *name;
+ char *cbuf;
+{
+ rscsisendcmd(usalp, fd, name, cbuf);
+ return (rscsigetstatus(usalp, fd, name));
+}
+
+LOCAL void
+rscsisendcmd(usalp, fd, name, cbuf)
+ SCSI *usalp;
+ int fd;
+ char *name;
+ char *cbuf;
+{
+ int buflen = strlen(cbuf);
+
+ errno = 0;
+ if (_nixwrite(fd, cbuf, buflen) != buflen)
+ rscsiaborted(usalp, fd);
+}
+
+LOCAL int
+rscsigetline(usalp, fd, line, count)
+ SCSI *usalp;
+ int fd;
+ char *line;
+ int count;
+{
+ register char *cp;
+
+ for (cp = line; cp < &line[count]; cp++) {
+ if (rscsirchar(usalp, cp) != 1)
+ return (rscsiaborted(usalp, fd));
+
+ if (*cp == '\n') {
+ *cp = '\0';
+ return (cp - line);
+ }
+ }
+ return (rscsiaborted(usalp, fd));
+}
+
+LOCAL int
+rscsireadnum(usalp, fd)
+ SCSI *usalp;
+ int fd;
+{
+ char cbuf[CMD_SIZE];
+
+ rscsigetline(usalp, fd, cbuf, sizeof (cbuf));
+ return (atoi(cbuf));
+}
+
+LOCAL int
+rscsigetstatus(usalp, fd, name)
+ SCSI *usalp;
+ int fd;
+ char *name;
+{
+ char cbuf[CMD_SIZE];
+ char code;
+ int number;
+ int count;
+ int voidsize = 0;
+
+ rscsigetline(usalp, fd, cbuf, sizeof (cbuf));
+ code = cbuf[0];
+ number = atoi(&cbuf[1]);
+
+ if (code == 'E' || code == 'F') {
+ rscsigetline(usalp, fd, cbuf, sizeof (cbuf));
+ if (code == 'F') /* should close file ??? */
+ rscsiaborted(usalp, fd);
+
+ rscsigetline(usalp, fd, cbuf, sizeof (cbuf));
+ count = atoi(cbuf);
+ if (count > 0) {
+ if (usalp->errstr == NULL) {
+ voidsize = count;
+ count = 0;
+ } else if (count > SCSI_ERRSTR_SIZE) {
+ voidsize = count - SCSI_ERRSTR_SIZE;
+ count = SCSI_ERRSTR_SIZE;
+ }
+ rscsireadbuf(usalp, fd, usalp->errstr, count);
+ rscsivoidarg(usalp, fd, voidsize);
+ }
+ if (usalp->debug > 0)
+ errmsgno(number, "Remote status(%s): %d '%s'.\n",
+ name, number, cbuf);
+ errno = number;
+ return (-1);
+ }
+ if (code != 'A') {
+ /* XXX Hier kommt evt Command not found ... */
+ if (usalp->debug > 0)
+ errmsgno(EX_BAD, "Protocol error (got %s).\n", cbuf);
+ return (rscsiaborted(usalp, fd));
+ }
+ return (number);
+}
+
+LOCAL int
+rscsiaborted(usalp, fd)
+ SCSI *usalp;
+ int fd;
+{
+ if ((usalp && usalp->debug > 0) || debug)
+ errmsgno(EX_BAD, "Lost connection to remote host ??\n");
+ /* if fd >= 0 */
+ /* close file */
+ if (errno == 0)
+ errno = EIO;
+ return (-1);
+}
+
+/*--------------------------------------------------------------------------*/
+#ifdef USE_RCMD_RSH
+/*
+ * If we make a separate file for libschily, we would need these include files:
+ *
+ * socketpair(): sys/types.h + sys/socket.h
+ * dup2(): unixstd.h (hat auch sys/types.h)
+ * strrchr(): strdefs.h
+ *
+ * and make sure that we use sigset() instead of signal() if possible.
+ */
+#include <waitdefs.h>
+LOCAL int
+_rcmdrsh(ahost, inport, locuser, remuser, cmd, rsh)
+ char **ahost;
+ int inport; /* port is ignored */
+ const char *locuser;
+ const char *remuser;
+ const char *cmd;
+ const char *rsh;
+{
+ struct passwd *pw;
+ int pp[2];
+ int pid;
+
+ if (rsh == 0)
+ rsh = "rsh";
+
+ /*
+ * Verify that 'locuser' is present on local host.
+ */
+ if ((pw = getpwnam(locuser)) == NULL) {
+ errmsgno(EX_BAD, "Unknown user: %s\n", locuser);
+ return (-1);
+ }
+ /* XXX Check the existence for 'ahost' here? */
+
+ /*
+ * rcmd(3) creates a single socket to be used for communication.
+ * We need a bi-directional pipe to implement the same interface.
+ * On newer OS that implement bi-directional we could use pipe(2)
+ * but it makes no sense unless we find an OS that implements a
+ * bi-directional pipe(2) but no socketpair().
+ */
+ if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pp) == -1) {
+ errmsg("Cannot create socketpair.\n");
+ return (-1);
+ }
+
+ pid = fork();
+ if (pid < 0) {
+ return (-1);
+ } else if (pid == 0) {
+ const char *p;
+ const char *av0;
+ int xpid;
+
+ (void) close(pp[0]);
+ if (dup2(pp[1], 0) == -1 || /* Pipe becomes 'stdin' */
+ dup2(0, 1) == -1) { /* Pipe becomes 'stdout' */
+
+ errmsg("dup2 failed.\n");
+ _exit(EX_BAD);
+ /* NOTREACHED */
+ }
+ (void) close(pp[1]); /* We don't need this anymore*/
+
+ /*
+ * Become 'locuser' to tell the rsh program the local user id.
+ */
+ if (getuid() != pw->pw_uid &&
+ setuid(pw->pw_uid) == -1) {
+ errmsg("setuid(%lld) failed.\n",
+ (Llong)pw->pw_uid);
+ _exit(EX_BAD);
+ /* NOTREACHED */
+ }
+ if (getuid() != geteuid() &&
+#ifdef HAVE_SETREUID
+ setreuid(-1, pw->pw_uid) == -1) {
+#else
+#ifdef HAVE_SETEUID
+ seteuid(pw->pw_uid) == -1) {
+#else
+ setuid(pw->pw_uid) == -1) {
+#endif
+#endif
+ errmsg("seteuid(%lld) failed.\n",
+ (Llong)pw->pw_uid);
+ _exit(EX_BAD);
+ /* NOTREACHED */
+ }
+ if (getuid() != geteuid() &&
+ seteuid(pw->pw_uid) == -1) {
+ errmsg("seteuid(%lld) failed.\n",
+ (Llong)pw->pw_uid);
+ _exit(EX_BAD);
+ /* NOTREACHED */
+ }
+
+ /*
+ * Fork again to completely detach from parent
+ * and avoid the need to wait(2).
+ */
+ if ((xpid = fork()) == -1) {
+ errmsg("rcmdsh: fork to lose parent failed.\n");
+ _exit(EX_BAD);
+ /* NOTREACHED */
+ }
+ if (xpid > 0) {
+ _exit(0);
+ /* NOTREACHED */
+ }
+
+ /*
+ * Always use remote shell programm (even for localhost).
+ * The client command may call getpeername() for security
+ * reasons and this would fail on a simple pipe.
+ */
+
+
+ /*
+ * By default, 'rsh' handles terminal created signals
+ * but this is not what we like.
+ * For this reason, we tell 'rsh' to ignore these signals.
+ * Ignoring these signals is important to allow 'star' / 'sdd'
+ * to e.g. implement SIGQUIT as signal to trigger intermediate
+ * status printing.
+ *
+ * For now (late 2002), we know that the following programs
+ * are broken and do not implement signal handling correctly:
+ *
+ * rsh on SunOS-5.0...SunOS-5.9
+ * ssh from ssh.com
+ * ssh from openssh.org
+ *
+ * Sun already did accept a bug report for 'rsh'. For the ssh
+ * commands we need to send out bug reports. Meanwhile it could
+ * help to call setsid() if we are running under X so the ssh
+ * X pop up for passwd reading will work.
+ */
+ signal(SIGINT, SIG_IGN);
+ signal(SIGQUIT, SIG_IGN);
+#ifdef SIGTSTP
+ signal(SIGTSTP, SIG_IGN); /* We would not be able to continue*/
+#endif
+
+ av0 = rsh;
+ if ((p = strrchr(rsh, '/')) != NULL)
+ av0 = ++p;
+ execlp(rsh, av0, *ahost, "-l", remuser, cmd, (char *)NULL);
+
+ errmsg("execlp '%s' failed.\n", rsh);
+ _exit(EX_BAD);
+ /* NOTREACHED */
+ } else {
+ (void) close(pp[1]);
+ /*
+ * Wait for the intermediate child.
+ * The real 'rsh' program is completely detached from us.
+ */
+ wait(0);
+ return (pp[0]);
+ }
+ return (-1); /* keep gcc happy */
+}
+
+#ifdef HAVE_GETPPRIV
+#include <priv.h>
+
+LOCAL BOOL
+ppriv_ok()
+{
+ priv_set_t *privset;
+ BOOL net_privaddr = FALSE;
+
+
+ if ((privset = priv_allocset()) == NULL) {
+ return (FALSE);
+ }
+ if (getppriv(PRIV_EFFECTIVE, privset) == -1) {
+ priv_freeset(privset);
+ return (FALSE);
+ }
+ if (priv_ismember(privset, PRIV_NET_PRIVADDR)) {
+ net_privaddr = TRUE;
+ }
+ priv_freeset(privset);
+
+ return (net_privaddr);
+}
+#endif /* HAVE_GETPPRIV */
+
+#endif /* USE_RCMD_RSH */
+
+#endif /* USE_REMOTE */