diff options
Diffstat (limited to 'netscsid/netscsid.c')
-rw-r--r-- | netscsid/netscsid.c | 972 |
1 files changed, 972 insertions, 0 deletions
diff --git a/netscsid/netscsid.c b/netscsid/netscsid.c new file mode 100644 index 0000000..df2f6b4 --- /dev/null +++ b/netscsid/netscsid.c @@ -0,0 +1,972 @@ +/* + * 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 */ |