Logo Search packages:      
Sourcecode: cdrkit version File versions  Download package

scsi-remote.c

/*
 * 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 */

Generated by  Doxygen 1.6.0   Back to index