home *** CD-ROM | disk | FTP | other *** search
/ rtsi.com / 2014.01.www.rtsi.com.tar / www.rtsi.com / OS9 / OSK / TELECOM / OS9_Unix.lzh / RSHSRC / rsh.c < prev    next >
C/C++ Source or Header  |  1992-10-06  |  11KB  |  464 lines

  1. /*
  2.     RSH.C    OS9/68K Version
  3.         Ivan Powis <pczip@chem.nott.ac.uk> 1-Sep-92
  4.  -
  5.  * Copyright (c) 1983, 1990 The Regents of the University of California.
  6.  * All rights reserved.
  7.  *
  8.  * Redistribution and use in source and binary forms, with or without
  9.  * modification, are permitted provided that the following conditions
  10.  * are met:
  11.  * 1. Redistributions of source code must retain the above copyright
  12.  *    notice, this list of conditions and the following disclaimer.
  13.  * 2. Redistributions in binary form must reproduce the above copyright
  14.  *    notice, this list of conditions and the following disclaimer in the
  15.  *    documentation and/or other materials provided with the distribution.
  16.  * 3. All advertising materials mentioning features or use of this software
  17.  *    must display the following acknowledgement:
  18.  *    This product includes software developed by the University of
  19.  *    California, Berkeley and its contributors.
  20.  * 4. Neither the name of the University nor the names of its contributors
  21.  *    may be used to endorse or promote products derived from this software
  22.  *    without specific prior written permission.
  23.  *
  24.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  25.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  26.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  27.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  28.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  29.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  30.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  31.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  32.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  33.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  34.  * SUCH DAMAGE.
  35.  */
  36.  
  37. #ifndef lint
  38. char copyright[] =
  39. "@(#) Copyright (c) 1983, 1990 The Regents of the University of California.\n\
  40.  Additional material for OS9 Copyright (c) 1992 Ivan Powis\n\
  41.  All rights reserved.\n";
  42. #endif /* not lint */
  43.  
  44. #ifndef lint
  45. static char sccsid[] = "@(#)rsh.c    5.24 (Berkeley) 7/1/91";
  46. #endif /* not lint */
  47.  
  48. /*
  49.  * $Source: mit/rsh/RCS/rsh.c,v $
  50.  * $Header: mit/rsh/RCS/rsh.c,v 5.1 89/07/31 19:28:59 kfall Exp Locker: kfall $
  51.  */
  52.  
  53. #include <types.h>
  54. #include <signal.h>
  55. #include <inet/socket.h>
  56. #include <inet/in.h>
  57. #include <inet/netdb.h>
  58.  
  59. /* The following are not std OS9 - I use blarslib headers + library */
  60. #include <pwd.h>
  61.  
  62. #include <stdio.h>
  63. #include <errno.h>
  64. #include <strings.h>
  65.  
  66. #define _PATH_RLOGIN "rlogin"
  67. #define perror(A)       prerr(0,_errmsg(errno,(A)))
  68.  
  69.  
  70. /*
  71.  * rsh - remote shell
  72.  */
  73. extern int errno;
  74. int rfd2;
  75.  
  76. main(argc, argv, envp)
  77.     int argc;
  78.     char **argv, **envp;
  79. {
  80.     extern char *optarg;
  81.     extern int optind;
  82.     struct passwd *pw;
  83.     struct servent *sp;
  84.     int argoff, asrsh, ch, dflag, nflag, one, pid, rem, uid;
  85.     register char *p;
  86.     char *args, *host, *user, *copyargs();
  87.     void pass_sig();
  88.  
  89.     if (*argv[0]==0) {
  90.     /*
  91.     *    We're an OS9 daughter process
  92.     *    Keyboard signals may come to either this process or the parent under
  93.     *    OS9 - it just depends which last did i/o to the terminal. Consequently
  94.     *    we arrange to catch them in either case.
  95.     */
  96.         rfd2=3;        /* Parent must pass error channel skt */
  97.         intercept(pass_sig);
  98.         rshb();     /* We never return from rshb() */
  99.     }
  100.  
  101. /*
  102.     We're the main process.
  103. */
  104.     argoff = asrsh = dflag = nflag = 0;
  105.     one = 1;
  106.     host = user = NULL;
  107.  
  108.     dup(2);        /* reserve path number 3 for later use */
  109.     
  110.     /* if called as something other than "rsh", use it as the host name */
  111.     if (p = rindex(argv[0], '/'))
  112.         ++p;
  113.     else
  114.         p = argv[0];
  115.     if (strcmp(p, "rsh"))
  116.         host = p;
  117.     else
  118.         asrsh = 1;
  119.  
  120.     /* handle "rsh host flags" */
  121.     if (!host && argc > 2 && argv[1][0] != '-') {
  122.         host = argv[1];
  123.         argoff = 1;
  124.     }
  125.  
  126. #define    OPTIONS    "8KLdel:nw"
  127.     while ((ch = getopt(argc - argoff, argv + argoff, OPTIONS)) != EOF)
  128.         switch(ch) {
  129.         case 'K':
  130.             break;
  131.         case 'L':    /* -8Lew are ignored to allow rlogin aliases */
  132.         case 'e':
  133.         case 'w':
  134.         case '8':
  135.             break;
  136.         case 'd':
  137.             dflag = 1;
  138.             break;
  139.         case 'l':
  140.             user = optarg;
  141.             break;
  142.         case 'n':
  143.             nflag = 1;
  144.             break;
  145.         case '?':
  146.         default:
  147.             usage();
  148.         }
  149.     optind += argoff;
  150.  
  151.     /* if haven't gotten a host yet, do so */
  152.     if (!host && !(host = argv[optind++]))
  153.         usage();
  154.  
  155.     /* if no further arguments, must have been called as rlogin. */
  156.     if (!argv[optind]) {
  157.         if (asrsh)
  158.             *argv = "rlogin";
  159.         execv(_PATH_RLOGIN, argv);
  160.         (void)fprintf(stderr, "rsh: can't exec %s.\n", _PATH_RLOGIN);
  161.         exit(1);
  162.     }
  163.  
  164.     argc -= optind;
  165.     argv += optind;
  166.  
  167.     if (!(pw = getpwuid(uid = getuid()))) {
  168.         (void)fprintf(stderr, "rsh: unknown user id.\n");
  169.         exit(1);
  170.     }
  171.     if (!user)
  172.         user = pw->pw_name;
  173.  
  174.  
  175.     args = copyargs(argv);
  176.  
  177.     sp = getservbyname("shell", "tcp");
  178.     if (sp == NULL) {
  179.         (void)fprintf(stderr, "rsh: shell/tcp: unknown service.\n");
  180.         exit(1);
  181.     }
  182.  
  183.     setuid(0);    /*    For OSK set us to be superuser */
  184.     rem = rcmd(&host, sp->s_port, pw->pw_name, user, args, &rfd2);
  185.     setuid(uid);
  186.     if (rem < 0)
  187.         exit(1);
  188.  
  189.     if (rfd2 < 0) {
  190.         (void)fprintf(stderr, "rsh: can't establish stderr.\n");
  191.         exit(1);
  192.     }
  193.     if (dflag) {
  194.         if (setsockopt(rem, SOL_SOCKET, SO_DEBUG, &one,
  195.             sizeof(one)) < 0)
  196.             perror("setsockopt(rem)");
  197.         if (setsockopt(rfd2, SOL_SOCKET, SO_DEBUG, &one,
  198.             sizeof(one)) < 0)
  199.             perror("setsockopt(rfd2)");
  200.     }
  201.  
  202.     sigmask(1);        /*OS9 has to block the lot ! */
  203.     intercept(pass_sig);
  204.     if( set_skt_block(rfd2,1) == -1) perror("rfd2 non-blocking");
  205.     if( set_skt_block(rem,1) == -1 ) perror("rem non-blocking");
  206.     talk(nflag, pid, rem);
  207.     exit(0);
  208. }
  209.  
  210. /*----------------------------------------------------------------------*/
  211. talk(nflag, pid, rem)
  212.     int nflag, pid;
  213.     register int rem;
  214. {
  215.     register int cc, wc;
  216.     register char *bp;
  217.     int skto=1,skte=1, scfo, scfe;
  218.     char buf[BUFSIZ];
  219.     static char *argblk[]={"",0};
  220.     extern int os9forkc();
  221.     extern char **environ;
  222.     int evid;
  223.     char event[12];
  224.  
  225.     if (!nflag) {            /* spawn a daughter to handle stdin -> remote */
  226.     /*
  227.         Place the secondary channel onto path 3
  228.     */
  229.         close(3);    /* this was reserved for this purpose */
  230.         dup(rfd2);
  231.     /*
  232.         Place the primary channel onto std output for daughter process
  233.     */
  234.         cc=dup(1);    /*duplicate output path*/
  235.         close(1);
  236.         dup(rem);    /*cpy socket rem to this path*/
  237.         pid=os9exec(os9forkc,"rsh",argblk,environ,0,0,4);
  238.         if (pid==-1) exit(_errmsg(errno,"forking daughter"));
  239.         close(1);
  240.         dup(cc);    /*reinstate std output*/
  241.         close(cc);
  242.         close(wc);
  243.     /*
  244.         We must now also close the std input path. This is required
  245.         because if it is a pipe the daughter will never find the end
  246.         while we hold onto it.
  247.     */ 
  248.         close(0);
  249.     }
  250.  
  251. /*
  252.  * Meanwhile we'll handle remot => stdout and stderr channels.
  253.    OS9 and UNIX use different newline codes. If the output paths are
  254.    SCF devices we will automatically attempt a conversion. If they aren't
  255.    (eg pipes, RBF) we copy as is
  256. */
  257.     scfo=isatty(1);
  258.     scfe=isatty(2);
  259.  
  260. /* OS9 has no select function so prepare an alternative ... */
  261.  
  262.     sprintf(event,"rsh%d",getpid());    /* unique name */
  263.     if((evid=_ev_creat(0,-1,-1,event)) == -1)
  264.         exit(_errmsg(errno,"Can't create new %s event",event));
  265.     if( _ss_sevent(rfd2,evid) == -1)
  266.         exit(_errmsg(errno,"Can't set rfd2 event"));
  267.     if( _ss_sevent(rem,evid) == -1)
  268.         exit(_errmsg(errno,"Can't set rem event"));
  269.     (void)sigmask(-1);
  270. /* I don't trust the event mechanism so lets set up a periodic wake up */
  271.     alm_cycle(999, 100);
  272. /*
  273.     GO ....
  274. */
  275.     for(;;) {
  276. /* ... Poll input skt ... */
  277.         if (skto) {
  278.             errno = 0;
  279. chko:        cc = read(rem, buf, sizeof buf);
  280.             if (cc <= 0) {
  281.                 if (errno != EWOULDBLOCK){
  282. /*
  283. The following line should not be necessary! It seems that the read to rfd2
  284. (below) can fail to notice that the socket has been closed and returns
  285. EWOULDBLOCK. Thus the process can enter an endless loop waiting for a
  286. non-existent socket to feed data. This set_opt call appears to mark it closed,
  287. allowing this process to terminate.
  288. */
  289.                     set_skt_block(rfd2,0);
  290.                     skto=0;
  291.                 }
  292.             } else{
  293.                 if(scfo) scf_write(1,buf,cc);
  294.                 else write(1, buf, cc);
  295.                 goto chko;    /* see if there's already more */
  296.             }
  297.         }
  298.  
  299. /* ... Poll error skt ... */
  300.         if (skte) {
  301. chke:        errno = 0;
  302.             cc = read(rfd2, buf, sizeof buf);
  303.             if (cc <= 0) {
  304.                 if (errno != EWOULDBLOCK)
  305.                     skte=0;
  306.             } else {
  307.                 if(scfe) scf_write(2,buf,cc);
  308.                 else write(2, buf, cc);
  309.                 goto chke;    /* see if there's already more */
  310.             }
  311.         }
  312.  
  313.         if( !skto && !skte) break;
  314.         
  315. /* Await more data using event flags */
  316.         if (_ev_wait(evid,1,32767) == -1)
  317.             exit(_errmsg(errno,"Can't wait"));
  318.     }
  319.  
  320. /* ... tidy up after ourself ... */
  321.     _ev_unlink(evid);
  322.     _ev_delete(event);
  323.     if (!nflag)
  324.         (void)kill(pid, SIGKILL);
  325. }
  326.  
  327. void pass_sig(signal)
  328. int signal;
  329. {
  330.     char signo;
  331.     switch (signal){
  332.         case SIGINT:    signo=2;
  333.             break;
  334.         case SIGQUIT:    signo=3;
  335.             break;
  336.         case SIGHUP:    signo=1;
  337.             break;
  338.         case SIGKILL:    signo=9;    /* This can't actually be caught */
  339.             break;
  340.         default:
  341.             return;        /*Ignore any others*/
  342.             break;
  343.     }
  344.     if( write(rfd2, &signo, 1) != 1) close(rfd2);
  345. }
  346.  
  347.  
  348. char *
  349. copyargs(argv)
  350.     char **argv;
  351. {
  352.     register int cc;
  353.     register char **ap, *p;
  354.     char *args, *malloc();
  355.  
  356.     cc = 0;
  357.     for (ap = argv; *ap; ++ap)
  358.         cc += strlen(*ap) + 1;
  359.     if (!(args = malloc((u_int)cc))) {
  360.         exit(_errmsg(errno,"No mem for malloc"));
  361.     }
  362.     for (p = args, ap = argv; *ap; ++ap) {
  363.         strcpy(p, *ap);
  364.         while(*++p);    /* move to null terminator */
  365.         if (ap[1]) *p++ = ' ';    /* change to space */
  366.     }
  367.     return(args);
  368. }
  369.  
  370. usage()
  371. {
  372.     (void)fprintf(stderr,
  373.         "usage: rsh [-nd%s]%s[-l login] host [command]\n",
  374.         "", " ");
  375.     exit(1);
  376. }
  377.  
  378. /**************************************************************************/
  379.     
  380. rshb()
  381. /*
  382.     sub-process to copy stdin to the remote host via socket which is
  383.     presumed to be on path 1. Using the same logic as previously we will
  384.     convert OS9 \r to Unix \l codes _if_ the stdin is a tty.
  385. */
  386. {
  387.     register int cc, wc;
  388.     register char *bp;
  389.     char buf[BUFSIZ];
  390.     int pipe, scf, n;
  391.  
  392.     scf=isatty(0);
  393.     pipe=isapipe(0);
  394.  
  395. reread:
  396.     n=BUFSIZ;
  397.     if(scf){
  398.         if (_gs_rdy(0) <=0){
  399.             sigmask(1);
  400.             if (_ss_ssig(0,SIGWAKE) == -1) exit(errno);
  401.             sleep(0);    /*await data ready*/
  402.         }
  403.     }else if(pipe){
  404.         if( (n=_gs_rdy(0)) <=0) n=1;
  405.         if(n > BUFSIZ) n=BUFSIZ;
  406.     }
  407.     if ((cc = read(0, buf, n )) <= 0)
  408.         goto done;
  409.     if(scf) os2ux(buf,cc);    /* convert \n codes */
  410.     bp = buf;
  411. rewrite:
  412.         wc = write(1, bp, cc);
  413.         if (wc < 0) {
  414.             if (errno == EWOULDBLOCK){
  415.                 tsleep(1);        /*without select what else can you do? */
  416.                 goto rewrite;
  417.  
  418.             }
  419.             goto done;
  420.         }
  421.         bp += wc;
  422.         cc -= wc;
  423.         if (cc == 0)
  424.             goto reread;
  425.         goto rewrite;
  426. done:
  427.         shutdown(1,1);        /* shutdown is crucial to flag other end */
  428.         exit(0);
  429. }
  430.  
  431. /******************************************************************/
  432. scf_write(p,t,n)
  433. /*
  434.  The following is a means to convert the UNIX
  435.  newline character to \r for useful looking output on an OS9
  436.  terminal
  437. */
  438. int p,n;
  439. register char *t;
  440. {
  441.     register int i;
  442.     register char *s;
  443.  
  444.     for(i=0,s=t;i<n;i++,s++){
  445.         if(*s == '\l') *s='\r';
  446.     }
  447.     while( (i=writeln(p,t,n)) < n ){
  448.         n -= i;
  449.         t += i;
  450.     }
  451. }
  452. /*
  453.  The next routine converts \n codes
  454. */
  455. os2ux(p,c)
  456. register char *p;
  457. register int c;
  458. {
  459.     register i;
  460.     for(i=0;i<c;i++,p++){
  461.         if(*p == '\n') *p='\l';
  462.     }
  463. }
  464.