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