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 >
Wrap
C/C++ Source or Header
|
1992-10-06
|
11KB
|
464 lines
/*
RSH.C OS9/68K Version
Ivan Powis <pczip@chem.nott.ac.uk> 1-Sep-92
-
* Copyright (c) 1983, 1990 The Regents of the University of California.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef lint
char copyright[] =
"@(#) Copyright (c) 1983, 1990 The Regents of the University of California.\n\
Additional material for OS9 Copyright (c) 1992 Ivan Powis\n\
All rights reserved.\n";
#endif /* not lint */
#ifndef lint
static char sccsid[] = "@(#)rsh.c 5.24 (Berkeley) 7/1/91";
#endif /* not lint */
/*
* $Source: mit/rsh/RCS/rsh.c,v $
* $Header: mit/rsh/RCS/rsh.c,v 5.1 89/07/31 19:28:59 kfall Exp Locker: kfall $
*/
#include <types.h>
#include <signal.h>
#include <inet/socket.h>
#include <inet/in.h>
#include <inet/netdb.h>
/* The following are not std OS9 - I use blarslib headers + library */
#include <pwd.h>
#include <stdio.h>
#include <errno.h>
#include <strings.h>
#define _PATH_RLOGIN "rlogin"
#define perror(A) prerr(0,_errmsg(errno,(A)))
/*
* rsh - remote shell
*/
extern int errno;
int rfd2;
main(argc, argv, envp)
int argc;
char **argv, **envp;
{
extern char *optarg;
extern int optind;
struct passwd *pw;
struct servent *sp;
int argoff, asrsh, ch, dflag, nflag, one, pid, rem, uid;
register char *p;
char *args, *host, *user, *copyargs();
void pass_sig();
if (*argv[0]==0) {
/*
* We're an OS9 daughter process
* Keyboard signals may come to either this process or the parent under
* OS9 - it just depends which last did i/o to the terminal. Consequently
* we arrange to catch them in either case.
*/
rfd2=3; /* Parent must pass error channel skt */
intercept(pass_sig);
rshb(); /* We never return from rshb() */
}
/*
We're the main process.
*/
argoff = asrsh = dflag = nflag = 0;
one = 1;
host = user = NULL;
dup(2); /* reserve path number 3 for later use */
/* if called as something other than "rsh", use it as the host name */
if (p = rindex(argv[0], '/'))
++p;
else
p = argv[0];
if (strcmp(p, "rsh"))
host = p;
else
asrsh = 1;
/* handle "rsh host flags" */
if (!host && argc > 2 && argv[1][0] != '-') {
host = argv[1];
argoff = 1;
}
#define OPTIONS "8KLdel:nw"
while ((ch = getopt(argc - argoff, argv + argoff, OPTIONS)) != EOF)
switch(ch) {
case 'K':
break;
case 'L': /* -8Lew are ignored to allow rlogin aliases */
case 'e':
case 'w':
case '8':
break;
case 'd':
dflag = 1;
break;
case 'l':
user = optarg;
break;
case 'n':
nflag = 1;
break;
case '?':
default:
usage();
}
optind += argoff;
/* if haven't gotten a host yet, do so */
if (!host && !(host = argv[optind++]))
usage();
/* if no further arguments, must have been called as rlogin. */
if (!argv[optind]) {
if (asrsh)
*argv = "rlogin";
execv(_PATH_RLOGIN, argv);
(void)fprintf(stderr, "rsh: can't exec %s.\n", _PATH_RLOGIN);
exit(1);
}
argc -= optind;
argv += optind;
if (!(pw = getpwuid(uid = getuid()))) {
(void)fprintf(stderr, "rsh: unknown user id.\n");
exit(1);
}
if (!user)
user = pw->pw_name;
args = copyargs(argv);
sp = getservbyname("shell", "tcp");
if (sp == NULL) {
(void)fprintf(stderr, "rsh: shell/tcp: unknown service.\n");
exit(1);
}
setuid(0); /* For OSK set us to be superuser */
rem = rcmd(&host, sp->s_port, pw->pw_name, user, args, &rfd2);
setuid(uid);
if (rem < 0)
exit(1);
if (rfd2 < 0) {
(void)fprintf(stderr, "rsh: can't establish stderr.\n");
exit(1);
}
if (dflag) {
if (setsockopt(rem, SOL_SOCKET, SO_DEBUG, &one,
sizeof(one)) < 0)
perror("setsockopt(rem)");
if (setsockopt(rfd2, SOL_SOCKET, SO_DEBUG, &one,
sizeof(one)) < 0)
perror("setsockopt(rfd2)");
}
sigmask(1); /*OS9 has to block the lot ! */
intercept(pass_sig);
if( set_skt_block(rfd2,1) == -1) perror("rfd2 non-blocking");
if( set_skt_block(rem,1) == -1 ) perror("rem non-blocking");
talk(nflag, pid, rem);
exit(0);
}
/*----------------------------------------------------------------------*/
talk(nflag, pid, rem)
int nflag, pid;
register int rem;
{
register int cc, wc;
register char *bp;
int skto=1,skte=1, scfo, scfe;
char buf[BUFSIZ];
static char *argblk[]={"",0};
extern int os9forkc();
extern char **environ;
int evid;
char event[12];
if (!nflag) { /* spawn a daughter to handle stdin -> remote */
/*
Place the secondary channel onto path 3
*/
close(3); /* this was reserved for this purpose */
dup(rfd2);
/*
Place the primary channel onto std output for daughter process
*/
cc=dup(1); /*duplicate output path*/
close(1);
dup(rem); /*cpy socket rem to this path*/
pid=os9exec(os9forkc,"rsh",argblk,environ,0,0,4);
if (pid==-1) exit(_errmsg(errno,"forking daughter"));
close(1);
dup(cc); /*reinstate std output*/
close(cc);
close(wc);
/*
We must now also close the std input path. This is required
because if it is a pipe the daughter will never find the end
while we hold onto it.
*/
close(0);
}
/*
* Meanwhile we'll handle remot => stdout and stderr channels.
OS9 and UNIX use different newline codes. If the output paths are
SCF devices we will automatically attempt a conversion. If they aren't
(eg pipes, RBF) we copy as is
*/
scfo=isatty(1);
scfe=isatty(2);
/* OS9 has no select function so prepare an alternative ... */
sprintf(event,"rsh%d",getpid()); /* unique name */
if((evid=_ev_creat(0,-1,-1,event)) == -1)
exit(_errmsg(errno,"Can't create new %s event",event));
if( _ss_sevent(rfd2,evid) == -1)
exit(_errmsg(errno,"Can't set rfd2 event"));
if( _ss_sevent(rem,evid) == -1)
exit(_errmsg(errno,"Can't set rem event"));
(void)sigmask(-1);
/* I don't trust the event mechanism so lets set up a periodic wake up */
alm_cycle(999, 100);
/*
GO ....
*/
for(;;) {
/* ... Poll input skt ... */
if (skto) {
errno = 0;
chko: cc = read(rem, buf, sizeof buf);
if (cc <= 0) {
if (errno != EWOULDBLOCK){
/*
The following line should not be necessary! It seems that the read to rfd2
(below) can fail to notice that the socket has been closed and returns
EWOULDBLOCK. Thus the process can enter an endless loop waiting for a
non-existent socket to feed data. This set_opt call appears to mark it closed,
allowing this process to terminate.
*/
set_skt_block(rfd2,0);
skto=0;
}
} else{
if(scfo) scf_write(1,buf,cc);
else write(1, buf, cc);
goto chko; /* see if there's already more */
}
}
/* ... Poll error skt ... */
if (skte) {
chke: errno = 0;
cc = read(rfd2, buf, sizeof buf);
if (cc <= 0) {
if (errno != EWOULDBLOCK)
skte=0;
} else {
if(scfe) scf_write(2,buf,cc);
else write(2, buf, cc);
goto chke; /* see if there's already more */
}
}
if( !skto && !skte) break;
/* Await more data using event flags */
if (_ev_wait(evid,1,32767) == -1)
exit(_errmsg(errno,"Can't wait"));
}
/* ... tidy up after ourself ... */
_ev_unlink(evid);
_ev_delete(event);
if (!nflag)
(void)kill(pid, SIGKILL);
}
void pass_sig(signal)
int signal;
{
char signo;
switch (signal){
case SIGINT: signo=2;
break;
case SIGQUIT: signo=3;
break;
case SIGHUP: signo=1;
break;
case SIGKILL: signo=9; /* This can't actually be caught */
break;
default:
return; /*Ignore any others*/
break;
}
if( write(rfd2, &signo, 1) != 1) close(rfd2);
}
char *
copyargs(argv)
char **argv;
{
register int cc;
register char **ap, *p;
char *args, *malloc();
cc = 0;
for (ap = argv; *ap; ++ap)
cc += strlen(*ap) + 1;
if (!(args = malloc((u_int)cc))) {
exit(_errmsg(errno,"No mem for malloc"));
}
for (p = args, ap = argv; *ap; ++ap) {
strcpy(p, *ap);
while(*++p); /* move to null terminator */
if (ap[1]) *p++ = ' '; /* change to space */
}
return(args);
}
usage()
{
(void)fprintf(stderr,
"usage: rsh [-nd%s]%s[-l login] host [command]\n",
"", " ");
exit(1);
}
/**************************************************************************/
rshb()
/*
sub-process to copy stdin to the remote host via socket which is
presumed to be on path 1. Using the same logic as previously we will
convert OS9 \r to Unix \l codes _if_ the stdin is a tty.
*/
{
register int cc, wc;
register char *bp;
char buf[BUFSIZ];
int pipe, scf, n;
scf=isatty(0);
pipe=isapipe(0);
reread:
n=BUFSIZ;
if(scf){
if (_gs_rdy(0) <=0){
sigmask(1);
if (_ss_ssig(0,SIGWAKE) == -1) exit(errno);
sleep(0); /*await data ready*/
}
}else if(pipe){
if( (n=_gs_rdy(0)) <=0) n=1;
if(n > BUFSIZ) n=BUFSIZ;
}
if ((cc = read(0, buf, n )) <= 0)
goto done;
if(scf) os2ux(buf,cc); /* convert \n codes */
bp = buf;
rewrite:
wc = write(1, bp, cc);
if (wc < 0) {
if (errno == EWOULDBLOCK){
tsleep(1); /*without select what else can you do? */
goto rewrite;
}
goto done;
}
bp += wc;
cc -= wc;
if (cc == 0)
goto reread;
goto rewrite;
done:
shutdown(1,1); /* shutdown is crucial to flag other end */
exit(0);
}
/******************************************************************/
scf_write(p,t,n)
/*
The following is a means to convert the UNIX
newline character to \r for useful looking output on an OS9
terminal
*/
int p,n;
register char *t;
{
register int i;
register char *s;
for(i=0,s=t;i<n;i++,s++){
if(*s == '\l') *s='\r';
}
while( (i=writeln(p,t,n)) < n ){
n -= i;
t += i;
}
}
/*
The next routine converts \n codes
*/
os2ux(p,c)
register char *p;
register int c;
{
register i;
for(i=0;i<c;i++,p++){
if(*p == '\n') *p='\l';
}
}