Imported Upstream version 1.1.11
[platform/upstream/cdrkit.git] / libusal / scsi-remote.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 #define USE_REMOTE
14 /* @(#)scsi-remote.c    1.18 06/01/12 Copyright 1990,2000-2003 J. Schilling */
15 /*
16  *      Remote SCSI user level command transport routines
17  *
18  *      Warning: you may change this source, but if you do that
19  *      you need to change the _usal_version and _usal_auth* string below.
20  *      You may not return "schily" for an SCG_AUTHOR request anymore.
21  *      Choose your name instead of "schily" and make clear that the version
22  *      string is related to a modified source.
23  *
24  *      Copyright (c) 1990,2000-2003 J. Schilling
25  */
26 /*
27  * This program is free software; you can redistribute it and/or modify
28  * it under the terms of the GNU General Public License version 2
29  * as published by the Free Software Foundation.
30  *
31  * This program is distributed in the hope that it will be useful,
32  * but WITHOUT ANY WARRANTY; without even the implied warranty of
33  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
34  * GNU General Public License for more details.
35  *
36  * You should have received a copy of the GNU General Public License along with
37  * this program; see the file COPYING.  If not, write to the Free Software
38  * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
39  */
40
41 #include <mconfig.h>
42
43 #if !defined(HAVE_FORK) || !defined(HAVE_SOCKETPAIR) || !defined(HAVE_DUP2)
44 #undef  USE_RCMD_RSH
45 #endif
46 /*
47  * We may work without getservbyname() if we restructure the code not to
48  * use the port number if we only use _rcmdrsh().
49  */
50 #if !defined(HAVE_GETSERVBYNAME)
51 #undef  USE_REMOTE                              /* Cannot get rcmd() port # */
52 #endif
53 #if (!defined(HAVE_NETDB_H) || !defined(HAVE_RCMD)) && !defined(USE_RCMD_RSH)
54 #undef  USE_REMOTE                              /* There is no rcmd() */
55 #endif
56
57 #ifdef  USE_REMOTE
58 #include <stdio.h>
59 #include <sys/types.h>
60 #include <fctldefs.h>
61 #ifdef  HAVE_SYS_SOCKET_H
62 #include <sys/socket.h>
63 #endif
64 #include <errno.h>
65 #include <signal.h>
66 #ifdef  HAVE_NETDB_H
67 #include <netdb.h>
68 #endif
69 #ifdef  HAVE_PWD_H
70 #include <pwd.h>
71 #endif
72 #include <standard.h>
73 #include <stdxlib.h>
74 #include <unixstd.h>
75 #include <strdefs.h>
76 #include <schily.h>
77
78 #include <usal/usalcmd.h>
79 #include <usal/scsitransp.h>
80
81 #if     defined(SIGDEFER) || defined(SVR4)
82 #define signal  sigset
83 #endif
84
85 /*
86  * On Cygwin, there are no privilleged ports.
87  * On UNIX, rcmd() uses privilleged port that only work for root.
88  */
89 #ifdef  IS_CYGWIN
90 #define privport_ok()   (1)
91 #else
92 #ifdef  HAVE_GETPPRIV
93 #define privport_ok()   ppriv_ok()
94 #else
95 #define privport_ok()   (geteuid() == 0)
96 #endif
97 #endif
98
99 #define CMD_SIZE        80
100
101 #define MAX_SCG         16      /* Max # of SCSI controllers */
102 #define MAX_TGT         16
103 #define MAX_LUN         8
104
105 /*extern        BOOL    debug;*/
106 LOCAL   BOOL    debug = 1;
107
108 LOCAL   char    _usal_trans_version[] = "remote-1.18";  /* The version for remote SCSI  */
109 LOCAL   char    _usal_auth_cdrkit[]     = "cdrkit-team";        /* The author for this module   */
110
111 LOCAL   int     usalo_rsend             __PR((SCSI *usalp));
112 LOCAL   char *  usalo_rversion          __PR((SCSI *usalp, int what));
113 LOCAL   int     usalo_rhelp             __PR((SCSI *usalp, FILE *f));
114 LOCAL   int     usalo_ropen             __PR((SCSI *usalp, char *device));
115 LOCAL   int     usalo_rclose            __PR((SCSI *usalp));
116 LOCAL   long    usalo_rmaxdma           __PR((SCSI *usalp, long amt));
117 LOCAL   void *  usalo_rgetbuf           __PR((SCSI *usalp, long amt));
118 LOCAL   void    usalo_rfreebuf          __PR((SCSI *usalp));
119 LOCAL   BOOL    usalo_rhavebus          __PR((SCSI *usalp, int busno));
120 LOCAL   int     usalo_rfileno           __PR((SCSI *usalp, int busno, int tgt, int tlun));
121 LOCAL   int     usalo_rinitiator_id     __PR((SCSI *usalp));
122 LOCAL   int     usalo_risatapi          __PR((SCSI *usalp));
123 LOCAL   int     usalo_rreset            __PR((SCSI *usalp, int what));
124
125 /*
126  * XXX We should rethink the fd parameter now that we introduced
127  * XXX the rscsirchar() function and most access of remfd is done
128  * XXX via usallocal(usalp)->remfd.
129  */
130 LOCAL   void    rscsiabrt               __PR((int sig));
131 LOCAL   int     rscsigetconn            __PR((SCSI *usalp, char *host));
132 LOCAL   char    *rscsiversion           __PR((SCSI *usalp, int fd, int what));
133 LOCAL   int     rscsiopen               __PR((SCSI *usalp, int fd, char *fname));
134 LOCAL   int     rscsiclose              __PR((SCSI *usalp, int fd));
135 LOCAL   int     rscsimaxdma             __PR((SCSI *usalp, int fd, long amt));
136 LOCAL   int     rscsigetbuf             __PR((SCSI *usalp, int fd, long amt));
137 LOCAL   int     rscsifreebuf            __PR((SCSI *usalp, int fd));
138 LOCAL   int     rscsihavebus            __PR((SCSI *usalp, int fd, int bus));
139 LOCAL   int     rscsifileno             __PR((SCSI *usalp, int fd, int busno, int tgt, int tlun));
140 LOCAL   int     rscsiinitiator_id       __PR((SCSI *usalp, int fd));
141 LOCAL   int     rscsiisatapi            __PR((SCSI *usalp, int fd));
142 LOCAL   int     rscsireset              __PR((SCSI *usalp, int fd, int what));
143 LOCAL   int     rscsiscmd               __PR((SCSI *usalp, int fd, struct usal_cmd *sp));
144 LOCAL   int     rscsifillrbuf           __PR((SCSI *usalp));
145 LOCAL   int     rscsirchar              __PR((SCSI *usalp, char *cp));
146 LOCAL   int     rscsireadbuf            __PR((SCSI *usalp, int fd, char *buf, int count));
147 LOCAL   void    rscsivoidarg            __PR((SCSI *usalp, int fd, int count));
148 LOCAL   int     rscsicmd                __PR((SCSI *usalp, int fd, char *name, char *cbuf));
149 LOCAL   void    rscsisendcmd            __PR((SCSI *usalp, int fd, char *name, char *cbuf));
150 LOCAL   int     rscsigetline            __PR((SCSI *usalp, int fd, char *line, int count));
151 LOCAL   int     rscsireadnum            __PR((SCSI *usalp, int fd));
152 LOCAL   int     rscsigetstatus          __PR((SCSI *usalp, int fd, char *name));
153 LOCAL   int     rscsiaborted            __PR((SCSI *usalp, int fd));
154 #ifdef  USE_RCMD_RSH
155 LOCAL   int     _rcmdrsh                __PR((char **ahost, int inport,
156                                                 const char *locuser,
157                                                 const char *remuser,
158                                                 const char *cmd,
159                                                 const char *rsh));
160 #ifdef  HAVE_GETPPRIV
161 LOCAL   BOOL    ppriv_ok                __PR((void));
162 #endif
163 #endif
164
165 /*--------------------------------------------------------------------------*/
166
167 #define READBUF_SIZE    128
168
169 struct usal_local {
170         int     remfd;
171         char    readbuf[READBUF_SIZE];
172         char    *readbptr;
173         int     readbcnt;
174         BOOL    isopen;
175         int     rsize;
176         int     wsize;
177         char    *v_version;
178         char    *v_author;
179         char    *v_sccs_id;
180 };
181
182
183 #define usallocal(p)    ((struct usal_local *)((p)->local))
184
185 usal_ops_t remote_ops = {
186         usalo_rsend,            /* "S" end      */
187         usalo_rversion,         /* "V" ersion   */
188         usalo_rhelp,            /*     help     */
189         usalo_ropen,            /* "O" pen      */
190         usalo_rclose,           /* "C" lose     */
191         usalo_rmaxdma,          /* "D" MA       */
192         usalo_rgetbuf,          /* "M" alloc    */
193         usalo_rfreebuf,         /* "F" free     */
194         usalo_rhavebus,         /* "B" us       */
195         usalo_rfileno,          /* "T" arget    */
196         usalo_rinitiator_id,    /* "I" nitiator */
197         usalo_risatapi,         /* "A" tapi     */
198         usalo_rreset,           /* "R" eset     */
199 };
200
201 /*
202  * Return our ops ptr.
203  */
204 usal_ops_t *
205 usal_remote()
206 {
207         return (&remote_ops);
208 }
209
210 /*
211  * Return version information for the low level SCSI transport code.
212  * This has been introduced to make it easier to trace down problems
213  * in applications.
214  */
215 LOCAL char *
216 usalo_rversion(usalp, what)
217         SCSI    *usalp;
218         int     what;
219 {
220         int     f;
221
222         if (usalp->local == NULL)
223                 return ((char *)0);
224
225         f = usallocal(usalp)->remfd;
226         if (usalp != (SCSI *)0) {
227                 switch (what) {
228
229                 case SCG_VERSION:
230                         return (_usal_trans_version);
231                 /*
232                  * If you changed this source, you are not allowed to
233                  * return "schily" for the SCG_AUTHOR request.
234                  */
235                 case SCG_AUTHOR:
236                         return (_usal_auth_cdrkit);
237                 case SCG_SCCS_ID:
238                         return (__sccsid);
239
240                 case SCG_RVERSION:
241                         if (usallocal(usalp)->v_version == NULL)
242                                 usallocal(usalp)->v_version = rscsiversion(usalp, f, SCG_VERSION);
243                         return (usallocal(usalp)->v_version);
244                 /*
245                  * If you changed this source, you are not allowed to
246                  * return "schily" for the SCG_AUTHOR request.
247                  */
248                 case SCG_RAUTHOR:
249                         if (usallocal(usalp)->v_author == NULL)
250                                 usallocal(usalp)->v_author = rscsiversion(usalp, f, SCG_AUTHOR);
251                         return (usallocal(usalp)->v_author);
252                 case SCG_RSCCS_ID:
253                         if (usallocal(usalp)->v_sccs_id == NULL)
254                                 usallocal(usalp)->v_sccs_id = rscsiversion(usalp, f, SCG_SCCS_ID);
255                         return (usallocal(usalp)->v_sccs_id);
256                 }
257         }
258         return ((char *)0);
259 }
260
261 LOCAL int
262 usalo_rhelp(usalp, f)
263         SCSI    *usalp;
264         FILE    *f;
265 {
266         __usal_help(f, "RSCSI", "Remote SCSI",
267                 "REMOTE:", "rscsi@host:bus,target,lun", "REMOTE:rscsi@host:1,2,0", TRUE, FALSE);
268         return (0);
269 }
270
271 LOCAL int
272 usalo_ropen(usalp, device)
273         SCSI    *usalp;
274         char    *device;
275 {
276                 int     busno   = usal_scsibus(usalp);
277                 int     tgt     = usal_target(usalp);
278                 int     tlun    = usal_lun(usalp);
279         register int    f;
280         register int    nopen = 0;
281         char            devname[128];
282         char            *p;
283
284         if (usalp->overbose)
285                 fprintf(stderr, "Warning: Using remote SCSI interface.\n");
286
287         if (busno >= MAX_SCG || tgt >= MAX_TGT || tlun >= MAX_LUN) {
288                 errno = EINVAL;
289                 if (usalp->errstr)
290                         snprintf(usalp->errstr, SCSI_ERRSTR_SIZE,
291                         "Illegal value for busno, target or lun '%d,%d,%d'",
292                         busno, tgt, tlun);
293
294                 return (-1);
295         }
296         if (usalp->local == NULL) {
297                 usalp->local = malloc(sizeof (struct usal_local));
298                 if (usalp->local == NULL)
299                         return (0);
300                 usallocal(usalp)->remfd = -1;
301                 usallocal(usalp)->readbptr = usallocal(usalp)->readbuf;
302                 usallocal(usalp)->readbcnt = 0;
303                 usallocal(usalp)->isopen = FALSE;
304                 usallocal(usalp)->rsize = 0;
305                 usallocal(usalp)->wsize = 0;
306                 usallocal(usalp)->v_version = NULL;
307                 usallocal(usalp)->v_author  = NULL;
308                 usallocal(usalp)->v_sccs_id = NULL;
309         }
310
311         if (device == NULL || (strncmp(device, "REMOTE", 6) != 0) ||
312                                 (device = strchr(device, ':')) == NULL) {
313                 if (usalp->errstr)
314                         snprintf(usalp->errstr, SCSI_ERRSTR_SIZE,
315                                 "Illegal remote device syntax");
316                 return (-1);
317         }
318         device++;
319         /*
320          * Save non user@host:device
321          */
322         snprintf(devname, sizeof (devname), "%s", device);
323
324         if ((p = strchr(devname, ':')) != NULL)
325                 *p++ = '\0';
326
327         f = rscsigetconn(usalp, devname);
328         if (f < 0) {
329                 if (usalp->errstr)
330                         snprintf(usalp->errstr, SCSI_ERRSTR_SIZE,
331                                 "Cannot get connection to remote host");
332                 return (-1);
333         }
334         usallocal(usalp)->remfd = f;
335         debug = usalp->debug;
336         if (rscsiopen(usalp, f, p) >= 0) {
337                 nopen++;
338                 usallocal(usalp)->isopen = TRUE;
339         }
340         return (nopen);
341 }
342
343 LOCAL int
344 usalo_rclose(usalp)
345         SCSI    *usalp;
346 {
347         register int    f;
348                 int     ret;
349
350         if (usalp->local == NULL)
351                 return (-1);
352
353         if (usallocal(usalp)->v_version != NULL) {
354                 free(usallocal(usalp)->v_version);
355                 usallocal(usalp)->v_version = NULL;
356         }
357         if (usallocal(usalp)->v_author != NULL) {
358                 free(usallocal(usalp)->v_author);
359                 usallocal(usalp)->v_author  = NULL;
360         }
361         if (usallocal(usalp)->v_sccs_id != NULL) {
362                 free(usallocal(usalp)->v_sccs_id);
363                 usallocal(usalp)->v_sccs_id = NULL;
364         }
365
366         f = usallocal(usalp)->remfd;
367         if (f < 0 || !usallocal(usalp)->isopen)
368                 return (0);
369         ret = rscsiclose(usalp, f);
370         usallocal(usalp)->isopen = FALSE;
371         close(f);
372         usallocal(usalp)->remfd = -1;
373         return (ret);
374 }
375
376 LOCAL long
377 usalo_rmaxdma(usalp, amt)
378         SCSI    *usalp;
379         long    amt;
380 {
381         if (usalp->local == NULL)
382                 return (-1L);
383
384         return (rscsimaxdma(usalp, usallocal(usalp)->remfd, amt));
385 }
386
387 LOCAL void *
388 usalo_rgetbuf(usalp, amt)
389         SCSI    *usalp;
390         long    amt;
391 {
392         int     ret;
393
394         if (usalp->local == NULL)
395                 return ((void *)0);
396
397         ret = rscsigetbuf(usalp, usallocal(usalp)->remfd, amt);
398         if (ret < 0)
399                 return ((void *)0);
400
401 #ifdef  HAVE_VALLOC
402         usalp->bufbase = (void *)valloc((size_t)amt);
403 #else
404         usalp->bufbase = (void *)malloc((size_t)amt);
405 #endif
406         if (usalp->bufbase == NULL) {
407                 usalo_rfreebuf(usalp);
408                 return ((void *)0);
409         }
410         return (usalp->bufbase);
411 }
412
413 LOCAL void
414 usalo_rfreebuf(usalp)
415         SCSI    *usalp;
416 {
417         int     f;
418
419         if (usalp->bufbase)
420                 free(usalp->bufbase);
421         usalp->bufbase = NULL;
422
423         if (usalp->local == NULL)
424                 return;
425
426         f = usallocal(usalp)->remfd;
427         if (f < 0 || !usallocal(usalp)->isopen)
428                 return;
429         rscsifreebuf(usalp, f);
430 }
431
432 LOCAL BOOL
433 usalo_rhavebus(usalp, busno)
434         SCSI    *usalp;
435         int     busno;
436 {
437         if (usalp->local == NULL || busno < 0 || busno >= MAX_SCG)
438                 return (FALSE);
439
440         return (rscsihavebus(usalp, usallocal(usalp)->remfd, busno));
441 }
442
443 LOCAL int
444 usalo_rfileno(usalp, busno, tgt, tlun)
445         SCSI    *usalp;
446         int     busno;
447         int     tgt;
448         int     tlun;
449 {
450         int     f;
451
452         if (usalp->local == NULL ||
453             busno < 0 || busno >= MAX_SCG ||
454             tgt < 0 || tgt >= MAX_TGT ||
455             tlun < 0 || tlun >= MAX_LUN)
456                 return (-1);
457
458         f = usallocal(usalp)->remfd;
459         if (f < 0 || !usallocal(usalp)->isopen)
460                 return (-1);
461         return (rscsifileno(usalp, f, busno, tgt, tlun));
462 }
463
464 LOCAL int
465 usalo_rinitiator_id(usalp)
466         SCSI    *usalp;
467 {
468         if (usalp->local == NULL)
469                 return (-1);
470
471         return (rscsiinitiator_id(usalp, usallocal(usalp)->remfd));
472 }
473
474 LOCAL int
475 usalo_risatapi(usalp)
476         SCSI    *usalp;
477 {
478         if (usalp->local == NULL)
479                 return (-1);
480
481         return (rscsiisatapi(usalp, usallocal(usalp)->remfd));
482 }
483
484 LOCAL int
485 usalo_rreset(usalp, what)
486         SCSI    *usalp;
487         int     what;
488 {
489         if (usalp->local == NULL)
490                 return (-1);
491
492         return (rscsireset(usalp, usallocal(usalp)->remfd, what));
493 }
494
495 LOCAL int
496 usalo_rsend(usalp)
497         SCSI            *usalp;
498 {
499         struct usal_cmd *sp = usalp->scmd;
500         int             ret;
501
502         if (usalp->local == NULL)
503                 return (-1);
504
505         if (usalp->fd < 0) {
506                 sp->error = SCG_FATAL;
507                 return (0);
508         }
509         ret = rscsiscmd(usalp, usallocal(usalp)->remfd, usalp->scmd);
510
511         return (ret);
512 }
513
514 /*--------------------------------------------------------------------------*/
515 LOCAL void
516 rscsiabrt(sig)
517         int     sig;
518 {
519         rscsiaborted((SCSI *)0, -1);
520 }
521
522 LOCAL int
523 rscsigetconn(usalp, host)
524         SCSI    *usalp;
525         char    *host;
526 {
527         static  struct servent  *sp = 0;
528         static  struct passwd   *pw = 0;
529                 char            *name = "root";
530                 char            *p;
531                 char            *rscsi;
532                 char            *rsh;
533                 int             rscsisock;
534                 char            *rscsipeer;
535                 char            rscsiuser[128];
536
537
538         signal(SIGPIPE, rscsiabrt);
539         if (sp == 0) {
540                 sp = getservbyname("shell", "tcp");
541                 if (sp == 0) {
542                         comerrno(EX_BAD, "shell/tcp: unknown service\n");
543                         /* NOTREACHED */
544                 }
545                 pw = getpwuid(getuid());
546                 if (pw == 0) {
547                         comerrno(EX_BAD, "who are you? No passwd entry found.\n");
548                         /* NOTREACHED */
549                 }
550         }
551         if ((p = strchr(host, '@')) != NULL) {
552                 size_t d = p - host;
553
554                 if (d > sizeof (rscsiuser))
555                         d = sizeof (rscsiuser);
556                 snprintf(rscsiuser, sizeof (rscsiuser), "%.*s", (int)d, host);
557                 name = rscsiuser;
558                 host = &p[1];
559         } else {
560                 name = pw->pw_name;
561         }
562         if (usalp->debug > 0)
563                 errmsgno(EX_BAD, "locuser: '%s' rscsiuser: '%s' host: '%s'\n",
564                                                 pw->pw_name, name, host);
565         rscsipeer = host;
566
567         if ((rscsi = getenv("RSCSI")) == NULL)
568                 rscsi = "/usr/sbin/netscsid";
569         rsh = getenv("RSH");
570
571 #ifdef  USE_RCMD_RSH
572         if (!privport_ok() || rsh != NULL)
573                 rscsisock = _rcmdrsh(&rscsipeer, (unsigned short)sp->s_port,
574                                         pw->pw_name, name, rscsi, rsh);
575         else
576 #endif
577 #ifdef  HAVE_RCMD
578                 rscsisock = rcmd(&rscsipeer, (unsigned short)sp->s_port,
579                                         pw->pw_name, name, rscsi, 0);
580 #else
581                 rscsisock = _rcmdrsh(&rscsipeer, (unsigned short)sp->s_port,
582                                         pw->pw_name, name, rscsi, rsh);
583 #endif
584
585         return (rscsisock);
586 }
587
588 LOCAL char *
589 rscsiversion(usalp, fd, what)
590         SCSI    *usalp;
591         int     fd;
592         int     what;
593 {
594         char    cbuf[CMD_SIZE];
595         char    *p;
596         int     ret;
597
598         snprintf(cbuf, sizeof (cbuf), "V%d\n", what);
599         ret = rscsicmd(usalp, fd, "version", cbuf);
600         p = malloc(ret);
601         if (p == NULL)
602                 return (p);
603         rscsireadbuf(usalp, fd, p, ret);
604         return (p);
605 }
606
607 LOCAL int
608 rscsiopen(usalp, fd, fname)
609         SCSI    *usalp;
610         int     fd;
611         char    *fname;
612 {
613         char    cbuf[CMD_SIZE];
614         int     ret;
615         int     bus;
616         int     chan;
617         int     tgt;
618         int     lun;
619
620         snprintf(cbuf, sizeof (cbuf), "O%s\n", fname?fname:"");
621         ret = rscsicmd(usalp, fd, "open", cbuf);
622         if (ret < 0)
623                 return (ret);
624
625         bus = rscsireadnum(usalp, fd);
626         chan = rscsireadnum(usalp, fd);
627         tgt = rscsireadnum(usalp, fd);
628         lun = rscsireadnum(usalp, fd);
629
630         usal_settarget(usalp, bus, tgt, lun);
631         return (ret);
632 }
633
634 LOCAL int
635 rscsiclose(usalp, fd)
636         SCSI    *usalp;
637         int     fd;
638 {
639         return (rscsicmd(usalp, fd, "close", "C\n"));
640 }
641
642 LOCAL int
643 rscsimaxdma(usalp, fd, amt)
644         SCSI    *usalp;
645         int     fd;
646         long    amt;
647 {
648         char    cbuf[CMD_SIZE];
649
650         snprintf(cbuf, sizeof (cbuf), "D%ld\n", amt);
651         return (rscsicmd(usalp, fd, "maxdma", cbuf));
652 }
653
654 LOCAL int
655 rscsigetbuf(usalp, fd, amt)
656         SCSI    *usalp;
657         int     fd;
658         long    amt;
659 {
660         char    cbuf[CMD_SIZE];
661         int     size;
662         int     ret;
663
664         snprintf(cbuf, sizeof (cbuf), "M%ld\n", amt);
665         ret = rscsicmd(usalp, fd, "getbuf", cbuf);
666         if (ret < 0)
667                 return (ret);
668
669         size = ret + 1024;      /* Add protocol overhead */
670
671 #ifdef  SO_SNDBUF
672         if (size > usallocal(usalp)->wsize) while (size > 512 &&
673                 setsockopt(fd, SOL_SOCKET, SO_SNDBUF,
674                                         (char *)&size, sizeof (size)) < 0) {
675                 size -= 512;
676         }
677         if (size > usallocal(usalp)->wsize) {
678                 usallocal(usalp)->wsize = size;
679                 if (usalp->debug > 0)
680                         errmsgno(EX_BAD, "sndsize: %d\n", size);
681         }
682 #endif
683 #ifdef  SO_RCVBUF
684         if (size > usallocal(usalp)->rsize) while (size > 512 &&
685                 setsockopt(fd, SOL_SOCKET, SO_RCVBUF,
686                                         (char *)&size, sizeof (size)) < 0) {
687                 size -= 512;
688         }
689         if (size > usallocal(usalp)->rsize) {
690                 usallocal(usalp)->rsize = size;
691                 if (usalp->debug > 0)
692                         errmsgno(EX_BAD, "rcvsize: %d\n", size);
693         }
694 #endif
695         return (ret);
696 }
697
698 LOCAL int
699 rscsifreebuf(usalp, fd)
700         SCSI    *usalp;
701         int     fd;
702 {
703         return (rscsicmd(usalp, fd, "freebuf", "F\n"));
704 }
705
706 LOCAL int
707 rscsihavebus(usalp, fd, busno)
708         SCSI    *usalp;
709         int     fd;
710         int     busno;
711 {
712         char    cbuf[2*CMD_SIZE];
713
714         snprintf(cbuf, sizeof (cbuf), "B%d\n%d\n",
715                 busno,
716                 0);
717         return (rscsicmd(usalp, fd, "havebus", cbuf));
718 }
719
720 LOCAL int
721 rscsifileno(usalp, fd, busno, tgt, tlun)
722         SCSI    *usalp;
723         int     fd;
724         int     busno;
725         int     tgt;
726         int     tlun;
727 {
728         char    cbuf[3*CMD_SIZE];
729
730         snprintf(cbuf, sizeof (cbuf), "T%d\n%d\n%d\n%d\n",
731                 busno,
732                 0,
733                 tgt,
734                 tlun);
735         return (rscsicmd(usalp, fd, "fileno", cbuf));
736 }
737
738 LOCAL int
739 rscsiinitiator_id(usalp, fd)
740         SCSI    *usalp;
741         int     fd;
742 {
743         return (rscsicmd(usalp, fd, "initiator id", "I\n"));
744 }
745
746 LOCAL int
747 rscsiisatapi(usalp, fd)
748         SCSI    *usalp;
749         int     fd;
750 {
751         return (rscsicmd(usalp, fd, "isatapi", "A\n"));
752 }
753
754 LOCAL int
755 rscsireset(usalp, fd, what)
756         SCSI    *usalp;
757         int     fd;
758         int     what;
759 {
760         char    cbuf[CMD_SIZE];
761
762         snprintf(cbuf, sizeof (cbuf), "R%d\n", what);
763         return (rscsicmd(usalp, fd, "reset", cbuf));
764 }
765
766 LOCAL int
767 rscsiscmd(usalp, fd, sp)
768         SCSI    *usalp;
769         int     fd;
770         struct usal_cmd  *sp;
771 {
772         char    cbuf[1600];
773         int     ret;
774         int     amt = 0;
775         int     voidsize = 0;
776
777         ret = snprintf(cbuf, sizeof (cbuf), "S%d\n%d\n%d\n%d\n%d\n",
778                 sp->size, sp->flags,
779                 sp->cdb_len, sp->sense_len,
780                 sp->timeout);
781         movebytes(sp->cdb.cmd_cdb, &cbuf[ret], sp->cdb_len);
782         ret += sp->cdb_len;
783
784         if ((sp->flags & SCG_RECV_DATA) == 0 && sp->size > 0) {
785                 amt = sp->size;
786                 if ((ret + amt) <= sizeof (cbuf)) {
787                         movebytes(sp->addr, &cbuf[ret], amt);
788                         ret += amt;
789                         amt = 0;
790                 }
791         }
792         errno = 0;
793         if (_nixwrite(fd, cbuf, ret) != ret)
794                 rscsiaborted(usalp, fd);
795
796         if (amt > 0) {
797                 if (_nixwrite(fd, sp->addr, amt) != amt)
798                         rscsiaborted(usalp, fd);
799         }
800
801         ret = rscsigetstatus(usalp, fd, "sendcmd");
802         if (ret < 0)
803                 return (ret);
804
805         sp->resid = sp->size - ret;
806         sp->error = rscsireadnum(usalp, fd);
807         sp->ux_errno = rscsireadnum(usalp, fd);
808         *(Uchar *)&sp->scb = rscsireadnum(usalp, fd);
809         sp->sense_count = rscsireadnum(usalp, fd);
810
811         if (sp->sense_count > SCG_MAX_SENSE) {
812                 voidsize = sp->sense_count - SCG_MAX_SENSE;
813                 sp->sense_count = SCG_MAX_SENSE;
814         }
815         if (sp->sense_count > 0) {
816                 rscsireadbuf(usalp, fd, (char *)sp->u_sense.cmd_sense, sp->sense_count);
817                 rscsivoidarg(usalp, fd, voidsize);
818         }
819
820         if ((sp->flags & SCG_RECV_DATA) != 0 && ret > 0)
821                 rscsireadbuf(usalp, fd, sp->addr, ret);
822
823         return (0);
824 }
825
826 LOCAL int
827 rscsifillrbuf(usalp)
828         SCSI    *usalp;
829 {
830         usallocal(usalp)->readbptr = usallocal(usalp)->readbuf;
831
832         return (usallocal(usalp)->readbcnt =
833                         _niread(usallocal(usalp)->remfd,
834                             usallocal(usalp)->readbuf, READBUF_SIZE));
835 }
836
837 LOCAL int
838 rscsirchar(usalp, cp)
839         SCSI    *usalp;
840         char    *cp;
841 {
842         if (--(usallocal(usalp)->readbcnt) < 0) {
843                 if (rscsifillrbuf(usalp) <= 0)
844                         return (usallocal(usalp)->readbcnt);
845                 --(usallocal(usalp)->readbcnt);
846         }
847         *cp = *(usallocal(usalp)->readbptr)++;
848         return (1);
849 }
850
851 LOCAL int
852 rscsireadbuf(usalp, fd, buf, count)
853         SCSI    *usalp;
854         int     fd;
855         char    *buf;
856         int     count;
857 {
858         register int    n = count;
859         register int    amt = 0;
860         register int    cnt;
861
862         if (usallocal(usalp)->readbcnt > 0) {
863                 cnt = usallocal(usalp)->readbcnt;
864                 if (cnt > n)
865                         cnt = n;
866                 movebytes(usallocal(usalp)->readbptr, buf, cnt);
867                 usallocal(usalp)->readbptr += cnt;
868                 usallocal(usalp)->readbcnt -= cnt;
869                 amt += cnt;
870         }
871         while (amt < n) {
872                 if ((cnt = _niread(fd, &buf[amt], n - amt)) <= 0) {
873                         return (rscsiaborted(usalp, fd));
874                 }
875                 amt += cnt;
876         }
877         return (amt);
878 }
879
880 LOCAL void
881 rscsivoidarg(usalp, fd, n)
882         SCSI    *usalp;
883         int     fd;
884         register int    n;
885 {
886         register int    i;
887         register int    amt;
888                 char    buf[512];
889
890         for (i = 0; i < n; i += amt) {
891                 amt = sizeof (buf);
892                 if ((n - i) < amt)
893                         amt = n - i;
894                 rscsireadbuf(usalp, fd, buf, amt);
895         }
896 }
897
898 LOCAL int
899 rscsicmd(usalp, fd, name, cbuf)
900         SCSI    *usalp;
901         int     fd;
902         char    *name;
903         char    *cbuf;
904 {
905         rscsisendcmd(usalp, fd, name, cbuf);
906         return (rscsigetstatus(usalp, fd, name));
907 }
908
909 LOCAL void
910 rscsisendcmd(usalp, fd, name, cbuf)
911         SCSI    *usalp;
912         int     fd;
913         char    *name;
914         char    *cbuf;
915 {
916         int     buflen = strlen(cbuf);
917
918         errno = 0;
919         if (_nixwrite(fd, cbuf, buflen) != buflen)
920                 rscsiaborted(usalp, fd);
921 }
922
923 LOCAL int
924 rscsigetline(usalp, fd, line, count)
925         SCSI    *usalp;
926         int     fd;
927         char    *line;
928         int     count;
929 {
930         register char   *cp;
931
932         for (cp = line; cp < &line[count]; cp++) {
933                 if (rscsirchar(usalp, cp) != 1)
934                         return (rscsiaborted(usalp, fd));
935
936                 if (*cp == '\n') {
937                         *cp = '\0';
938                         return (cp - line);
939                 }
940         }
941         return (rscsiaborted(usalp, fd));
942 }
943
944 LOCAL int
945 rscsireadnum(usalp, fd)
946         SCSI    *usalp;
947         int     fd;
948 {
949         char    cbuf[CMD_SIZE];
950
951         rscsigetline(usalp, fd, cbuf, sizeof (cbuf));
952         return (atoi(cbuf));
953 }
954
955 LOCAL int
956 rscsigetstatus(usalp, fd, name)
957         SCSI    *usalp;
958         int     fd;
959         char    *name;
960 {
961         char    cbuf[CMD_SIZE];
962         char    code;
963         int     number;
964         int     count;
965         int     voidsize = 0;
966
967         rscsigetline(usalp, fd, cbuf, sizeof (cbuf));
968         code = cbuf[0];
969         number = atoi(&cbuf[1]);
970
971         if (code == 'E' || code == 'F') {
972                 rscsigetline(usalp, fd, cbuf, sizeof (cbuf));
973                 if (code == 'F')        /* should close file ??? */
974                         rscsiaborted(usalp, fd);
975
976                 rscsigetline(usalp, fd, cbuf, sizeof (cbuf));
977                 count = atoi(cbuf);
978                 if (count > 0) {
979                         if (usalp->errstr == NULL) {
980                                 voidsize = count;
981                                 count = 0;
982                         } else if (count > SCSI_ERRSTR_SIZE) {
983                                 voidsize = count - SCSI_ERRSTR_SIZE;
984                                 count = SCSI_ERRSTR_SIZE;
985                         }
986                         rscsireadbuf(usalp, fd, usalp->errstr, count);
987                         rscsivoidarg(usalp, fd, voidsize);
988                 }
989                 if (usalp->debug > 0)
990                         errmsgno(number, "Remote status(%s): %d '%s'.\n",
991                                                         name, number, cbuf);
992                 errno = number;
993                 return (-1);
994         }
995         if (code != 'A') {
996                 /* XXX Hier kommt evt Command not found ... */
997                 if (usalp->debug > 0)
998                         errmsgno(EX_BAD, "Protocol error (got %s).\n", cbuf);
999                 return (rscsiaborted(usalp, fd));
1000         }
1001         return (number);
1002 }
1003
1004 LOCAL int
1005 rscsiaborted(usalp, fd)
1006         SCSI    *usalp;
1007         int     fd;
1008 {
1009         if ((usalp && usalp->debug > 0) || debug)
1010                 errmsgno(EX_BAD, "Lost connection to remote host ??\n");
1011         /* if fd >= 0 */
1012         /* close file */
1013         if (errno == 0)
1014                 errno = EIO;
1015         return (-1);
1016 }
1017
1018 /*--------------------------------------------------------------------------*/
1019 #ifdef  USE_RCMD_RSH
1020 /*
1021  * If we make a separate file for libschily, we would need these include files:
1022  *
1023  * socketpair():        sys/types.h + sys/socket.h
1024  * dup2():              unixstd.h (hat auch sys/types.h)
1025  * strrchr():           strdefs.h
1026  *
1027  * and make sure that we use sigset() instead of signal() if possible.
1028  */
1029 #include <waitdefs.h>
1030 LOCAL int
1031 _rcmdrsh(ahost, inport, locuser, remuser, cmd, rsh)
1032         char            **ahost;
1033         int             inport;         /* port is ignored */
1034         const char      *locuser;
1035         const char      *remuser;
1036         const char      *cmd;
1037         const char      *rsh;
1038 {
1039         struct passwd   *pw;
1040         int     pp[2];
1041         int     pid;
1042
1043         if (rsh == 0)
1044                 rsh = "rsh";
1045
1046         /*
1047          * Verify that 'locuser' is present on local host.
1048          */
1049         if ((pw = getpwnam(locuser)) == NULL) {
1050                 errmsgno(EX_BAD, "Unknown user: %s\n", locuser);
1051                 return (-1);
1052         }
1053         /* XXX Check the existence for 'ahost' here? */
1054
1055         /*
1056          * rcmd(3) creates a single socket to be used for communication.
1057          * We need a bi-directional pipe to implement the same interface.
1058          * On newer OS that implement bi-directional we could use pipe(2)
1059          * but it makes no sense unless we find an OS that implements a
1060          * bi-directional pipe(2) but no socketpair().
1061          */
1062         if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pp) == -1) {
1063                 errmsg("Cannot create socketpair.\n");
1064                 return (-1);
1065         }
1066
1067         pid = fork();
1068         if (pid < 0) {
1069                 return (-1);
1070         } else if (pid == 0) {
1071                 const char      *p;
1072                 const char      *av0;
1073                 int             xpid;
1074
1075                 (void) close(pp[0]);
1076                 if (dup2(pp[1], 0) == -1 ||     /* Pipe becomes 'stdin'  */
1077                     dup2(0, 1) == -1) {         /* Pipe becomes 'stdout' */
1078
1079                         errmsg("dup2 failed.\n");
1080                         _exit(EX_BAD);
1081                         /* NOTREACHED */
1082                 }
1083                 (void) close(pp[1]);            /* We don't need this anymore*/
1084
1085                 /*
1086                  * Become 'locuser' to tell the rsh program the local user id.
1087                  */
1088                 if (getuid() != pw->pw_uid &&
1089                     setuid(pw->pw_uid) == -1) {
1090                         errmsg("setuid(%lld) failed.\n",
1091                                                         (Llong)pw->pw_uid);
1092                         _exit(EX_BAD);
1093                         /* NOTREACHED */
1094                 }
1095                 if (getuid() != geteuid() &&
1096 #ifdef  HAVE_SETREUID
1097                     setreuid(-1, pw->pw_uid) == -1) {
1098 #else
1099 #ifdef  HAVE_SETEUID
1100                     seteuid(pw->pw_uid) == -1) {
1101 #else
1102                     setuid(pw->pw_uid) == -1) {
1103 #endif
1104 #endif
1105                         errmsg("seteuid(%lld) failed.\n",
1106                                                         (Llong)pw->pw_uid);
1107                         _exit(EX_BAD);
1108                         /* NOTREACHED */
1109                 }
1110                 if (getuid() != geteuid() &&
1111                     seteuid(pw->pw_uid) == -1) {
1112                         errmsg("seteuid(%lld) failed.\n",
1113                                                         (Llong)pw->pw_uid);
1114                         _exit(EX_BAD);
1115                         /* NOTREACHED */
1116                 }
1117
1118                 /*
1119                  * Fork again to completely detach from parent
1120                  * and avoid the need to wait(2).
1121                  */
1122                 if ((xpid = fork()) == -1) {
1123                         errmsg("rcmdsh: fork to lose parent failed.\n");
1124                         _exit(EX_BAD);
1125                         /* NOTREACHED */
1126                 }
1127                 if (xpid > 0) {
1128                         _exit(0);
1129                         /* NOTREACHED */
1130                 }
1131
1132                 /*
1133                  * Always use remote shell programm (even for localhost).
1134                  * The client command may call getpeername() for security
1135                  * reasons and this would fail on a simple pipe.
1136                  */
1137
1138
1139                 /*
1140                  * By default, 'rsh' handles terminal created signals
1141                  * but this is not what we like.
1142                  * For this reason, we tell 'rsh' to ignore these signals.
1143                  * Ignoring these signals is important to allow 'star' / 'sdd'
1144                  * to e.g. implement SIGQUIT as signal to trigger intermediate
1145                  * status printing.
1146                  *
1147                  * For now (late 2002), we know that the following programs
1148                  * are broken and do not implement signal handling correctly:
1149                  *
1150                  *      rsh     on SunOS-5.0...SunOS-5.9
1151                  *      ssh     from ssh.com
1152                  *      ssh     from openssh.org
1153                  *
1154                  * Sun already did accept a bug report for 'rsh'. For the ssh
1155                  * commands we need to send out bug reports. Meanwhile it could
1156                  * help to call setsid() if we are running under X so the ssh
1157                  * X pop up for passwd reading will work.
1158                  */
1159                 signal(SIGINT, SIG_IGN);
1160                 signal(SIGQUIT, SIG_IGN);
1161 #ifdef  SIGTSTP
1162                 signal(SIGTSTP, SIG_IGN); /* We would not be able to continue*/
1163 #endif
1164
1165                 av0 = rsh;
1166                 if ((p = strrchr(rsh, '/')) != NULL)
1167                         av0 = ++p;
1168                 execlp(rsh, av0, *ahost, "-l", remuser, cmd, (char *)NULL);
1169
1170                 errmsg("execlp '%s' failed.\n", rsh);
1171                 _exit(EX_BAD);
1172                 /* NOTREACHED */
1173         } else {
1174                 (void) close(pp[1]);
1175                 /*
1176                  * Wait for the intermediate child.
1177                  * The real 'rsh' program is completely detached from us.
1178                  */
1179                 wait(0);
1180                 return (pp[0]);
1181         }
1182         return (-1);    /* keep gcc happy */
1183 }
1184
1185 #ifdef  HAVE_GETPPRIV
1186 #include <priv.h>
1187
1188 LOCAL BOOL
1189 ppriv_ok()
1190 {
1191         priv_set_t      *privset;
1192         BOOL            net_privaddr = FALSE;
1193
1194
1195         if ((privset = priv_allocset()) == NULL) {
1196                 return (FALSE);
1197         }
1198         if (getppriv(PRIV_EFFECTIVE, privset) == -1) {
1199                 priv_freeset(privset);
1200                 return (FALSE);
1201         }
1202         if (priv_ismember(privset, PRIV_NET_PRIVADDR)) {
1203                 net_privaddr = TRUE;
1204         }
1205         priv_freeset(privset);
1206
1207         return (net_privaddr);
1208 }
1209 #endif  /* HAVE_GETPPRIV */
1210
1211 #endif  /* USE_RCMD_RSH */
1212
1213 #endif  /* USE_REMOTE */