Files
seta75D d6fe8fe829 Init
2021-10-11 22:19:34 -03:00

771 lines
12 KiB
C

static char sccsid[] = "@(#)54 1.11 src/bos/usr/lib/boot/ssh.c, bosboot, bos411, 9428A410j 93/10/13 13:17:37";
/*
* COMPONENT_NAME: (BOSBOOT) Base Operating System Boot
*
* FUNCTIONS: ssh.c (boot init)
*
* ORIGINS: 27
*
* IBM CONFIDENTIAL -- (IBM Confidential Restricted when
* combined with the aggregated modules for this product)
* SOURCE MATERIALS
* (C) COPYRIGHT International Business Machines Corp. 1990
* All Rights Reserved
*
* US Government Users Restricted Rights - Use, duplication or
* disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/fullstat.h>
#include <errno.h>
#include <sys/termio.h>
#include <ustat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/access.h>
#include <signal.h>
#include <assert.h>
#include <sys/shm.h>
#include <sys/sysconfig.h>
#include <sys/var.h>
FILE *fp0, *fp1, *fp2;
int fd0;
struct termio tt;
int trace;
int lineo;
char *dflt_env[] = { "HOME=/", "PATH=/usr/sbin:/etc:/usr/bin::", (char *) 0 };
char **env = dflt_env;
int Xrv;
int Xerrno;
int init;
/*
* When the system is booted, very little device support is available.
* Before the system console can be accessed, a variety of device drivers
* must be loaded and a bunch of configuration stuff must be performed.
*/
#define DBG_CONSOLE "/dev/dbgcons"
#define CONSOLE "/dev/console"
#define NO_CONSOLE "/dev/null"
#define RCBOOT "/sbin/rc.boot"
#define SYSINIT "/sbin/rc.boot 1"
#define BRC "/sbin/rc.boot 2"
#define SHELL "/usr/bin/sh"
FILE *coninit();
#define INTERACTIVE 1
#define BATCH 2
/* return values from icmd */
#define ICMD 0
#define XCMD 1
#define SUCCESS 0
#define FAILURE 1
/* special return values from doit */
#define EFATAL (NSIG+1)
static get_ctl_term = 0; /* get a controlling terminal */
main(argc,argv,envp)
char **argv, **envp;
{
FILE *fp;
int rc, done;
if( envp )
if( *envp )
env = envp;
init = getpid() == 1 ? 1 : 0;
/*
* Check to see if base file descriptors are already open
* if not, then open /dev/console.
*/
if( init )
{
/*
* Perform any boot time initializations before
* attempting to access the console.
*/
fp = coninit(DBG_CONSOLE);
if( access(RCBOOT,X_OK) == 0 )
{
fprintf(fp,"\nINIT: EXECUTING %s\n", SYSINIT);
if( execute(SYSINIT) )
{
fprintf(fp,"\nINIT: %s failed\n", SYSINIT);
exit(1);
}
}
fclose(fp);
fp = coninit(CONSOLE);
errno = 0;
/*
* If brc returns then BRC exited with a non-zero status,
* attempt to start a shell on the console.
*/
if( access(RCBOOT,X_OK) == 0 ) brc(BRC,fp);
done = 0;
/* set up stdin (fp0), stdout(fp1), stderr(fp2) for doit() */
fp0 = fp;
fp1 = fp;
fp2 = fp;
while( !done )
{
fprintf(fp,"\nINIT: SINGLE USER MODE\n");
get_ctl_term = 1;
if( (rc = doit(SHELL)) == EFATAL )
done = 1;
}
fprintf(fp,"\nINIT: FATAL ERROR IN %s\n", SHELL);
/*
* If a shell cannot be started on the console,
* then attempt to go into interactive mode.
*/
}
else
{
fp0 = stdin;
fp1 = stdout;
fp2 = stderr;
if( argc > 1 ) /* support ssh -c command ala the shell */
if( *argv[1] == '-' && *(argv[1]+1) == 'c' )
return(doit(argv[2]));
}
loop(fp0,INTERACTIVE);
}
loop(fp,mode)
FILE *fp;
int mode;
{
char buf[256], *p;
fprintf(fp1,"XIX s-shell");
for( lineo = 0; ; mode == INTERACTIVE ? lineo : lineo++ )
{
fprintf(fp1,"\n# ");
fflush(fp1);
for( p = buf; p < &buf[256]; p++ )
*p = '\0';
if( fgets(buf,256,fp) == NULL )
return SUCCESS;
/*
if( mode != INTERACTIVE )
fprintf(fp1,"%s",buf);
*/
for( p = buf; *p; p++ )
if( *p == '\n' || *p == '\r' )
{
*p = '\0';
break;
}
if( *buf != '\0' && *buf != '#' )
if( doit(buf) != 0 && mode != INTERACTIVE )
return FAILURE;
}
}
char *args[80];
int nargs;
char fname[80];
doit(ptr)
char *ptr;
{
int pid, epid, waitloc, r, ic, weird;
char **cp;
for( pid = 0; pid < 80; pid++ )
args[pid] = (char *) 0;
for( nargs = 0, cp = args; *ptr; ptr++ )
{
if( !*cp )
*cp = ptr;
if( *ptr == ' ' )
{
*ptr = '\0';
cp++;
nargs++;
}
}
cp++;
*cp = (char *) 0;
r = icmd(nargs,args,&ic);
if( ic == ICMD )
return r;
switch( pid = fork() )
{
case 0:
if (init) {
/* terminal driver sends signals generated from
the keyboard to the foreground process group.
A child process that opens its terminal should
ensure the terminal driver sends no signals
to the init process. setsid() puts the child
in its own process group. */
setsid();
if (get_ctl_term) {
FILE *fp;
get_ctl_term = 0;
/* setup the console as the controlling terminal */
fp = coninit(CONSOLE);
/* ignore errors */
errno = 0;
}
}
if( *args[0] != '/' && *args[0] != '.' )
{
/* try paths */
strcpy(fname,"/usr/sbin/");
strcat(fname,args[0]);
execve(fname,args,env);
if( errno != ENOENT )
goto badexec;
strcpy(fname,"/etc/");
strcat(fname,args[0]);
execve(fname,args,env);
if( errno != ENOENT )
goto badexec;
strcpy(fname,"/usr/bin/");
strcat(fname,args[0]);
execve(fname,args,env);
if( errno != ENOENT )
goto badexec;
}
else
{
strcpy(fname,args[0]);
execve(fname,args,env);
if( errno != ENOENT )
goto badexec;
}
fprintf(fp1,"%s not found\n", args[0]);
_exit(EFATAL);
badexec:
fprintf(fp1,"execve %s failed, errno = %d\n", fname, errno);
_exit(EFATAL);
case -1:
fprintf(fp1,"fork failed, errno = %d\n", errno);
r = EFATAL;
break;
default:
epid = -1;
while (epid != pid)
{
waitloc = 0;
epid = wait(&waitloc);
}
Xrv = waitloc;
if( waitloc )
{
int v;
char *msg;
if( (waitloc & 0x7f) == 0x7f )
{
msg = "stopped by signal";
v = waitloc & 0x7f;
weird = 1;
r = EFATAL;
}
else if( waitloc & 0xff )
{
msg = "killed by signal";
v = waitloc & 0x7f;
weird = 1;
r = EFATAL;
}
else
{
msg = "exited with status";
v = waitloc >> 8;
weird = 0;
r = v;
}
if( trace || weird )
fprintf(fp1,"%s %s %d\n", args[0], msg, v);
}
else
r = 0;
break;
}
return r;
}
xcmp(a,b)
char *a, *b;
{
while( *a++ == *b++ )
if( *(a-1) == '\0' )
return 0;
return 1;
}
atoo(p)
char *p;
{
int base, v = 0;
do
{
v <<= 3;
switch( *p )
{
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8':
base = (int) '0';
break;
break;
default:
return -1;
}
v += (int) *p - base;
}
while( *++p );
return v;
}
atoh(p)
char *p;
{
int base, v = 0;
do
{
v <<= 4;
switch( *p )
{
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
base = (int) '0';
break;
case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
base = (int) 'a';
break;
case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
base = (int) 'A';
break;
default:
return -1;
}
v += (int) *p - base;
}
while( *++p );
return v;
}
/*
* System V basic system calls
*/
int Xaccess();
int Xclose();
int Xchmod();
int Xdup();
int Xexec();
int Xexit();
int Xfork();
int Xgetpid();
int Xioctl();
int Xkill();
int Xopen();
int Xwait();
int Xunlink();
int Xtelinit();
/*
* psuedo functions
*/
int Xprintf();
struct ix
{
char * cmdname;
int (* func)();
int argcount;
int return_rv;
};
struct ix ix[] =
{
{"access", Xaccess,2, },
{"close", Xclose,1, },
{"chmod", Xchmod,2, },
{"dup", Xdup,1, },
{"exec", Xexec,-1, },
{"exit", Xexit,1, },
{"fork", Xfork,0, },
{"getpid", Xgetpid,1, },
{"ioctl", Xioctl,3, },
{"kill", Xkill,2, },
{"open", Xopen,2, },
{"wait", Xwait,1, },
{"unlink", Xunlink,1, },
{"printf", Xprintf,-1, },
{"telinit", Xtelinit,1, },
{ (char *) 0, },
};
icmd(argc,argv,flagp)
char **argv;
int *flagp;
{
struct ix *ixp;
int r;
for( ixp = ix; ixp->cmdname; ixp++ )
if( xcmp(ixp->cmdname,argv[0]) == 0 )
{
*flagp = ICMD;
r = (*ixp->func)(argc,argv);
if( ixp->return_rv )
return r;
else
return SUCCESS;
}
*flagp = XCMD;
return FAILURE;
}
#define MODULE(X) X(argc,argv)\
int argc;\
char **argv;
#define EMOD(X) X(){fprintf(fp1,"Not implemented\n"); fflush(fp1);}
MODULE(Xprintf)
{
int arg2;
arg2 = atoh(argv[2]);
/* sscanf(argv[2],"%x",&arg2); */
fprintf(fp1,argv[1],arg2);
}
#define FMT_STRING "%.8x: %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %s\n"
MODULE(Xaccess)
{
int amode;
amode = atoi(argv[2]);
Xrv = access(argv[1],amode);
logx("access(%s,%d) = %d", argv[1], amode, Xrv);
}
MODULE(Xchmod)
{
int mode;
mode = atoo(argv[2]);
Xrv = chmod(argv[1],mode);
logx("chmod(%s,0%o) = %d", argv[1], mode, Xrv);
}
MODULE(Xclose)
{
int fd;
fd = atoi(argv[1]);
if( (fd == 0 || fd == 1 || fd == 2) && lineo == 0 )
{
fprintf(fp2,"Can't close that\n");
return 1;
}
Xrv = close(fd);
logx("close(%d) = %d", fd, Xrv);
}
MODULE(Xdup)
{
int fd;
fd = atoi(argv[1]);
Xrv = dup(fd);
logx("dup(%d) = %d", fd, Xrv);
}
MODULE(Xexec)
{
Xrv = execve(argv[1],argv+1,env);
logx("execve(%s,...) = %d\n", argv[1], Xrv);
}
MODULE(Xexit)
{
int ev;
ev = atoi(argv[1]);
exit(ev);
}
EMOD(Xfork)
MODULE(Xgetpid)
{
Xrv = getpid();
logx("getpid() = %d", Xrv);
}
EMOD(Xioctl)
MODULE(Xkill)
{
int pid, signo;
pid = atoi(argv[1]);
signo = atoi(argv[2]);
Xrv = kill(pid,signo);
logx("kill(%d,%d) = %d", pid, signo, Xrv);
}
MODULE(Xopen)
{
int mode;
mode = atoi(argv[2]);
Xrv = open(argv[1],mode);
logx("open(%s,%d) = %d", argv[1], mode, Xrv);
}
MODULE(Xunlink)
{
int fd;
char *buff;
struct stat sbuf;
if (stat(argv[1], &sbuf))
{
return 2;
}
fd = open(argv[1], O_RDWR|O_EXCL, 0);
if (fd == -1)
{
return 3;
}
buff = shmat(fd, 0, SHM_MAP);
assert((int)buff != -1);
bzero(buff, sbuf.st_size);
fsync(fd);
close(fd);
Xrv = unlink(argv[1]);
logx("unlink(%s) = %d", argv[1], Xrv);
}
MODULE(Xtelinit)
{
int Xrv;
struct var newv;
char c;
Xrv = sysconfig(SYS_GETPARMS, &newv, sizeof(struct var));
c = argv[1][0];
if( c == 's' || c == 'S' || c == 'm' || c == 'M' ) {
strncpy(&newv.v_initlvl,argv[1], 4);
}
else {
strcpy(&newv.v_initlvl,"");
}
Xrv = sysconfig(SYS_SETPARMS, &newv, sizeof(struct var));
logx("telinit(%s) = %d", argv[1],Xrv);
}
EMOD(Xwait)
/* AIX 2.2.1 or 3.x specific */
logx(fmt,arg1,arg2,arg3,arg4,arg5)
{
Xerrno = errno;
fprintf(fp1,fmt,arg1,arg2,arg3,arg4,arg5);
if( Xerrno )
fprintf(fp1,", errno = %d\n", Xerrno);
else
fprintf(fp1,"\n");
errno = 0;
}
/*
* Execute the BRC if it exists. If it executes
* successfully, then exit. This will hopefully
* cause the system to be restarted.
*/
brc(pgm,fp)
char *pgm;
FILE *fp;
{
int rc;
fprintf(fp,"\nINIT: EXECUTING %s\n", pgm);
if( execute(pgm) == 0 )
{
fprintf(fp, "\nINIT: EXITING\n");
/* terminate all process */
kill(-1,9);
/* pick up those zombies */
while( wait(&rc) != -1 && errno != ECHILD )
;
exit(0);
}
}
execute(pgm)
char *pgm;
{
int pid, wstat;
FILE *fp;
switch( pid = fork() )
{
case -1:
wstat = errno;
break;
case 0:
if (init) {
/* terminal driver sends signals generated from
the keyboard to the foreground process group.
A child process that opens its terminal should
ensure the terminal driver sends no signals
to the init process. setsid() puts the child
in its own process group. */
setsid(); /* become session and process group leader */
fp = coninit(CONSOLE);
}
execl(SHELL,"sh","-c",pgm,0);
for(;;)
_exit(errno); /* EAGAIN? */
default:
while(wait(&wstat) != pid)
;
break;
}
return wstat;
}
/*
* This zero filled FILE struct will cause fprintf to fail
* w/o error. This is used when coninit can't open the
* requested device, usually due to a device error.
*/
FILE nofile;
FILE *
coninit(dev)
char *dev;
{
int rc;
FILE *fp;
close(0); close(1); close(2); errno = 0;
if( open(dev,O_RDWR) != 0 ) /* stdin */
return &nofile;
if( dup(0) != 1 ) /* stdout */
{
close(0);
return &nofile;
}
if( dup(0) != 2 ) /* stderr */
{
close(0);
close(1);
return &nofile;
}
if( (fp = fdopen(1,"r+")) == NULL )
{
close(0);
close(1);
close(2);
return &nofile;
}
return fp;
}