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 / rshdc.c < prev    next >
C/C++ Source or Header  |  1992-10-02  |  10KB  |  360 lines

  1. /*--------------------------------------------------------------------------*/
  2. /*RSHDC*/
  3. /*Ivan Powis <pczip@chem.nott.ac.uk> 9/92 */
  4.  
  5. /*    The basic requirement is to fork a shell to execute the command. 
  6. In the original Unix version the main process then sits in a select loop
  7. and monitors pipes from the shell std-out and std-err, feeding the data
  8. streams into the sockets back for return to the client.  Thus when the
  9. pipes are closed the daemon knows the shell has terminated and can close
  10. down.  Simultaneously the auxilliary control socket is monitored for
  11. incoming bytes to be signalled to the process. 
  12.     To the OS9 version I added the functionality to inter-convert \r
  13. & \l to improve communication with the Unix Universe.  This is enabled
  14. on stdin/out by a '+'flag as the first character of the command string. 
  15. I took the decision that stderr would always be human readable, so it
  16. always does such a conversion. 
  17.     OS9 problems: (i) was a lack of select, and inconsistent ways of
  18. monitoring sockets and pipes for data ready (events and signals).  (ii)
  19. Another is the inconsistent way of checking for data available (_gs_rdy
  20. & read on a non-blocking socket) and the fact that _gs_rdy on a pipe
  21. doesn't indicate end-of-pipe (only E_NOTRDY) - in fact the only way I
  22. know to check for EOF on a pipe is to do a read and get a 0 return - but
  23. this cannot be then multiplexed with monitoring other pipes in a single
  24. task.(iii) a full duplex socket suffers from the same brain damage as
  25. SCF ie one task waiting on a read blocks output for another (iv)
  26. SO_LINGER on a socket doesn't seem to be functional.  Thus its advisable
  27. to hold a socket open for a while after the last write to ensure that
  28. data is flushed through it. 
  29.     Microware - all this money for low grade software ...?
  30.  */
  31. char copyright[] = "@(#) Copyright (c) 1992 Ivan Powis.\n\
  32. All rights reserved.\n";
  33.  
  34. #include <signal.h>
  35. #include <errno.h>
  36. #include <procid.h>
  37.  
  38. #define NULL    (void *) 0
  39. #define TRACE(A,B)  _errmsg(0,(A),(B))
  40. #define min(A,B)    (A)<(B) ? (A) : (B)
  41. #define MAXB    512
  42.  
  43. #define in_skt  0
  44. #define out_skt 1
  45. #define err_skt 2
  46. #define err_pipe    3
  47. #define in_pipe     4
  48. #define out_pipe    5
  49.  
  50. extern int os9forkc();
  51. extern int errno;
  52.  
  53. static int evid;
  54. static char event_nam[20];
  55.  
  56. /*
  57.  *  The main program decides whether we are to fork to create an orphaned
  58.  *  rshdc process, or whether we are the orphan!
  59.  */
  60.  
  61. main(argc,argv,envp)
  62. int argc;
  63. char **argv, **envp;
  64. {
  65.     int pid;
  66.  
  67.     switch (**argv){
  68.         case 0:     /* become the active orphan */
  69.             orphan(argc,argv,envp);
  70.             break;
  71.         case 1:     /* copy err_pipe to err_skt only */
  72.             close(in_skt);  /* not needed */
  73.             close(out_skt);
  74.             xfer(err_pipe,err_skt);
  75.             break;
  76.         case 2:     /* copy out_pipe to out_skt with \r -> \l */
  77.         close(in_skt);
  78.         close(err_skt);
  79.         close(in_pipe);
  80.         close(err_pipe);
  81.         xfer(out_pipe,out_skt);
  82.             break;
  83.     case 3:        /* copy in_skt -> in_pipe * with \l -> \r */
  84.         close(out_skt);
  85.         close(err_skt);
  86.         close(err_pipe);
  87.         refx(in_skt,in_pipe);
  88.         break;
  89.         case 4:     /* monitor auxilliary control skt */
  90.             close(in_skt);
  91.             close(out_skt);
  92.             monitor();
  93.             break;
  94.         default:    /* respawn then orphan */
  95.             **argv=0;
  96.             pid=os9exec(os9forkc,"rshdc",argv,envp,0,0,3);
  97.             if(pid==-1) exit(_errmsg(errno,"Can't orphan"));
  98.             exit(0);
  99.     }
  100. }
  101.  
  102. /*===================================================================
  103.  *  If this is the orphan go to business ...
  104. =================================================================== */
  105.  
  106. static int pid5=0;
  107.  
  108. orphan(argc,argv,envp)
  109. int argc;
  110. char **argv;
  111. {
  112.     register int tmp1;
  113.     int status, pid1=0, pid2=0, pid3=0, pid4=0;
  114.     int tr=0;           /* flag for \r to \l translation */
  115.     int mon=0;          /* flag for use of control channel */
  116.     int pass_em();
  117.     char *err_str, *strerror();
  118. /*
  119.  * argv { code, y/n, shell, command }
  120.  */
  121.     if (*argv[1] == 'y') mon=1;
  122.     if (*argv[3] == '+' || *argv[3] == '@'){
  123.         tr=1;           /* + flag to enable OSk <-> Unix translation */
  124.         argv[3]++;      /* advance past the + flag */
  125.     }
  126. /*
  127.  *  create a process to copy and translate err path
  128.  */
  129.     if ( (tmp1=create("/pipe",0x23,0,256)) != err_pipe)
  130.             exit(_errmsg(0,"err pipe %d\n",tmp1));
  131.     **argv=1;
  132.     pid1=os9exec(os9forkc,"rshdc",argv,envp,0,0,err_pipe+1);
  133.     if(pid1==-1) exit(_errmsg(errno,"Can't fork"));
  134. /*
  135.  *  create processes to copy and translate stdin and stdout
  136.  */
  137.     if(tr){
  138.         if ( (tmp1=create("/pipe",0x23,0,256)) != in_pipe)
  139.                 exit(_errmsg(0,"in pipe %d\n",tmp1));
  140.         if ( (tmp1=create("/pipe",0x23,0,256)) != out_pipe)
  141.                 exit(_errmsg(0,"out pipe %d\n",tmp1));
  142.         **argv=2;
  143.         pid2=os9exec(os9forkc,"rshdc",argv,envp,0,0,out_pipe+1);
  144.         if(pid2==-1) exit(_errmsg(errno,"Can't fork"));
  145.         **argv=3;
  146.         pid3=os9exec(os9forkc,"rshdc",argv,envp,0,0,in_pipe+1);
  147.         if(pid3==-1) exit(_errmsg(errno,"Can't fork"));
  148.     }
  149.  
  150. /*
  151.  * if required create a monitor process.
  152.  */
  153.     if(mon){
  154.         sigmask(1);
  155.         intercept(pass_em); 
  156.         **argv=4;
  157.         pid4=os9exec(os9forkc,"rshdc",argv,envp,0,0,3);
  158.         if(pid4==-1) exit(_errmsg(errno,"Can't fork mon"));
  159.     }
  160. /*
  161.  *  prepare to exec shell by juggling paths and arguments
  162.  */
  163.     if (tr){
  164.         exg_paths(out_pipe,out_skt);
  165.         exg_paths(in_pipe,in_skt);
  166.     }
  167.     exg_paths(err_pipe,err_skt);
  168.  
  169.     argv++; /*skip rshdc*/ 
  170.     argv++; /*skip y/n */
  171.     pid5=os9exec(os9forkc,argv[0],argv,envp,0,0,3);
  172.     if(pid5<=0) {
  173.         exit(_errmsg(errno,"can't fork shell"));
  174.     }
  175. /*
  176.  *  Reset std_in, std_out, std_err sockets on the correct paths
  177.  */
  178.     if (tr){
  179.         dup2(in_pipe,in_skt);
  180.         close(in_pipe);
  181.         dup2(out_pipe,out_skt);
  182.         close(out_pipe);
  183.     }
  184.     dup2(err_pipe,err_skt);
  185.     close(err_pipe);
  186. /*
  187.  *  Now wait for shell to quit then tidy up
  188.  */
  189.     if (mon) sigmask(0);
  190.     while( (tmp1=wait(&status)) != pid5){
  191.         if(tmp1 > 0 && status){
  192.             _errmsg(0,"daughter %d aborts:\l",tmp1);
  193.             err_str=strerror(status);
  194.             write(err_skt,err_str,strlen(err_str));
  195.             write(err_skt,"\l",1);
  196.         }
  197.     }
  198.     if(status){
  199.         err_str=strerror(status);
  200.         write(err_skt,err_str,strlen(err_str));
  201.         write(err_skt,"\l",1);
  202.     }
  203.     if(pid3){
  204.         kill(pid3,SIGKILL);
  205.         sprintf(event_nam,"rshdc%d",pid3);
  206.         evid=_ev_link(event_nam);
  207.         _ev_unlink(evid);
  208.         _ev_unlink(evid);
  209.         _ev_delete(event_nam);
  210.     }
  211.     if(pid4){
  212.         kill(pid4,SIGKILL);
  213.         sprintf(event_nam,"rshdc%d",pid4);
  214.         evid=_ev_link(event_nam);
  215.         _ev_unlink(evid);
  216.         _ev_unlink(evid);
  217.         _ev_delete(event_nam);
  218.     }
  219.     tsleep(75);     /* SO_LINGER bug work around */
  220.     exit(0);
  221. }
  222.  
  223. /*-------------------------------------------------------------------
  224.  *  intercept routine pass signal on to shell daughter
  225. ------------------------------------------------------------------- */
  226.  
  227. int pass_em(code)
  228. int code;
  229. {
  230.     procid procdesc;
  231.     int sub_shell;
  232.  
  233.     _get_process_desc(pid5, (int)sizeof(procdesc), &procdesc);
  234.    sub_shell=procdesc._cid;
  235.    if(sub_shell > 0){
  236.         kill(sub_shell,code);
  237.    }else{
  238.     kill(pid5,code);
  239.    }
  240. }
  241.  
  242. /*-------------------------------------------------------------------
  243.  * monitoring task: (i) monitor the control skt for signals
  244.  * to relay to the parent
  245. ------------------------------------------------------------------- */
  246. monitor()
  247. {
  248.     register int cc,ppid;
  249.     char sigval;
  250.  
  251.     ppid=getppid();
  252. /*
  253.  *  Use events to signal incoming data from control
  254.  */
  255.     sprintf(event_nam,"rshdc%d",getpid());  /* unique name */
  256.     if((evid=_ev_creat(0,-1,-1,event_nam)) == -1 && errno == E_EVBUSY){
  257.             evid=_ev_link(event_nam);   /*try to use existing one*/
  258.     }
  259.     if(evid==-1){
  260.         exit(_errmsg(errno,"Can't create new %s event",event_nam));
  261.     }
  262.     if( _ss_sevent(err_skt,evid) == -1)
  263.         exit(_errmsg(errno,"Can't set contol skt event"));
  264.         
  265. /* Await data */
  266.     while( _ev_wait(evid,1,32767) > 0 ){
  267.         if((cc=read(err_skt,&sigval,1)) != 1) break;
  268.         if(sigval==2) sigval=3;
  269.         else if(sigval==3) sigval=2;
  270.         if( kill(ppid, (short) sigval)==-1 ) exit(errno);
  271.     }
  272.     shutdown(err_skt,0);
  273.     exit(errno);
  274. }
  275.  
  276. /*-------------------------------------------------------------------
  277.  * refx - copy std input skt to pipe with translation
  278.  * from the os9 to unix universe (ie \l -> \r)
  279. ------------------------------------------------------------------- */
  280.  
  281. refx(a,b)
  282. {
  283.     char buff[MAXB];
  284.     register int cc;
  285. /*
  286.  * OS9 lacks select so use events to signal incoming data from control
  287.  */
  288.     sprintf(event_nam,"rshdc%d",getpid());  /* unique name */
  289.     if((evid=_ev_creat(0,-1,-1,event_nam)) == -1 && errno == E_EVBUSY){
  290.             evid=_ev_link(event_nam);   /*try to use existing one*/
  291.     }
  292.     if(evid==-1){
  293.         exit(_errmsg(errno,"Can't create new %s event",event_nam));
  294.     }
  295.     if( _ss_sevent(in_skt,evid) == -1)
  296.         exit(_errmsg(errno,"Can't set in_skt event"));
  297.         
  298. /* Await data using event flags and signals */
  299.     while( _ev_wait(evid,1,32767) > 0 ){
  300.         if((cc=read(in_skt,buff,MAXB)) < 1) break;
  301.         l2r(buff, cc);
  302.         cc=write(in_pipe,buff,cc);
  303.     }
  304.     shutdown(in_skt,0);
  305.     close(in_pipe);
  306.     exit(errno);
  307. }
  308.  
  309. /*-------------------------------------------------------------------
  310.  * xfer - copy ???_pipe to ???_skt with translation from the os9
  311.  * to unix universe (ie \r -> \l)
  312. ------------------------------------------------------------------- */
  313.  
  314. xfer(a,b)
  315. int a,b;
  316. {
  317.     register int cc;
  318.     char buff[MAXB];
  319.  
  320.     while ( (cc=readln(a,buff, MAXB)) > 0){
  321.             r2l(buff, cc);
  322.             cc=write(b,buff,cc);
  323.     }
  324.     exit(errno);
  325. }
  326. /*-------------------------------------------------------------------*/
  327. /*      utilities   */
  328.  
  329. r2l(buff,n)
  330. register char *buff;
  331. register int n;
  332.  
  333. {
  334.     for(;n>0;--n, buff++){
  335.         if(*buff == '\r') *buff='\l';
  336.     }
  337. }
  338.  
  339. l2r(buff,n)
  340. register char *buff;
  341. register int n;
  342.  
  343. {
  344.     for(;n>0;--n, buff++){
  345.         if(*buff == '\l') *buff='\r';
  346.     }
  347. }
  348.  
  349. exg_paths(a,b)
  350. int a,b;
  351. {
  352.     register int tmp;
  353.  
  354.     tmp=dup(a);
  355.     dup2(b,a);
  356.     dup2(tmp,b);
  357.     close(tmp);
  358. }
  359.  
  360.