home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The World of Computer Software
/
World_Of_Computer_Software-02-385-Vol-1of3.iso
/
c
/
condor40.zip
/
CONDOR
/
src
/
condor_starter
/
starter.c
< prev
next >
Wrap
C/C++ Source or Header
|
1989-09-18
|
19KB
|
835 lines
/*
** Copyright 1986, 1987, 1988, 1989 University of Wisconsin
**
** Permission to use, copy, modify, and distribute this software and its
** documentation for any purpose and without fee is hereby granted,
** provided that the above copyright notice appear in all copies and that
** both that copyright notice and this permission notice appear in
** supporting documentation, and that the name of the University of
** Wisconsin not be used in advertising or publicity pertaining to
** distribution of the software without specific, written prior
** permission. The University of Wisconsin makes no representations about
** the suitability of this software for any purpose. It is provided "as
** is" without express or implied warranty.
**
** THE UNIVERSITY OF WISCONSIN DISCLAIMS ALL WARRANTIES WITH REGARD TO
** THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
** FITNESS. IN NO EVENT SHALL THE UNIVERSITY OF WISCONSIN BE LIABLE FOR
** ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
** WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
** ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
** OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
**
** Authors: Allan Bricker and Michael J. Litzkow,
** University of Wisconsin, Computer Sciences Dept.
**
*/
#include <stdio.h>
#include <pwd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/file.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/param.h>
#include <rpc/types.h>
#include <rpc/xdr.h>
#include <errno.h>
#include <a.out.h>
#include "debug.h"
#include "except.h"
#include "proc.h"
#include "trace.h"
#include "xdr_lib.h"
#include "condor_sys.h"
#include "fileno.h"
#include "expr.h"
#ifdef DAYAO
#include "ctrace.h"
#endif DAYAO
static char *_FileName_ = __FILE__; /* Used by EXCEPT (see except.h) */
char *param();
#define MINUTE 60
#define HOUR (MINUTE * 60)
extern int errno;
int CondorGid, CondorUid;
char *Execute;
int MinCkptInterval;
int MaxCkptInterval;
int CkptInterval;
int ChildPid;
char Shortname[ MAXPATHLEN ];
char CkptTmpName[ MAXPATHLEN ];
char *CoreName = "core";
char *CkptName = NULL;
char *Stdin = NULL;
char *Stdout = NULL;
char *Stderr = NULL;
char *RootDir = NULL;
char *CmdName = NULL;
char *Args = NULL;
char *JobArgs[ MAXPATHLEN / 2 ];
int Cluster, Proc;
int Suspended;
int CkptCreated;
int JobExited;
int Aborted;
struct rusage AccumRusage;
int vacate_order(), checkpoint_order(), suspend_order(), resume_order();
int Cleanup(), die(), abort();
main( argc, argv )
int argc;
char *argv[];
{
int i, nfds;
union wait status;
struct rusage rusage;
XDR *xdrs, *RSC_Init();
(void) SetSyscalls( SYS_LOCAL | SYS_UNRECORDED );
setlinebuf( stderr );
DebugFlags |= D_ALWAYS | D_NOHEADER;
/*
DebugFlags |= D_CKPT;
*/
dprintf( D_ALWAYS, "********** STARTER starting up ***********\n" );
config( argv[0], (CONTEXT *)0 );
/*
dprintf_config( "STARTER", CLIENT_LOG );
*/
get_condor_uid();
_EXCEPT_Cleanup = Cleanup;
if( argc != 2 )
usage();
init_params();
set_sigs();
(void)sigsetmask( 0 );
if( chdir(Execute) ) {
EXCEPT( "chdir(%s)", Execute );
}
if( chroot(Execute) < 0 ) {
EXCEPT( "chroot(%s)", Execute );
}
if( setregid(CondorGid,CondorGid) < 0 ) {
EXCEPT( "setregid(%d, %d)", CondorGid, CondorGid );
}
if( setreuid(CondorUid,CondorUid) < 0 ) {
EXCEPT( "sereuid(%d, %d)", CondorUid, CondorUid );
}
(void)dup2( 1, RSC_SOCK );
(void)dup2( 2, CLIENT_LOG );
stderr->_file = CLIENT_LOG;
xdrs = RSC_Init( RSC_SOCK, CLIENT_LOG );
xdrrec_skiprecord(xdrs);
GetFileNames( xdrs );
nfds = getdtablesize();
for( i=0; i<nfds; i++ ) {
if( i==RSC_SOCK || i==CLIENT_LOG ) continue;
(void)close( i );
}
GetJobFile( xdrs );
if( magic_check(Shortname) < 0 ) {
bzero( (char *)&AccumRusage, sizeof(AccumRusage) );
status.w_termsig = 0; /* no sig, but a coredump -- can only */
status.w_coredump = 1; /* be if we set it on purpose */
status.w_retcode = ENOEXEC; /* now say why we didn't run the job */
(void)REMOTE_syscall( PSEUDO_reallyexit, &status, &AccumRusage);
Cleanup();
exit( 0 );
}
CkptInterval = MinCkptInterval;
/* I don't think this is needed -- mike
if( Suspended ) {
sigpause( ~(sigmask(SIGCONT) | sigmask(SIGTSTP)) );
}
*/
for(;;) {
(void)sigsetmask( ~0 );
if( (ChildPid = vfork()) < 0 ) {
EXCEPT( "vfork" );
}
if( ChildPid ) { /* The parent */
(void)sigsetmask( 0 );
(void)alarm( (unsigned)CkptInterval );
dprintf( D_ALWAYS, "Set alarm for %d seconds\n", CkptInterval );
WaitForChild(&status, &rusage);
(void)alarm( (unsigned) 0 );
update_rusage( &AccumRusage, &rusage );
dprintf( D_FULLDEBUG, "Accumulated Rusage\n" );
dprintf( D_FULLDEBUG, "ru_utime = %d.%06d\n",
AccumRusage.ru_utime.tv_sec, AccumRusage.ru_utime.tv_usec );
dprintf( D_FULLDEBUG, "ru_stime = %d.%06d\n",
AccumRusage.ru_stime.tv_sec, AccumRusage.ru_stime.tv_usec );
if( Aborted && CkptCreated ) {
SendCkptFile( Shortname, CkptName );
status.w_termsig = SIGQUIT;
}
if( JobExited || Aborted ) {
dprintf(D_FULLDEBUG, "Cleaning up now.\n");
Cleanup();
dprintf( D_FULLDEBUG, "Accumulated Rusage After Cleanup\n" );
dprintf( D_FULLDEBUG, "ru_utime = %d.%06d\n",
AccumRusage.ru_utime.tv_sec, AccumRusage.ru_utime.tv_usec );
dprintf( D_FULLDEBUG, "ru_stime = %d.%06d\n",
AccumRusage.ru_stime.tv_sec, AccumRusage.ru_stime.tv_usec );
dprintf( D_ALWAYS, "********** STARTER exiting ***********\n" );
/*
** Make sure that the log socket is read before the
** syscall socket.
sleep( 1 );
*/
(void)REMOTE_syscall( PSEUDO_reallyexit, &status, &AccumRusage);
exit( 0 );
}
CkptInterval = MIN( 2 * CkptInterval, MaxCkptInterval );
} else { /* The child */
dprintf( D_ALWAYS, "Starter: Doing execv( %s, 0x%x )\n",
Shortname, JobArgs );
(void)execv( Shortname, JobArgs );
EXCEPT( "execv(%s)", Shortname );
}
}
}
WaitForChild(statp, rusagep)
union wait *statp;
struct rusage *rusagep;
{
int pid;
int scm;
dprintf( D_FULLDEBUG, "Starter: waiting for \"%s\" (pid %d) to die\n",
Shortname, ChildPid );
while( (pid=wait3(statp, 0, rusagep)) < 0 ) {
if( errno != EINTR ) {
EXCEPT( "wait3" );
}
}
if( pid != ChildPid ) {
EXCEPT("wait3 returned pid %d (not %d)\n", pid, ChildPid );
}
ChildPid = 0;
dprintf(D_ALWAYS,
"Pid %d exited, termsig = %d, coredump = %d, retcode = %d\n",
pid, statp->w_termsig,
statp->w_coredump, statp->w_retcode
);
dprintf( D_FULLDEBUG, "ru_utime = %d.%06d\n",
rusagep->ru_utime.tv_sec, rusagep->ru_utime.tv_usec );
dprintf( D_FULLDEBUG, "ru_stime = %d.%06d\n",
rusagep->ru_stime.tv_sec, rusagep->ru_stime.tv_usec );
switch( statp->w_termsig ) {
case 0: /* Normal Exit */
JobExited = TRUE;
break;
case SIGKILL: /* Kicked Off */
bzero( (char *)rusagep, sizeof(struct rusage) );
JobExited = TRUE;
Aborted = TRUE;
#ifdef DAYAO
scm = SetSyscalls( SYS_REMOTE | SYS_UNRECORDED );
if( ProcessLogging(CATCH_SIGKILL,0) < 0 ) {
EXCEPT( "ProcessLogging(CATCH_SIGKILL,0)" );
}
(void)SetSyscalls( scm );
#endif DAYAO
break;
case SIGQUIT: /* Periodic checkpoint */
/* I don't think this is needed -- mike
if( Suspended ) {
sigpause( ~(sigmask(SIGCONT) | sigmask(SIGTSTP)) );
}
*/
if( !Aborted ) {
do_ckpt();
}
break;
default: /* Abnormal Exit */
if( statp->w_coredump ) {
SendBackCore();
}
JobExited = TRUE;
break;
}
}
do_ckpt()
{
#if defined(vax) || defined(i386) || defined(mc68020) || defined(sparc)
/*
** Checkpointing is only possible on the defined systems.
** If this isn't one of them, we'll just restart the job from the
** initial checkpoint and hopefully it will be able to complete.
*/
(void)sprintf(CkptTmpName, "%s.tmp", Shortname);
dprintf(D_ALWAYS, "Starter: About to _updateckpt(%s, %s, %s)\n",
CkptTmpName, Shortname, CoreName );
_updateckpt( CkptTmpName, Shortname, CoreName );
(void)unlink( Shortname );
(void)unlink( CoreName );
(void)rename( CkptTmpName, Shortname );
CkptCreated = 1;
#endif defined(vax) || defined(i386) || defined(mc68020) || defined(sparc)
}
SendBackCore()
{
char core_name[ MAXPATHLEN ];
(void)sprintf( core_name, "core.%d.%d", Cluster, Proc );
dprintf(D_CKPT, "Sending back core file to \"%s\".\n", core_name);
SendBackFile( "core", core_name );
}
Cleanup()
{
(void) SetSyscalls( SYS_LOCAL | SYS_UNRECORDED );
(void)sigsetmask( ~0 );
if( ChildPid ) {
(void)kill(ChildPid, SIGKILL);
}
(void)unlink( CoreName );
if( Shortname[0] != 0 ) {
(void)unlink( Shortname );
}
if( CkptTmpName && CkptTmpName[0] ) {
(void)unlink( CkptTmpName );
}
}
usage()
{
dprintf( D_ALWAYS, "Usage: starter init_machine\n" );
exit( 1 );
}
/*
** Get the Condor job off the machine asap.
*/
vacate_order()
{
union wait fake_status;
dprintf(D_ALWAYS, "Got SIGINT, killed by the startd.\n" );
Aborted = TRUE;
if( ChildPid ) {
(void)kill(ChildPid, SIGKILL);
dprintf( D_ALWAYS, "Sent SIGKILL to user job\n" );
} else {
if( CkptCreated ) {
SendCkptFile( Shortname, CkptName );
fake_status.w_termsig = SIGQUIT; /* Kicked off with ckpt */
} else {
fake_status.w_termsig = SIGKILL; /* Kicked off without ckpt */
}
(void)REMOTE_syscall( PSEUDO_reallyexit, &fake_status, &AccumRusage);
dprintf( D_ALWAYS, "No user job running\n" );
dprintf(D_FULLDEBUG, "Cleaning up now.\n");
Cleanup();
exit( 1 );
}
}
die()
{
Cleanup();
exit( 1 );
}
/*
** Send the Condor job an order to do a checkpoint.
*/
checkpoint_order()
{
if( ChildPid == 0 ) {
dprintf(D_FULLDEBUG, "Cleaning up now.\n");
Cleanup();
} else {
(void)kill(ChildPid, SIGCONT);
(void)kill(ChildPid, SIGTSTP);
dprintf( D_ALWAYS, "Got SIGALRM, sent SIGCONT & SIGTSTP to user job\n");
}
}
int SavedAlarm;
/*
** Suspend the Condor job.
*/
suspend_order()
{
if( ChildPid != 0 ) {
(void)kill(ChildPid, SIGSTOP);
dprintf( D_ALWAYS, "Got SIGUSR1, sent SIGSTOP to user job\n" );
}
SavedAlarm = alarm( 0 );
dprintf( D_ALWAYS, "Stopped alarm clock, %d seconds remaining\n",
SavedAlarm );
Suspended = TRUE;
/* Try this for now, see how it works out */
sigpause( sigmask(SIGUSR1) );
}
/*
** Resume running the Condor job.
*/
resume_order()
{
if( ChildPid != 0 ) {
(void)kill(ChildPid, SIGCONT);
dprintf( D_ALWAYS, "Got SIGCONT, sent SIGCONT to user job\n" );
}
(void)alarm( (unsigned)SavedAlarm );
dprintf( D_ALWAYS, "Reset alarm clock, %d seconds remaining\n",
SavedAlarm );
Suspended = FALSE;
}
GetFileNames( xdrs )
XDR *xdrs;
{
PROC proc;
bzero( (char *)&proc, sizeof(PROC) );
xdrs->x_op = XDR_DECODE;
ASSERT(xdr_proc(xdrs, &proc));
ASSERT( xdr_string(xdrs,&CkptName,MAXPATHLEN) );
Cluster = proc.id.cluster;
Proc = proc.id.proc;
CmdName = proc.cmd;
Stdin = proc.in;
Stdout = proc.out;
Stderr = proc.err;
Args = proc.args;
RootDir = proc.rootdir;
dprintf( D_PROC, "Cluster = %d\n", Cluster );
dprintf( D_PROC, "Proc = %d\n", Proc );
dprintf( D_PROC, "CkptName = \"%s\"\n", CkptName );
dprintf( D_PROC, "Stdin = \"%s\"\n", Stdin );
dprintf( D_PROC, "Stdout = \"%s\"\n", Stdout );
dprintf( D_PROC, "Stderr = \"%s\"\n", Stderr );
dprintf( D_PROC, "RootDir = \"%s\"\n", RootDir );
dprintf( D_PROC, "CmdName = \"%s\"\n", CmdName );
dprintf( D_PROC, "Args = \"%s\"\n", Args );
(void)sprintf( Shortname, "condor_exec%06d.%d", Cluster, Proc );
}
GetJobFile( xdrs )
XDR *xdrs;
{
int len;
int got, written;
int fd;
char buf[XDR_BLOCKSIZ];
int argc;
/* Copy in the file */
if( (fd=open(Shortname,O_WRONLY | O_CREAT,0775)) < 0 ) {
EXCEPT( "open of \"%s\"", Shortname );
}
dprintf( D_FULLDEBUG, "Opened file \"%s\"\n", Shortname );
ASSERT( xdr_int(xdrs,&len) );
while( len ) {
got = len < XDR_BLOCKSIZ ? len : XDR_BLOCKSIZ;
errno = 0;
ASSERT( xdr_opaque(xdrs, buf, got) );
if( (written=write(fd,buf,got)) != got ) {
EXCEPT( "write" );
}
len -= written;
}
(void)close( fd );
dprintf( D_FULLDEBUG, "Closed \"%s\"\n", Shortname );
mkargv( &argc, &JobArgs[1], Args );
JobArgs[0] = Shortname;
}
get_condor_uid()
{
struct passwd *pwd;
if( (pwd=getpwnam("condor")) == NULL ) {
EXCEPT( "Can't find passwd entry for condor" );
}
CondorUid = pwd->pw_uid;
CondorGid = pwd->pw_gid;
}
SendCkptFile( local_name, remote_name )
char *local_name;
char *remote_name;
{
char tmp_name[ MAXPATHLEN ];
(void)sprintf( tmp_name, "%s.tmp", remote_name );
dprintf( D_FULLDEBUG, "SendCkptFile() called\n" );
dprintf( D_FULLDEBUG, "local_name = \"%s\"\n", local_name );
dprintf( D_FULLDEBUG, "remote_name = \"%s\"\n", remote_name );
dprintf( D_FULLDEBUG, "tmp_name = \"%s\"\n", tmp_name );
SendBackFile( local_name, tmp_name );
(void) SetSyscalls( SYS_REMOTE | SYS_UNRECORDED );
if( rename(tmp_name,remote_name) < 0 ) {
EXCEPT( "remote_rename(%s,%s)", tmp_name, remote_name );
}
(void) SetSyscalls( SYS_LOCAL | SYS_UNRECORDED );
dprintf( D_ALWAYS, "Returned latest checkpoint\n" );
}
/*
** Send a file to the initiating machine using the remote system call
** mechanism.
*/
SendBackFile( local_name, remote_name )
char *local_name;
char *remote_name;
{
int ifd, ofd;
int got, sent;
char buf[ 16 * 1024 ];
int scm, len;
scm = SetSyscalls( SYS_LOCAL | SYS_UNRECORDED );
if( (ifd=open(local_name,O_RDONLY)) < 0 ) {
EXCEPT( "open(%s,O_RDONLY)", local_name );
}
(void) SetSyscalls( SYS_REMOTE | SYS_UNRECORDED );
#ifdef DAYAO
if( ProcessLogging(START_LOGGING,0) < 0 ) {
EXCEPT( "ProcessLogging(START_LOGGING,0) (pseudo call)" );
}
#endif DAYAO
if( (ofd=open(remote_name,O_WRONLY|O_CREAT,0664)) < 0 ) {
EXCEPT( "remote_open(%s,O_WRONLY|O_CREAT,0664)", remote_name );
}
#ifdef DAYAO
for(len=0;;len+=sent) {
#else
for(;;) {
#endif DAYAO
(void) SetSyscalls( SYS_LOCAL | SYS_UNRECORDED );
if( (got = read( ifd, buf, sizeof(buf) )) < 0 ) {
EXCEPT( "read(%d,0x%x,%d)", ifd, buf, sizeof(buf) );
}
if( got == 0 ) {
break;
}
(void) SetSyscalls( SYS_REMOTE | SYS_UNRECORDED );
if( (sent = write( ofd, buf, got )) != got ) {
EXCEPT( "remote_write(%d,0x%x,%d) returns %d", ofd, buf, got, sent);
}
}
(void) SetSyscalls( SYS_REMOTE | SYS_UNRECORDED );
if( close(ofd) < 0 ) {
EXCEPT( "remote_close(%d)", ofd );
}
#ifdef DAYAO
if( ProcessLogging(COMPLETE_LOGGING,len) < 0 ) {
EXCEPT( "ProcessLogging(COMPLETE_LOGGING,0) (pseudo call)" );
}
#endif DAYAO
(void) SetSyscalls( SYS_LOCAL | SYS_UNRECORDED );
if( close(ifd) < 0 ) {
EXCEPT( "close(%d)", ifd );
}
(void) SetSyscalls( scm );
}
update_rusage( ru1, ru2 )
register struct rusage *ru1, *ru2;
{
ru1->ru_utime.tv_usec += ru2->ru_utime.tv_usec;
if( ru1->ru_utime.tv_usec >= 1000000 ) {
ru1->ru_utime.tv_usec -= 1000000;
ru1->ru_utime.tv_sec += 1;
}
ru1->ru_utime.tv_sec += ru2->ru_utime.tv_sec;
ru1->ru_stime.tv_usec += ru2->ru_stime.tv_usec;
if( ru1->ru_stime.tv_usec >= 1000000 ) {
ru1->ru_stime.tv_usec -= 1000000;
ru1->ru_stime.tv_sec += 1;
}
ru1->ru_stime.tv_sec += ru2->ru_stime.tv_sec;
if( ru2->ru_maxrss > ru1->ru_maxrss ) {
ru1->ru_maxrss = ru2->ru_maxrss;
}
if( ru2->ru_ixrss > ru1->ru_ixrss ) {
ru1->ru_ixrss = ru2->ru_ixrss;
}
if( ru2->ru_idrss > ru1->ru_idrss ) {
ru1->ru_idrss = ru2->ru_idrss;
}
if( ru2->ru_isrss > ru1->ru_isrss ) {
ru1->ru_isrss = ru2->ru_isrss;
}
ru1->ru_minflt += ru2->ru_minflt;
ru1->ru_majflt += ru2->ru_majflt;
ru1->ru_nswap += ru2->ru_nswap;
ru1->ru_inblock += ru2->ru_inblock;
ru1->ru_oublock += ru2->ru_oublock;
ru1->ru_msgsnd += ru2->ru_msgsnd;
ru1->ru_msgrcv += ru2->ru_msgrcv;
ru1->ru_nsignals += ru2->ru_nsignals;
ru1->ru_nvcsw += ru2->ru_nvcsw;
ru1->ru_nivcsw += ru2->ru_nivcsw;
}
init_params()
{
char *tmp;
if( (Execute=param("EXECUTE")) == NULL ) {
EXCEPT( "Execute directory not specified in config file" );
}
if( (tmp=param("MIN_CKPT_INTERVAL")) == NULL ) {
MinCkptInterval = 15 * MINUTE;
} else {
MinCkptInterval = atoi( tmp );
}
if( (tmp=param("MAX_CKPT_INTERVAL")) == NULL ) {
MaxCkptInterval = 2 * HOUR;
} else {
MaxCkptInterval = atoi( tmp );
}
if( MaxCkptInterval > 2 * HOUR ) {
MaxCkptInterval = 2 * HOUR;
}
if( MaxCkptInterval < 15 * MINUTE ) {
MaxCkptInterval = 15 * MINUTE;
}
if( MinCkptInterval < 15 * MINUTE ) {
MinCkptInterval = 15 * MINUTE;
}
if( MinCkptInterval > MaxCkptInterval ) {
MinCkptInterval = MaxCkptInterval;
}
}
#define SETSIG(s,f) \
if( signal(s, f) < 0 ) { \
EXCEPT( "Can't set signal %d to 0x%x", s, f ); \
}
set_sigs()
{
int i;
for( i=1; i<NSIG; i++ ) {
switch( i ) {
case SIGKILL:
case SIGSTOP:
break;
case SIGINT:
SETSIG( i, die );
break;
case SIGQUIT:
SETSIG( i, abort );
break;
case SIGTSTP:
SETSIG( i, vacate_order );
break;
case SIGUSR1:
SETSIG( i, suspend_order );
break;
case SIGCONT:
SETSIG( i, resume_order );
break;
case SIGALRM:
SETSIG( i, checkpoint_order );
break;
case SIGCHLD:
SETSIG( i, SIG_IGN );
break;
default:
SETSIG( i, die );
}
}
}
abort()
{
char wd[1024];
getwd( wd );
Cleanup();
SETSIG( SIGILL, SIG_DFL );
dprintf( D_ALWAYS, "Got abort signal, CWD = \"%s\"\n", wd );
kill( getpid(), SIGILL );
sigpause( 0 );
}
/*
** Check the header of the file we are about to exec. Make sure everything
** is reasonable.
*/
#ifdef MIPS
magic_check( name )
char *name;
{
return( 0 );
}
#else MIPS
magic_check( name )
char *name;
{
int fd;
struct exec exec;
int scm;
scm = SetSyscalls( SYS_LOCAL | SYS_UNRECORDED );
if( (fd=open(name,O_RDONLY,0)) < 0 ) {
EXCEPT( "open(%s,O_RDONLY,0)", name );
}
if( read(fd,(char *)&exec,sizeof(struct exec)) != sizeof(struct exec) ) {
EXCEPT( "read(%d,0x%x,%d)", fd, &exec, sizeof(struct exec) );
}
(void)close( fd );
(void)SetSyscalls( scm );
#ifdef vax
if( exec.a_magic != ZMAGIC ) {
dprintf( D_ALWAYS, "\"%s\": BAD MAGIC NUMBER\n", name );
return -1;
}
#endif
#ifdef sequent
if( exec.a_magic != ZMAGIC ) {
dprintf( D_ALWAYS, "\"%s\": BAD MAGIC NUMBER\n", name );
return -1;
}
#endif sequent
#ifdef sparc
if( exec.a_magic != ZMAGIC ) {
dprintf( D_ALWAYS, "\"%s\": BAD MAGIC NUMBER\n", name );
return -1;
}
if( exec.a_machtype != M_SPARC ) {
dprintf( D_ALWAYS, "\"%s\": NOT COMPILED FOR SPARC ARCHITECTURE\n",
name );
return -1;
}
if( exec.a_dynamic ) {
dprintf( D_ALWAYS, "\"%s\": LINKED FOR DYNAMIC LOADING\n", name );
return -1;
}
#endif
#ifdef mc68020
if( exec.a_magic != ZMAGIC ) {
dprintf( D_ALWAYS, "\"%s\": BAD MAGIC NUMBER\n", name );
return -1;
}
if( exec.a_machtype != M_68020 ) {
dprintf( D_ALWAYS, "\"%s\": NOT COMPILED FOR MC68020 ARCHITECTURE\n",
name );
return -1;
}
#endif
return 0;
}
#endif MIPS