/*
* 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.
*
*/
/* @(#)rscsi.c 1.29 05/05/16 Copyright 1994,2000-2002 J. Schilling*/
/*
* Remote SCSI server
*
* Copyright (c) 1994,2000-2002 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.
*/
/*#define FORCE_DEBUG*/
#include <mconfig.h>
#include <stdio.h>
#include <stdxlib.h>
#include <unixstd.h> /* includes <sys/types.h> */
#include <utypes.h>
#include <fctldefs.h>
#include <statdefs.h>
#include <strdefs.h>
#ifdef HAVE_SYS_SOCKET_H
#define USE_REMOTE
#include <sys/socket.h>
#endif
#ifdef HAVE_SYS_PARAM_H
#include <sys/param.h> /* BSD-4.2 & Linux need this for MAXHOSTNAMELEN */
#endif
#include <errno.h>
#include <pwd.h>
#include <standard.h>
#include <deflts.h>
#include <patmatch.h>
#include <schily.h>
#include <usal/usalcmd.h>
#include <usal/scsitransp.h>
#include <netinet/in.h>
#ifdef HAVE_ARPA_INET_H
#include <arpa/inet.h> /* BeOS does not have <arpa/inet.h> */
#endif /* but inet_ntaoa() is in <netdb.h> */
#ifdef HAVE_NETDB_H
#include <netdb.h>
#endif
#ifdef USE_REMOTE
static void checkuser(void);
static char *getpeer(void);
static BOOL checktarget(void);
static void dorscsi(void);
static void scsiversion(void);
static void openscsi(void);
static void closescsi(void);
static void maxdma(void);
static void getbuf(void);
static void freebuf(void);
static void havebus(void);
static void scsifileno(void);
static void initiator_id(void);
static void isatapi(void);
static void scsireset(void);
static void sendcmd(void);
static int fillrdbuf(void);
static int readchar(char *cp);
static void readbuf(char *buf, int n);
static void voidarg(int n);
static void readarg(char *buf, int n);
static char *preparebuffer(int size);
static int checkscsi(char *decive);
static void rscsirespond(int ret, int err);
static void rscsireply(int ret);
static void rscsierror(int err, char *str, char *xstr);
#define CMD_SIZE 80
static SCSI *scsi_ptr = NULL;
static char *Sbuf;
static long Sbufsize;
static char *username;
static char *peername;
static char *debug_name;
static FILE *debug_file;
#define DEBUG(fmt) if (debug_file) fprintf(debug_file, fmt)
#define DEBUG1(fmt,a) if (debug_file) fprintf(debug_file, fmt, a)
#define DEBUG2(fmt,a1,a2) if (debug_file) fprintf(debug_file, fmt, a1, a2)
#define DEBUG3(fmt,a1,a2,a3) if (debug_file) fprintf(debug_file, fmt, a1, a2, a3)
#define DEBUG4(fmt,a1,a2,a3,a4) if (debug_file) fprintf(debug_file, fmt, a1, a2, a3, a4)
#define DEBUG5(fmt,a1,a2,a3,a4,a5) if (debug_file) fprintf(debug_file, fmt, a1, a2, a3, a4, a5)
#define DEBUG6(fmt,a1,a2,a3,a4,a5,a6) if (debug_file) fprintf(debug_file, fmt, a1, a2, a3, a4, a5, a6)
#endif /* USE_REMOTE */
int
main(int argc, char *argv[])
{
save_args(argc, argv);
#ifndef USE_REMOTE
comerrno(EX_BAD, "No remote SCSI support on this platform.\n");
#else
argc--, argv++;
if (argc > 0 && strcmp(*argv, "-c") == 0) {
/*
* Skip params in case we have been installed as shell.
*/
argc--, argv++;
argc--, argv++;
}
/*
* WARNING you are only allowed to change the defaults configuration
* filename if you also change the documentation and add a statement
* that makes clear where the official location of the file is, why you
* did choose a nonstandard location and that the nonstandard location
* only refers to inofficial rscsi versions.
*
* I was forced to add this because some people change cdrecord without
* rational reason and then publish the result. As those people
* don't contribute work and don't give support, they are causing extra
* work for me and this way slow down the development.
*/
if (cfg_open("/etc/netscsid.conf") < 0) {
rscsierror(geterrno(), errmsgstr(geterrno()),
"Remote configuration error: Cannot open /etc/netscsid.conf");
/* rscsirespond(-1, geterrno());*/
exit(EX_BAD);
}
debug_name=cfg_get("DEBUG");
#ifdef FORCE_DEBUG
if (debug_name == NULL && argc <= 0)
debug_name = "/tmp/RSCSI";
#endif
#ifdef NONONO
/*
* Should we allow root to shoot himself into the foot?
* Allowing to write arbitrary files may be a security risk.
*/
if (argc > 0 && getuid() == 0)
debug_name = *argv;
#endif
/*
* XXX If someone sets up debugging and allows the debug file to be
* XXX replaced by a symlink to e.g. /etc/passwd this would be a
* XXX security risk. But /etc/rscsi.conf is only writable by root
* XXX and for this reason a possible security risk would have been
* XXX introduced by the administrator.
*/
if (debug_name != NULL) {
/* Try to be careful when opening debug files, might be
* created in an unsafe location
* */
int fd = open(debug_name, O_CREAT | O_EXCL | O_TRUNC | O_RDWR, 0600);
if (fd > -1)
debug_file = fdopen(fd, "w");
else {
rscsirespond(-1, geterrno());
exit(EX_BAD);
}
}
if (argc > 0) {
if (debug_file == 0) {
rscsirespond(-1, geterrno());
exit(EX_BAD);
}
(void) setbuf(debug_file, (char *)0);
}
checkuser(); /* Check if we are called by a bad guy */
peername = getpeer(); /* Get host name of caller */
dorscsi();
#endif /* USE_REMOTE */
return (0);
}
#ifdef USE_REMOTE
static void
checkuser()
{
uid_t uid = getuid();
char *uname;
struct passwd *pw;
if (uid == 0) {
username = "root";
DEBUG("rscsid: user id 0, name root\n");
return;
}
pw = getpwuid(uid);
if (pw == NULL)
goto notfound;
username = pw->pw_name;
DEBUG2("rscsid: user id %ld, name %s\n", (long)uid, username);
cfg_restart();
while ((uname = cfg_get_next("USER")) != NULL) {
if (0==strcmp(username, uname))
return;
}
notfound:
DEBUG2("rscsid: Illegal user '%s' id %ld for RSCSI server\n",
username, (long)uid);
rscsierror(0, "Illegal user id for RSCSI server", NULL);
exit(EX_BAD);
}
#ifndef NI_MAXHOST
#ifdef MAXHOSTNAMELEN /* XXX remove this and sys/param.h */
#define NI_MAXHOST MAXHOSTNAMELEN
#else
#define NI_MAXHOST 64
#endif
#endif
static char *
getpeer()
{
#ifdef HAVE_GETNAMEINFO
#ifdef HAVE_SOCKADDR_STORAGE
struct sockaddr_storage sa;
#else
char sa[256];
#endif
#else
struct sockaddr sa;
struct hostent *he;
#endif
struct sockaddr *sap;
struct sockaddr_in *s;
socklen_t sasize = sizeof (sa);
static char buffer[NI_MAXHOST];
sap = (struct sockaddr *)&sa;
if (getpeername(STDIN_FILENO, sap, &sasize) < 0) {
int errsav = geterrno();
struct stat sb;
if (fstat(STDIN_FILENO, &sb) >= 0) {
if (S_ISFIFO(sb.st_mode)) {
DEBUG("rmt: stdin is a PIPE\n");
return ("PIPE");
}
DEBUG1("rscsid: stdin st_mode %0llo\n", (Llong)sb.st_mode);
}
DEBUG1("rscsid: peername %s\n", errmsgstr(errsav));
return ("ILLEGAL_SOCKET");
} else {
s = (struct sockaddr_in *)&sa;
#ifdef AF_INET6
if (s->sin_family != AF_INET && s->sin_family != AF_INET6) {
#else
if (s->sin_family != AF_INET) {
#endif
#ifdef AF_UNIX
/*
* AF_UNIX is not defined on BeOS
*/
if (s->sin_family == AF_UNIX) {
DEBUG("rmt: stdin is a PIPE (UNIX domain socket)\n");
return ("PIPE");
}
#endif
DEBUG1("rmt: stdin NOT_IP socket (sin_family: %d)\n",
s->sin_family);
return ("NOT_IP");
}
#ifdef HAVE_GETNAMEINFO
buffer[0] = '\0';
if (debug_file &&
getnameinfo(sap, sasize, buffer, sizeof (buffer), NULL, 0,
NI_NUMERICHOST) == 0) {
DEBUG1("rmt: peername %s\n", buffer);
}
buffer[0] = '\0';
if (getnameinfo(sap, sasize, buffer, sizeof (buffer), NULL, 0,
0) == 0) {
DEBUG1("rmt: peername %s\n", buffer);
return (buffer);
}
return ("CANNOT_MAP_ADDRESS");
#else /* HAVE_GETNAMEINFO */
#ifdef HAVE_INET_NTOA
(void) snprintf(buffer, sizeof(buffer), "%s", inet_ntoa(s->sin_addr));
#else
(void) snprintf(buffer, sizeof(buffer), "%x", s->sin_addr.s_addr);
#endif
DEBUG1("rscsid: peername %s\n", buffer);
he = gethostbyaddr((char *)&s->sin_addr.s_addr, 4, AF_INET);
DEBUG1("rscsid: peername %s\n", he!=NULL?he->h_name:buffer);
if (he != NULL)
return (he->h_name);
return (buffer);
#endif /* HAVE_GETNAMEINFO */
}
}
static BOOL
checktarget()
{
char *target;
char *user;
char *host;
char *p;
int bus;
int chan;
int tgt;
int lun;
if (peername == NULL)
return (FALSE);
cfg_restart();
while ((target = cfg_get_next("ACCESS")) != NULL) {
p = target;
while (*p == '\t')
p++;
user = p;
if ((p = strchr(p, '\t')) != NULL)
*p++ = '\0';
else
continue;
if (0!=strcmp(username, user))
continue;
while (*p == '\t')
p++;
host = p;
if ((p = strchr(p, '\t')) != NULL)
*p++ = '\0';
else
continue;
if (0!=strcmp(peername, host))
continue;
p = astoi(p, &bus);
if (*p != '\t')
continue;
p = astoi(p, &chan);
if (*p != '\t')
continue;
p = astoi(p, &tgt);
if (*p != '\t')
continue;
p = astoi(p, &lun);
if (*p != '\t' && *p != '\n' && *p != '\r' && *p != '\0')
continue;
DEBUG6("ACCESS %s %s %d.%d,%d,%d\n", user, host, bus, chan, tgt, lun);
if (bus != -1 && bus != usal_scsibus(scsi_ptr))
continue;
if (tgt != -1 && tgt != usal_target(scsi_ptr))
continue;
if (lun != -1 && lun != usal_lun(scsi_ptr))
continue;
return (TRUE);
}
return (FALSE);
}
static void
dorscsi()
{
char c;
while (readchar(&c) == 1) {
seterrno(0);
switch (c) {
case 'V': /* "V" ersion */
scsiversion();
break;
case 'O': /* "O" pen */
openscsi();
break;
case 'C': /* "C" lose */
closescsi();
break;
case 'D': /* "D" MA */
maxdma();
break;
case 'M': /* "M" alloc */
getbuf();
break;
case 'F': /* "F" free */
freebuf();
break;
case 'B': /* "B" us */
havebus();
break;
case 'T': /* "T" arget */
scsifileno();
break;
case 'I': /* "I" nitiator */
initiator_id();
break;
case 'A': /* "A" tapi */
isatapi();
break;
case 'R': /* "R" eset */
scsireset();
break;
case 'S': /* "S" end */
sendcmd();
break;
default:
DEBUG1("rscsid: garbage command '%c'\n", c);
rscsierror(0, "Garbage command", NULL);
exit(EX_BAD);
}
}
exit(0);
}
static void
scsiversion()
{
int ret;
char *str;
char what[CMD_SIZE];
readarg(what, sizeof(what));
DEBUG1("rscsid: V %s\n", what);
if (scsi_ptr == NULL) {
rscsirespond(-1, EBADF);
return;
}
str = usal_version(scsi_ptr, atoi(what));
ret = strlen(str);
ret++; /* Include null char */
rscsirespond(ret, geterrno());
_nixwrite(STDOUT_FILENO, str, ret);
}
static void
openscsi()
{
char device[CMD_SIZE];
char errstr[80];
int debug = 0;
int lverbose = 0;
int ret = 0;
char rbuf[1600];
if (scsi_ptr != NULL)
(void) usal_close(scsi_ptr);
readarg(device, sizeof(device));
DEBUG1("rscsid: O %s\n", device);
if (strncmp(device, "REMOTE", 6) == 0) {
scsi_ptr = NULL;
seterrno(EINVAL);
} else if (!checkscsi(device)) {
scsi_ptr = NULL;
seterrno(EACCES);
} else {
scsi_ptr = usal_open(device, errstr, sizeof(errstr), debug, lverbose);
if (scsi_ptr == NULL) {
ret = -1;
} else {
scsi_ptr->silent = 1;
scsi_ptr->verbose = 0;
scsi_ptr->debug = 0;
scsi_ptr->kdebug = 0;
}
}
if (ret < 0) {
/*
* XXX This is currently the only place where we use the
* XXX extended error string.
*/
rscsierror(geterrno(), errmsgstr(geterrno()), errstr);
/* rscsirespond(ret, geterrno());*/
return;
}
DEBUG4("rscsid:>A 0 %d.%d,%d,%d\n",
usal_scsibus(scsi_ptr),
0,
usal_target(scsi_ptr),
usal_lun(scsi_ptr));
ret = snprintf(rbuf, sizeof(rbuf), "A0\n%d\n%d\n%d\n%d\n",
usal_scsibus(scsi_ptr),
0,
usal_target(scsi_ptr),
usal_lun(scsi_ptr));
(void) _nixwrite(STDOUT_FILENO, rbuf, ret);
}
static void
closescsi()
{
int ret;
char device[CMD_SIZE];
readarg(device, sizeof(device));
DEBUG1("rscsid: C %s\n", device);
ret = usal_close(scsi_ptr);
rscsirespond(ret, geterrno());
scsi_ptr = NULL;
}
static void
maxdma()
{
int ret;
char amt[CMD_SIZE];
readarg(amt, sizeof(amt));
DEBUG1("rscsid: D %s\n", amt);
if (scsi_ptr == NULL) {
rscsirespond(-1, EBADF);
return;
}
ret = usal_bufsize(scsi_ptr, atol(amt));
rscsirespond(ret, geterrno());
}
static void
getbuf()
{
int ret = 0;
char amt[CMD_SIZE];
readarg(amt, sizeof(amt));
DEBUG1("rscsid: M %s\n", amt);
if (scsi_ptr == NULL) {
rscsirespond(-1, EBADF);
return;
}
ret = usal_bufsize(scsi_ptr, atol(amt));
if (preparebuffer(ret) == NULL)
ret = -1;
rscsirespond(ret, geterrno());
}
static void
freebuf()
{
int ret = 0;
char dummy[CMD_SIZE];
readarg(dummy, sizeof(dummy));
DEBUG1("rscsid: F %s\n", dummy);
if (scsi_ptr == NULL) {
rscsirespond(-1, EBADF);
return;
}
usal_freebuf(scsi_ptr);
Sbuf = NULL;
rscsirespond(ret, geterrno());
}
static void
havebus()
{
int ret;
char bus[CMD_SIZE];
char chan[CMD_SIZE];
readarg(bus, sizeof(bus));
readarg(chan, sizeof(chan));
DEBUG2("rscsid: B %s.%s\n", bus, chan);
if (scsi_ptr == NULL) {
rscsirespond(-1, EBADF);
return;
}
ret = usal_havebus(scsi_ptr, atol(bus));
rscsirespond(ret, geterrno());
}
static void
scsifileno()
{
int ret;
char bus[CMD_SIZE];
char chan[CMD_SIZE];
char tgt[CMD_SIZE];
char lun[CMD_SIZE];
readarg(bus, sizeof(bus));
readarg(chan, sizeof(chan));
readarg(tgt, sizeof(tgt));
readarg(lun, sizeof(lun));
DEBUG4("rscsid: T %s.%s,%s,%s\n", bus, chan, tgt, lun);
if (scsi_ptr == NULL) {
rscsirespond(-1, EBADF);
return;
}
seterrno(0);
ret = usal_settarget(scsi_ptr, atoi(bus), atoi(tgt), atoi(lun));
if (!checktarget()) {
usal_settarget(scsi_ptr, -1, -1, -1);
ret = -1;
}
if (geterrno() != 0)
rscsirespond(ret, geterrno());
else
rscsireply(ret);
}
static void
initiator_id()
{
int ret;
char dummy[CMD_SIZE];
readarg(dummy, sizeof(dummy));
DEBUG1("rscsid: I %s\n", dummy);
if (scsi_ptr == NULL) {
rscsirespond(-1, EBADF);
return;
}
seterrno(0);
ret = usal_initiator_id(scsi_ptr);
if (geterrno() != 0)
rscsirespond(ret, geterrno());
else
rscsireply(ret);
}
static void
isatapi()
{
int ret;
char dummy[CMD_SIZE];
readarg(dummy, sizeof(dummy));
DEBUG1("rscsid: A %s\n", dummy);
if (scsi_ptr == NULL) {
rscsirespond(-1, EBADF);
return;
}
seterrno(0);
ret = usal_isatapi(scsi_ptr);
if (geterrno() != 0)
rscsirespond(ret, geterrno());
else
rscsireply(ret);
}
static void
scsireset()
{
int ret;
char what[CMD_SIZE];
readarg(what, sizeof(what));
DEBUG1("rscsid: R %s\n", what);
if (scsi_ptr == NULL) {
rscsirespond(-1, EBADF);
return;
}
ret = usal_reset(scsi_ptr, atoi(what));
rscsirespond(ret, geterrno());
}
static void
sendcmd()
{
register struct usal_cmd *scmd;
int n;
int ret;
char count[CMD_SIZE];
char flags[CMD_SIZE];
char cdb_len[CMD_SIZE];
char sense_len[CMD_SIZE];
char timeout[CMD_SIZE];
int csize;
int cflags;
int clen;
int ctimeout;
char rbuf[1600];
char *p;
/*
* S count\n
* flags\n
* cdb_len\n
* sense_len\n
* timeout\n
* <data if available>
*
* Timeout:
* - sss (e.g. 10)
* - sss.uuu (e.g. 10.23)
*/
readarg(count, sizeof(count));
readarg(flags, sizeof(flags));
readarg(cdb_len, sizeof(cdb_len));
readarg(sense_len, sizeof(sense_len));
readarg(timeout, sizeof(timeout));
DEBUG5("rscsid: S %s %s %s %s %s", count, flags, cdb_len, sense_len, timeout);
csize = atoi(count);
cflags = atoi(flags);
clen = atoi(cdb_len);
p = strchr(timeout, '.');
if (p)
*p = '\0';
ctimeout = atoi(timeout);
if (scsi_ptr == NULL || clen > SCG_MAX_CMD || csize > Sbufsize) {
DEBUG("\n");
voidarg(clen);
if ((cflags & SCG_RECV_DATA) == 0 && csize > 0)
voidarg(csize);
rscsirespond(-1, scsi_ptr==NULL ? EBADF : EINVAL);
return;
}
scmd = scsi_ptr->scmd;
fillbytes((caddr_t)scmd, sizeof(*scmd), '\0');
scmd->addr = (caddr_t)Sbuf;
scmd->size = csize;
scmd->flags = cflags;
scmd->cdb_len = clen;
scmd->sense_len = atoi(sense_len);
scmd->timeout = ctimeout;
readbuf((char *)scmd->cdb.cmd_cdb, clen);
DEBUG6(" 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X\n",
scmd->cdb.cmd_cdb[0],
scmd->cdb.cmd_cdb[1],
scmd->cdb.cmd_cdb[2],
scmd->cdb.cmd_cdb[3],
scmd->cdb.cmd_cdb[4],
scmd->cdb.cmd_cdb[5]);
if ((cflags & SCG_RECV_DATA) == 0 && csize > 0)
readbuf(Sbuf, scmd->size);
scsi_ptr->cmdname = "";
ret = usal_cmd(scsi_ptr);
n = 0;
if ((csize - scmd->resid) > 0)
n = csize - scmd->resid;
/*
* A count\n
* error\n
* errno\n
* scb\n
* sense_count\n
* <data if available>
*/
DEBUG5("rscsid:>A %d %d %d %d %d\n",
n,
scmd->error,
scmd->ux_errno,
*(Uchar *)&scmd->scb,
scmd->sense_count);
ret = snprintf(rbuf, sizeof(rbuf), "A%d\n%d\n%d\n%d\n%d\n",
n,
scmd->error,
scmd->ux_errno,
*(Uchar *)&scmd->scb,
scmd->sense_count);
if (scmd->sense_count > 0) {
movebytes(scmd->u_sense.cmd_sense, &rbuf[ret], scmd->sense_count);
ret += scmd->sense_count;
}
if ((cflags & SCG_RECV_DATA) == 0)
n = 0;
if (n > 0 && ((ret + n) <= sizeof(rbuf))) {
movebytes(Sbuf, &rbuf[ret], n);
ret += n;
n = 0;
}
(void) _nixwrite(STDOUT_FILENO, rbuf, ret);
if (n > 0)
(void) _nixwrite(STDOUT_FILENO, Sbuf, n);
}
#define READB_SIZE 128
static char readb[READB_SIZE];
static char *readbptr;
static int readbcnt;
static int
fillrdbuf()
{
readbptr = readb;
return (readbcnt = _niread(STDIN_FILENO, readb, READB_SIZE));
}
static int
readchar(char *cp)
{
if (--readbcnt < 0) {
if (fillrdbuf() <= 0)
return (readbcnt);
--readbcnt;
}
*cp = *readbptr++;
return (1);
}
static void
readbuf(register char *buf, register int n)
{
register int i = 0;
register int amt;
if (readbcnt > 0) {
amt = readbcnt;
if (amt > n)
amt = n;
movebytes(readbptr, buf, amt);
readbptr += amt;
readbcnt -= amt;
i += amt;
}
for (; i < n; i += amt) {
amt = _niread(STDIN_FILENO, &buf[i], n - i);
if (amt <= 0) {
DEBUG("rscsid: premature eof\n");
rscsierror(0, "Premature eof", NULL);
exit(EX_BAD);
}
}
}
static void
voidarg(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;
readbuf(buf, amt);
}
}
static void
readarg(char *buf, int n)
{
int i;
for (i = 0; i < n; i++) {
if (readchar(&buf[i]) != 1)
exit(0);
if (buf[i] == '\n')
break;
}
buf[i] = '\0';
}
static char *
preparebuffer(int size)
{
Sbufsize = size;
if ((Sbuf = usal_getbuf(scsi_ptr, Sbufsize)) == NULL) {
Sbufsize = 0L;
return (Sbuf);
}
size = Sbufsize + 1024; /* Add protocol overhead */
#ifdef SO_SNDBUF
while (size > 512 &&
setsockopt(STDOUT_FILENO, SOL_SOCKET, SO_SNDBUF, (char *)&size, sizeof (size)) < 0)
size -= 512;
DEBUG1("rscsid: sndsize: %d\n", size);
#endif
#ifdef SO_RCVBUF
while (size > 512 &&
setsockopt(STDIN_FILENO, SOL_SOCKET, SO_RCVBUF, (char *)&size, sizeof (size)) < 0)
size -= 512;
DEBUG1("rscsid: rcvsize: %d\n", size);
#endif
return (Sbuf);
}
static int
checkscsi(char *device)
{
#ifdef CHECKTAPE
if (strncmp(device, "/dev/rst", 8) == 0 ||
strncmp(device, "/dev/nrst", 9) == 0 ||
strcmp(device, "/dev/zero") == 0 ||
strcmp(device, "/dev/null") == 0)
return (1);
return (0);
#else
return (1);
#endif
}
static void
rscsirespond(int ret, int err)
{
if (ret < 0) {
rscsierror(err, errmsgstr(err), NULL);
} else {
rscsireply(ret);
}
}
static void
rscsireply(int ret)
{
char rbuf[CMD_SIZE];
DEBUG1("rscsid:>A %d\n", ret);
(void) snprintf(rbuf, sizeof(rbuf), "A%d\n", ret);
(void) _nixwrite(STDOUT_FILENO, rbuf, strlen(rbuf));
}
static void
rscsierror(int err, char *str, char *xstr)
{
char rbuf[1600];
int xlen = 0;
int n;
if (xstr != NULL)
xlen = strlen(xstr) + 1;
DEBUG3("rscsid:>E %d (%s) [%s]\n", err, str, xstr?xstr:"");
n = snprintf(rbuf, sizeof(rbuf), "E%d\n%s\n%d\n", err, str, xlen);
if (xlen > 0 && ((xlen + n) <= sizeof(rbuf))) {
movebytes(xstr, &rbuf[n], xlen);
n += xlen;
xlen = 0;
}
(void) _nixwrite(STDOUT_FILENO, rbuf, n);
if (xlen > 0)
(void) _nixwrite(STDOUT_FILENO, xstr, xlen);
}
#endif /* USE_REMOTE */
syntax highlighted by Code2HTML, v. 0.9.1