Imported Upstream version 1.1.11
[platform/upstream/cdrkit.git] / netscsid / netscsid.c
1 /*
2  * This file has been modified for the cdrkit suite.
3  *
4  * The behaviour and appearence of the program code below can differ to a major
5  * extent from the version distributed by the original author(s).
6  *
7  * For details, see Changelog file distributed with the cdrkit package. If you
8  * received this file from another source then ask the distributing person for
9  * a log of modifications.
10  *
11  */
12
13 /* @(#)rscsi.c  1.29 05/05/16 Copyright 1994,2000-2002 J. Schilling*/
14 /*
15  *      Remote SCSI server
16  *
17  *      Copyright (c) 1994,2000-2002 J. Schilling
18  */
19 /*
20  * This program is free software; you can redistribute it and/or modify
21  * it under the terms of the GNU General Public License version 2
22  * as published by the Free Software Foundation.
23  *
24  * This program is distributed in the hope that it will be useful,
25  * but WITHOUT ANY WARRANTY; without even the implied warranty of
26  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
27  * GNU General Public License for more details.
28  *
29  * You should have received a copy of the GNU General Public License along with
30  * this program; see the file COPYING.  If not, write to the Free Software
31  * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
32  */
33
34 /*#define       FORCE_DEBUG*/
35
36 #include <mconfig.h>
37
38 #include <stdio.h>
39 #include <stdxlib.h>
40 #include <unixstd.h>    /* includes <sys/types.h> */
41 #include <utypes.h>
42 #include <fctldefs.h>
43 #include <statdefs.h>
44 #include <strdefs.h>
45 #ifdef  HAVE_SYS_SOCKET_H
46 #define USE_REMOTE
47 #include <sys/socket.h>
48 #endif
49 #ifdef   HAVE_SYS_PARAM_H
50 #include <sys/param.h>  /* BSD-4.2 & Linux need this for MAXHOSTNAMELEN */
51 #endif
52 #include <errno.h>
53 #include <pwd.h>
54
55 #include <standard.h>
56 #include <deflts.h>
57 #include <patmatch.h>
58 #include <schily.h>
59
60 #include <usal/usalcmd.h>
61 #include <usal/scsitransp.h>
62
63 #include <netinet/in.h>
64 #ifdef  HAVE_ARPA_INET_H
65 #include <arpa/inet.h>          /* BeOS does not have <arpa/inet.h> */
66 #endif                          /* but inet_ntaoa() is in <netdb.h> */
67 #ifdef  HAVE_NETDB_H
68 #include <netdb.h>
69 #endif
70
71 #ifdef  USE_REMOTE
72 static  void    checkuser(void);
73 static  char    *getpeer(void);
74 static  BOOL    checktarget(void);
75 static  void    dorscsi(void);
76 static  void    scsiversion(void);
77 static  void    openscsi(void);
78 static  void    closescsi(void);
79 static  void    maxdma(void);
80 static  void    getbuf(void);
81 static  void    freebuf(void);
82 static  void    havebus(void);
83 static  void    scsifileno(void);
84 static  void    initiator_id(void);
85 static  void    isatapi(void);
86 static  void    scsireset(void);
87 static  void    sendcmd(void);
88
89 static  int     fillrdbuf(void);
90 static  int     readchar(char *cp);
91
92 static  void    readbuf(char *buf, int n);
93 static  void    voidarg(int n);
94 static  void    readarg(char *buf, int n);
95 static  char *preparebuffer(int size);
96 static  int     checkscsi(char *decive);
97 static  void    rscsirespond(int ret, int err);
98 static  void    rscsireply(int ret);
99 static  void    rscsierror(int err, char *str, char *xstr);
100
101 #define CMD_SIZE        80
102
103 static  SCSI    *scsi_ptr = NULL;
104 static  char    *Sbuf;
105 static  long    Sbufsize;
106
107 static  char    *username;
108 static  char    *peername;
109
110 static  char    *debug_name;
111 static  FILE    *debug_file;
112
113 #define DEBUG(fmt)              if (debug_file) fprintf(debug_file, fmt)
114 #define DEBUG1(fmt,a)           if (debug_file) fprintf(debug_file, fmt, a)
115 #define DEBUG2(fmt,a1,a2)       if (debug_file) fprintf(debug_file, fmt, a1, a2)
116 #define DEBUG3(fmt,a1,a2,a3)    if (debug_file) fprintf(debug_file, fmt, a1, a2, a3)
117 #define DEBUG4(fmt,a1,a2,a3,a4) if (debug_file) fprintf(debug_file, fmt, a1, a2, a3, a4)
118 #define DEBUG5(fmt,a1,a2,a3,a4,a5)      if (debug_file) fprintf(debug_file, fmt, a1, a2, a3, a4, a5)
119 #define DEBUG6(fmt,a1,a2,a3,a4,a5,a6)   if (debug_file) fprintf(debug_file, fmt, a1, a2, a3, a4, a5, a6)
120 #endif  /* USE_REMOTE */
121
122 int
123 main(int argc, char *argv[])
124 {
125         save_args(argc, argv);
126 #ifndef USE_REMOTE
127         comerrno(EX_BAD, "No remote SCSI support on this platform.\n");
128 #else
129         argc--, argv++;
130         if (argc > 0 && strcmp(*argv, "-c") == 0) {
131                 /*
132                  * Skip params in case we have been installed as shell.
133                  */
134                 argc--, argv++;
135                 argc--, argv++;
136         }
137         /*
138          * WARNING you are only allowed to change the defaults configuration
139          * filename if you also change the documentation and add a statement
140          * that makes clear where the official location of the file is, why you
141          * did choose a nonstandard location and that the nonstandard location
142          * only refers to inofficial rscsi versions.
143          *
144          * I was forced to add this because some people change cdrecord without
145          * rational reason and then publish the result. As those people
146          * don't contribute work and don't give support, they are causing extra
147          * work for me and this way slow down the development.
148          */
149         if (cfg_open("/etc/netscsid.conf") < 0) {
150                 rscsierror(geterrno(), errmsgstr(geterrno()),
151                         "Remote configuration error: Cannot open /etc/netscsid.conf");
152 /*              rscsirespond(-1, geterrno());*/
153                 exit(EX_BAD);
154         }
155         debug_name=cfg_get("DEBUG");
156 #ifdef  FORCE_DEBUG
157         if (debug_name == NULL && argc <= 0)
158                 debug_name = "/tmp/RSCSI";
159 #endif
160 #ifdef  NONONO
161         /*
162          * Should we allow root to shoot himself into the foot?
163          * Allowing to write arbitrary files may be a security risk.
164          */
165         if (argc > 0 && getuid() == 0)
166                 debug_name = *argv;
167 #endif
168
169         /*
170          * XXX If someone sets up debugging and allows the debug file to be
171          * XXX replaced by a symlink to e.g. /etc/passwd this would be a
172          * XXX security risk. But /etc/rscsi.conf is only writable by root
173          * XXX and for this reason a possible security risk would have been
174          * XXX introduced by the administrator.
175          */
176     if (debug_name != NULL) {
177         /* Try to be careful when opening debug files, might be
178          * created in an unsafe location 
179          * */
180         int fd = open(debug_name, O_CREAT | O_EXCL | O_TRUNC | O_RDWR, 0600);
181         if (fd > -1) 
182             debug_file = fdopen(fd, "w");
183         else {
184             rscsirespond(-1, geterrno());
185             exit(EX_BAD);
186         }
187     } 
188                 
189         if (argc > 0) {
190                 if (debug_file == 0) {
191                         rscsirespond(-1, geterrno());
192                         exit(EX_BAD);
193                 }
194                 (void) setbuf(debug_file, (char *)0);
195         }
196         checkuser();            /* Check if we are called by a bad guy  */
197         peername = getpeer();   /* Get host name of caller              */
198         dorscsi();
199 #endif  /* USE_REMOTE */
200         return (0);
201 }
202
203 #ifdef  USE_REMOTE
204 static void
205 checkuser()
206 {
207         uid_t   uid = getuid();
208         char    *uname;
209         struct passwd *pw;
210
211         if (uid == 0) {
212                 username = "root";
213                 DEBUG("rscsid: user id 0, name root\n");
214                 return;
215         }
216         pw = getpwuid(uid);
217         if (pw == NULL)
218                 goto notfound;
219
220         username = pw->pw_name;
221         DEBUG2("rscsid: user id %ld, name %s\n", (long)uid, username);
222
223         cfg_restart();
224         while ((uname = cfg_get_next("USER")) != NULL) {
225                 if (0==strcmp(username, uname))
226                         return;
227         }
228 notfound:
229         DEBUG2("rscsid: Illegal user '%s' id %ld for RSCSI server\n",
230                                                 username, (long)uid);
231         rscsierror(0, "Illegal user id for RSCSI server", NULL);
232         exit(EX_BAD);
233 }
234
235 #ifndef NI_MAXHOST
236 #ifdef  MAXHOSTNAMELEN                  /* XXX remove this and sys/param.h */
237 #define NI_MAXHOST      MAXHOSTNAMELEN
238 #else
239 #define NI_MAXHOST      64
240 #endif
241 #endif
242
243 static char *
244 getpeer()
245 {
246 #ifdef  HAVE_GETNAMEINFO
247 #ifdef  HAVE_SOCKADDR_STORAGE
248         struct sockaddr_storage sa;
249 #else
250         char                    sa[256];
251 #endif
252 #else
253         struct  sockaddr sa;
254         struct hostent  *he;
255 #endif
256         struct  sockaddr *sap;
257         struct  sockaddr_in *s;
258         socklen_t        sasize = sizeof (sa);
259 static  char            buffer[NI_MAXHOST];
260
261         sap = (struct  sockaddr *)&sa;
262         if (getpeername(STDIN_FILENO, sap, &sasize) < 0) {
263                 int             errsav = geterrno();
264                 struct stat     sb;
265
266                 if (fstat(STDIN_FILENO, &sb) >= 0) {
267                         if (S_ISFIFO(sb.st_mode)) {
268                                 DEBUG("rmt: stdin is a PIPE\n");
269                                 return ("PIPE");
270                         }
271                         DEBUG1("rscsid: stdin st_mode %0llo\n", (Llong)sb.st_mode);
272                 }
273
274                 DEBUG1("rscsid: peername %s\n", errmsgstr(errsav));
275                 return ("ILLEGAL_SOCKET");
276         } else {
277                 s = (struct sockaddr_in *)&sa;
278 #ifdef  AF_INET6
279                 if (s->sin_family != AF_INET && s->sin_family != AF_INET6) {
280 #else
281                 if (s->sin_family != AF_INET) {
282 #endif
283 #ifdef  AF_UNIX
284                         /*
285                          * AF_UNIX is not defined on BeOS
286                          */
287                         if (s->sin_family == AF_UNIX) {
288                                 DEBUG("rmt: stdin is a PIPE (UNIX domain socket)\n");
289                                 return ("PIPE");
290                         }
291 #endif
292                         DEBUG1("rmt: stdin NOT_IP socket (sin_family: %d)\n",
293                                                         s->sin_family);
294                         return ("NOT_IP");
295                 }
296                
297 #ifdef  HAVE_GETNAMEINFO
298                 buffer[0] = '\0';
299                 if (debug_file &&
300                     getnameinfo(sap, sasize, buffer, sizeof (buffer), NULL, 0,
301                     NI_NUMERICHOST) == 0) {
302                         DEBUG1("rmt: peername %s\n", buffer);
303                 }
304                 buffer[0] = '\0';
305                 if (getnameinfo(sap, sasize, buffer, sizeof (buffer), NULL, 0,
306                     0) == 0) {
307                         DEBUG1("rmt: peername %s\n", buffer);
308                         return (buffer);
309                 }
310                 return ("CANNOT_MAP_ADDRESS");
311 #else   /* HAVE_GETNAMEINFO */
312 #ifdef  HAVE_INET_NTOA
313                 (void) snprintf(buffer, sizeof(buffer), "%s", inet_ntoa(s->sin_addr));
314 #else
315                 (void) snprintf(buffer, sizeof(buffer), "%x", s->sin_addr.s_addr);
316 #endif
317                 DEBUG1("rscsid: peername %s\n", buffer);
318                 he = gethostbyaddr((char *)&s->sin_addr.s_addr, 4, AF_INET);
319                 DEBUG1("rscsid: peername %s\n", he!=NULL?he->h_name:buffer);
320                 if (he != NULL)
321                         return (he->h_name);
322                 return (buffer);
323 #endif  /* HAVE_GETNAMEINFO */
324         }
325 }
326
327 static BOOL
328 checktarget()
329 {
330         char    *target;
331         char    *user;
332         char    *host;
333         char    *p;
334         int     bus;
335         int     chan;
336         int     tgt;
337         int     lun;
338
339         if (peername == NULL)
340                 return (FALSE);
341   cfg_restart();
342         while ((target = cfg_get_next("ACCESS")) != NULL) {
343                 p = target;
344                 while (*p == '\t')
345                         p++;
346                 user = p;
347                 if ((p = strchr(p, '\t')) != NULL)
348                         *p++ = '\0';
349                 else
350                         continue;
351                 if (0!=strcmp(username, user))
352                         continue;
353
354                 while (*p == '\t')
355                         p++;
356                 host = p;
357                 if ((p = strchr(p, '\t')) != NULL)
358                         *p++ = '\0';
359                 else
360                         continue;
361                 if (0!=strcmp(peername, host))
362                         continue;
363
364                 p = astoi(p, &bus);
365                 if (*p != '\t')
366                         continue;
367                 p = astoi(p, &chan);
368                 if (*p != '\t')
369                         continue;
370                 p = astoi(p, &tgt);
371                 if (*p != '\t')
372                         continue;
373                 p = astoi(p, &lun);
374
375                 if (*p != '\t' && *p != '\n' && *p != '\r' && *p != '\0') 
376                         continue;
377                 DEBUG6("ACCESS %s %s %d.%d,%d,%d\n", user, host, bus, chan, tgt, lun);
378
379                 if (bus != -1 && bus != usal_scsibus(scsi_ptr))
380                         continue;
381                 if (tgt != -1 && tgt != usal_target(scsi_ptr))
382                         continue;
383                 if (lun != -1 && lun != usal_lun(scsi_ptr))
384                         continue;
385                 return (TRUE);
386         }
387         return (FALSE);
388 }
389
390 static void
391 dorscsi()
392 {
393         char    c;
394
395         while (readchar(&c) == 1) {
396                 seterrno(0);
397
398                 switch (c) {
399
400                 case 'V':               /* "V" ersion   */
401                         scsiversion();
402                         break;
403                 case 'O':               /* "O" pen      */
404                         openscsi();
405                         break;
406                 case 'C':               /* "C" lose     */
407                         closescsi();
408                         break;
409                 case 'D':               /* "D" MA       */
410                         maxdma();
411                         break;
412                 case 'M':               /* "M" alloc    */
413                         getbuf();
414                         break;
415                 case 'F':               /* "F" free     */
416                         freebuf();
417                         break;
418                 case 'B':               /* "B" us       */
419                         havebus();
420                         break;
421                 case 'T':               /* "T" arget    */
422                         scsifileno();
423                         break;
424                 case 'I':               /* "I" nitiator */
425                         initiator_id();
426                         break;
427                 case 'A':               /* "A" tapi     */
428                         isatapi();
429                         break;
430                 case 'R':               /* "R" eset     */
431                         scsireset();
432                         break;
433                 case 'S':               /* "S" end      */
434                         sendcmd();
435                         break;
436
437                 default:
438                         DEBUG1("rscsid: garbage command '%c'\n", c);
439                         rscsierror(0, "Garbage command", NULL);
440                         exit(EX_BAD);
441                 }
442         }
443         exit(0);
444 }
445
446 static void
447 scsiversion()
448 {
449         int     ret;
450         char    *str;
451         char    what[CMD_SIZE];
452
453         readarg(what, sizeof(what));
454         DEBUG1("rscsid: V %s\n", what);
455         if (scsi_ptr == NULL) {
456                 rscsirespond(-1, EBADF);
457                 return;
458         }
459         str = usal_version(scsi_ptr, atoi(what));
460         ret = strlen(str);
461         ret++;  /* Include null char */
462         rscsirespond(ret, geterrno());
463         _nixwrite(STDOUT_FILENO, str, ret);
464 }
465
466 static void
467 openscsi()
468 {
469         char    device[CMD_SIZE];
470         char    errstr[80];
471         int     debug = 0;
472         int     lverbose = 0;
473         int     ret = 0;
474         char    rbuf[1600];
475
476         if (scsi_ptr != NULL)
477                 (void) usal_close(scsi_ptr);
478
479         readarg(device, sizeof(device));
480         DEBUG1("rscsid: O %s\n", device);
481         if (strncmp(device, "REMOTE", 6) == 0) {
482                 scsi_ptr = NULL;
483                 seterrno(EINVAL);
484         } else if (!checkscsi(device)) {
485                 scsi_ptr = NULL;
486                 seterrno(EACCES);
487         } else {
488                 scsi_ptr = usal_open(device, errstr, sizeof(errstr), debug, lverbose);
489                 if (scsi_ptr == NULL) {
490                         ret = -1;
491                 } else {
492                         scsi_ptr->silent = 1;
493                         scsi_ptr->verbose = 0;
494                         scsi_ptr->debug = 0;
495                         scsi_ptr->kdebug = 0;
496                 }
497         }
498         if (ret < 0) {
499                 /*
500                  * XXX This is currently the only place where we use the
501                  * XXX extended error string.
502                  */
503                 rscsierror(geterrno(), errmsgstr(geterrno()), errstr);
504 /*              rscsirespond(ret, geterrno());*/
505                 return;
506         }
507         DEBUG4("rscsid:>A 0 %d.%d,%d,%d\n", 
508                 usal_scsibus(scsi_ptr),
509                 0,
510                 usal_target(scsi_ptr),
511                 usal_lun(scsi_ptr));
512
513         ret = snprintf(rbuf, sizeof(rbuf), "A0\n%d\n%d\n%d\n%d\n",
514                 usal_scsibus(scsi_ptr),
515                 0,
516                 usal_target(scsi_ptr),
517                 usal_lun(scsi_ptr));
518         (void) _nixwrite(STDOUT_FILENO, rbuf, ret);
519 }
520
521 static void
522 closescsi()
523 {
524         int     ret;
525         char    device[CMD_SIZE];
526
527         readarg(device, sizeof(device));
528         DEBUG1("rscsid: C %s\n", device);
529         ret = usal_close(scsi_ptr);
530         rscsirespond(ret, geterrno());
531         scsi_ptr = NULL;
532 }
533
534 static void
535 maxdma()
536 {
537         int     ret;
538         char    amt[CMD_SIZE];
539
540         readarg(amt, sizeof(amt));
541         DEBUG1("rscsid: D %s\n", amt);
542         if (scsi_ptr == NULL) {
543                 rscsirespond(-1, EBADF);
544                 return;
545         }
546         ret = usal_bufsize(scsi_ptr, atol(amt));
547         rscsirespond(ret, geterrno());
548 }
549
550 static void
551 getbuf()
552 {
553         int     ret = 0;
554         char    amt[CMD_SIZE];
555
556         readarg(amt, sizeof(amt));
557         DEBUG1("rscsid: M %s\n", amt);
558         if (scsi_ptr == NULL) {
559                 rscsirespond(-1, EBADF);
560                 return;
561         }
562         ret = usal_bufsize(scsi_ptr, atol(amt));
563         if (preparebuffer(ret) == NULL)
564                 ret = -1;
565         rscsirespond(ret, geterrno());
566 }
567
568 static void
569 freebuf()
570 {
571         int     ret = 0;
572         char    dummy[CMD_SIZE];
573
574         readarg(dummy, sizeof(dummy));
575         DEBUG1("rscsid: F %s\n", dummy);
576         if (scsi_ptr == NULL) {
577                 rscsirespond(-1, EBADF);
578                 return;
579         }
580         usal_freebuf(scsi_ptr);
581         Sbuf = NULL;
582         rscsirespond(ret, geterrno());
583 }
584
585 static void
586 havebus()
587 {
588         int     ret;
589         char    bus[CMD_SIZE];
590         char    chan[CMD_SIZE];
591
592         readarg(bus, sizeof(bus));
593         readarg(chan, sizeof(chan));
594         DEBUG2("rscsid: B %s.%s\n", bus, chan);
595         if (scsi_ptr == NULL) {
596                 rscsirespond(-1, EBADF);
597                 return;
598         }
599         ret = usal_havebus(scsi_ptr, atol(bus));
600         rscsirespond(ret, geterrno());
601 }
602
603 static void
604 scsifileno()
605 {
606         int     ret;
607         char    bus[CMD_SIZE];
608         char    chan[CMD_SIZE];
609         char    tgt[CMD_SIZE];
610         char    lun[CMD_SIZE];
611
612         readarg(bus, sizeof(bus));
613         readarg(chan, sizeof(chan));
614         readarg(tgt, sizeof(tgt));
615         readarg(lun, sizeof(lun));
616         DEBUG4("rscsid: T %s.%s,%s,%s\n", bus, chan, tgt, lun);
617         if (scsi_ptr == NULL) {
618                 rscsirespond(-1, EBADF);
619                 return;
620         }
621         seterrno(0);
622         ret = usal_settarget(scsi_ptr, atoi(bus), atoi(tgt), atoi(lun));
623         if (!checktarget()) {
624                 usal_settarget(scsi_ptr, -1, -1, -1);
625                 ret = -1;
626         }
627         if (geterrno() != 0)
628                 rscsirespond(ret, geterrno());
629         else
630                 rscsireply(ret);
631 }
632
633 static void
634 initiator_id()
635 {
636         int     ret;
637         char    dummy[CMD_SIZE];
638
639         readarg(dummy, sizeof(dummy));
640         DEBUG1("rscsid: I %s\n", dummy);
641         if (scsi_ptr == NULL) {
642                 rscsirespond(-1, EBADF);
643                 return;
644         }
645         seterrno(0);
646         ret = usal_initiator_id(scsi_ptr);
647         if (geterrno() != 0)
648                 rscsirespond(ret, geterrno());
649         else
650                 rscsireply(ret);
651 }
652
653 static void
654 isatapi()
655 {
656         int     ret;
657         char    dummy[CMD_SIZE];
658
659         readarg(dummy, sizeof(dummy));
660         DEBUG1("rscsid: A %s\n", dummy);
661         if (scsi_ptr == NULL) {
662                 rscsirespond(-1, EBADF);
663                 return;
664         }
665         seterrno(0);
666         ret = usal_isatapi(scsi_ptr);
667         if (geterrno() != 0)
668                 rscsirespond(ret, geterrno());
669         else
670                 rscsireply(ret);
671 }
672
673 static void
674 scsireset()
675 {
676         int     ret;
677         char    what[CMD_SIZE];
678
679         readarg(what, sizeof(what));
680         DEBUG1("rscsid: R %s\n", what);
681         if (scsi_ptr == NULL) {
682                 rscsirespond(-1, EBADF);
683                 return;
684         }
685         ret = usal_reset(scsi_ptr, atoi(what));
686         rscsirespond(ret, geterrno());
687 }
688
689 static void
690 sendcmd()
691 {
692         register struct usal_cmd        *scmd;
693         int     n;
694         int     ret;
695         char    count[CMD_SIZE];
696         char    flags[CMD_SIZE];
697         char    cdb_len[CMD_SIZE];
698         char    sense_len[CMD_SIZE];
699         char    timeout[CMD_SIZE];
700         int     csize;
701         int     cflags;
702         int     clen;
703         int     ctimeout;
704         char    rbuf[1600];
705         char    *p;
706
707         /*
708          *      S count\n
709          *      flags\n
710          *      cdb_len\n
711          *      sense_len\n
712          *      timeout\n
713          *      <data if available>
714          *
715          *      Timeout:
716          *      -       sss     (e.g. 10)
717          *      -       sss.uuu (e.g. 10.23)
718          */
719         readarg(count, sizeof(count));
720         readarg(flags, sizeof(flags));
721         readarg(cdb_len, sizeof(cdb_len));
722         readarg(sense_len, sizeof(sense_len));
723         readarg(timeout, sizeof(timeout));
724         DEBUG5("rscsid: S %s %s %s %s %s", count, flags, cdb_len, sense_len, timeout);
725         csize = atoi(count);
726         cflags = atoi(flags);
727         clen = atoi(cdb_len);
728
729         p = strchr(timeout, '.');
730         if (p)
731                 *p = '\0';
732         ctimeout = atoi(timeout);
733
734         if (scsi_ptr == NULL || clen > SCG_MAX_CMD || csize > Sbufsize) {
735                 DEBUG("\n");
736                 voidarg(clen);
737                 if ((cflags & SCG_RECV_DATA) == 0 && csize > 0)
738                         voidarg(csize);
739                 rscsirespond(-1, scsi_ptr==NULL ? EBADF : EINVAL);
740                 return;
741         }
742
743         scmd = scsi_ptr->scmd;
744         fillbytes((caddr_t)scmd, sizeof(*scmd), '\0');
745         scmd->addr = (caddr_t)Sbuf;
746         scmd->size = csize;
747         scmd->flags = cflags;
748         scmd->cdb_len = clen;
749         scmd->sense_len = atoi(sense_len);
750         scmd->timeout = ctimeout;
751         readbuf((char *)scmd->cdb.cmd_cdb, clen);
752         DEBUG6(" 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X\n",
753                 scmd->cdb.cmd_cdb[0],
754                 scmd->cdb.cmd_cdb[1],
755                 scmd->cdb.cmd_cdb[2],
756                 scmd->cdb.cmd_cdb[3],
757                 scmd->cdb.cmd_cdb[4],
758                 scmd->cdb.cmd_cdb[5]);
759
760         if ((cflags & SCG_RECV_DATA) == 0 && csize > 0)
761                 readbuf(Sbuf, scmd->size);
762
763         scsi_ptr->cmdname = "";
764
765         ret = usal_cmd(scsi_ptr);
766
767         n = 0;
768         if ((csize - scmd->resid) > 0)
769                 n = csize - scmd->resid;
770
771         /*
772          *      A count\n
773          *      error\n
774          *      errno\n
775          *      scb\n
776          *      sense_count\n
777          *      <data if available>
778          */
779         DEBUG5("rscsid:>A %d %d %d %d %d\n",
780                 n,
781                 scmd->error,
782                 scmd->ux_errno,
783                 *(Uchar *)&scmd->scb,
784                 scmd->sense_count);
785
786         ret = snprintf(rbuf, sizeof(rbuf), "A%d\n%d\n%d\n%d\n%d\n",
787                 n,
788                 scmd->error,
789                 scmd->ux_errno,
790                 *(Uchar *)&scmd->scb,
791                 scmd->sense_count);
792
793         if (scmd->sense_count > 0) {
794                 movebytes(scmd->u_sense.cmd_sense, &rbuf[ret], scmd->sense_count);
795                 ret += scmd->sense_count;
796         }
797         if ((cflags & SCG_RECV_DATA) == 0)
798                 n = 0;
799         if (n > 0 && ((ret + n) <= sizeof(rbuf))) {
800                 movebytes(Sbuf, &rbuf[ret], n);
801                 ret += n;
802                 n = 0;
803         }
804         (void) _nixwrite(STDOUT_FILENO, rbuf, ret);
805
806         if (n > 0)
807                 (void) _nixwrite(STDOUT_FILENO, Sbuf, n);
808 }
809
810 #define READB_SIZE      128
811 static  char            readb[READB_SIZE];
812 static  char            *readbptr;
813 static  int             readbcnt;
814
815 static int
816 fillrdbuf()
817 {
818         readbptr = readb;
819
820         return (readbcnt = _niread(STDIN_FILENO, readb, READB_SIZE));
821 }
822
823 static int
824 readchar(char *cp)
825 {
826         if (--readbcnt < 0) {
827                 if (fillrdbuf() <= 0)
828                         return (readbcnt);
829                 --readbcnt;
830         }
831         *cp = *readbptr++;
832         return (1);
833 }
834
835 static void
836 readbuf(register char *buf, register int n)
837 {
838         register int    i = 0;
839         register int    amt;
840
841         if (readbcnt > 0) {
842                 amt = readbcnt;
843                 if (amt > n)
844                         amt = n;
845                 movebytes(readbptr, buf, amt);
846                 readbptr += amt;
847                 readbcnt -= amt;
848                 i += amt;
849         }
850
851         for (; i < n; i += amt) {
852                 amt = _niread(STDIN_FILENO, &buf[i], n - i);
853                 if (amt <= 0) {
854                         DEBUG("rscsid: premature eof\n");
855                         rscsierror(0, "Premature eof", NULL);
856                         exit(EX_BAD);
857                 }
858         }
859 }
860
861 static void
862 voidarg(register int n)
863 {
864         register int    i;
865         register int    amt;
866                  char   buf[512];
867
868         for (i = 0; i < n; i += amt) {
869                 amt = sizeof(buf);
870                 if ((n - i) < amt)
871                         amt = n - i;
872                 readbuf(buf, amt);
873         }
874 }
875
876 static void
877 readarg(char *buf, int n)
878 {
879         int     i;
880
881         for (i = 0; i < n; i++) {
882                 if (readchar(&buf[i]) != 1)
883                         exit(0);
884                 if (buf[i] == '\n')
885                         break;
886         }
887         buf[i] = '\0';
888 }
889
890 static char *
891 preparebuffer(int size)
892 {
893         Sbufsize = size;
894         if ((Sbuf = usal_getbuf(scsi_ptr, Sbufsize)) == NULL) {
895                 Sbufsize = 0L;
896                 return (Sbuf);
897         }
898         size = Sbufsize + 1024; /* Add protocol overhead */
899
900 #ifdef  SO_SNDBUF
901         while (size > 512 &&
902                setsockopt(STDOUT_FILENO, SOL_SOCKET, SO_SNDBUF, (char *)&size, sizeof (size)) < 0)
903                 size -= 512;
904         DEBUG1("rscsid: sndsize: %d\n", size);
905 #endif
906 #ifdef  SO_RCVBUF
907         while (size > 512 &&
908                setsockopt(STDIN_FILENO, SOL_SOCKET, SO_RCVBUF, (char *)&size, sizeof (size)) < 0)
909                 size -= 512;
910         DEBUG1("rscsid: rcvsize: %d\n", size);
911 #endif
912         return (Sbuf);
913 }
914
915 static int
916 checkscsi(char *device)
917 {
918 #ifdef  CHECKTAPE
919         if (strncmp(device, "/dev/rst", 8) == 0 ||
920             strncmp(device, "/dev/nrst", 9) == 0 ||
921             strcmp(device, "/dev/zero") == 0 ||
922             strcmp(device, "/dev/null") == 0)
923                 return (1);
924         return (0);
925 #else
926         return (1);
927 #endif
928 }
929
930 static void
931 rscsirespond(int ret, int err)
932 {
933         if (ret < 0) {
934                 rscsierror(err, errmsgstr(err), NULL);
935         } else {
936                 rscsireply(ret);
937         }
938 }
939
940 static void
941 rscsireply(int ret)
942 {
943         char    rbuf[CMD_SIZE];
944
945         DEBUG1("rscsid:>A %d\n", ret);
946         (void) snprintf(rbuf, sizeof(rbuf), "A%d\n", ret);
947         (void) _nixwrite(STDOUT_FILENO, rbuf, strlen(rbuf));
948 }
949
950 static void
951 rscsierror(int err, char *str, char *xstr)
952 {
953         char    rbuf[1600];
954         int     xlen = 0;
955         int     n;
956
957         if (xstr != NULL)
958                 xlen = strlen(xstr) + 1;
959
960         DEBUG3("rscsid:>E %d (%s) [%s]\n", err, str, xstr?xstr:"");
961         n = snprintf(rbuf, sizeof(rbuf), "E%d\n%s\n%d\n", err, str, xlen);
962
963         if (xlen > 0 && ((xlen + n) <= sizeof(rbuf))) {
964                 movebytes(xstr, &rbuf[n], xlen);
965                 n += xlen;
966                 xlen = 0;
967         }
968         (void) _nixwrite(STDOUT_FILENO, rbuf, n);
969         if (xlen > 0)
970                 (void) _nixwrite(STDOUT_FILENO, xstr, xlen);
971 }
972 #endif  /* USE_REMOTE */