--- /dev/null
+/*
+ * $Id: a2boot.c,v 1.1 2003-01-11 17:26:06 jmarcus Exp $
+ * Apple II boot support code. with aid of Steven N. Hirsch
+ *
+ * based on timelord 1.6 so below copyrights still apply
+ *
+ * Copyright (c) 1990,1992 Regents of The University of Michigan.
+ * All Rights Reserved. See COPYRIGHT.
+ *
+ * The "timelord protocol" was reverse engineered from Timelord,
+ * distributed with CAP, Copyright (c) 1990, The University of
+ * Melbourne. The following copyright, supplied by The University
+ * of Melbourne, may apply to this code:
+ *
+ * This version of timelord.c is based on code distributed
+ * by the University of Melbourne as part of the CAP package.
+ *
+ * The tardis/Timelord package for Macintosh/CAP is
+ * Copyright (c) 1990, The University of Melbourne.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/file.h>
+#include <sys/uio.h>
+
+#include <unistd.h>
+
+#include <netatalk/at.h>
+#include <netatalk/endian.h>
+#include <atalk/atp.h>
+#include <atalk/nbp.h>
+
+#ifdef HAVE_SGTTY_H
+#include <sgtty.h>
+#endif /* HAVE_SGTTY_H */
+
+#include <errno.h>
+#include <signal.h>
+#include <atalk/logger.h>
+#include <stdio.h>
+#include <string.h>
+
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif /* HAVE_NETDB_H */
+
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif /* HAVE_FCNTL_H */
+#ifdef HAVE_SYS_FCNTL_H
+#include <sys/fcntl.h>
+#endif /* HAVE_SYS_FCNTL_H */
+
+#ifdef HAVE_TERMIOS_H
+#include <termios.h>
+#endif /* HAVE_TERMIOS_H */
+#ifdef HAVE_SYS_TERMIOS_H
+#include <sys/termios.h>
+#endif /* HAVE_SYS_TERMIOS_H */
+
+#define TL_OK '\0'
+#define TL_EOF '\1'
+
+int debug = 0;
+char *bad = "Bad request!";
+char buf[ 4624 ];
+char *server;
+int reqblklo,reqblkhi;
+
+long a2bootreq(char *fname);
+
+void usage( char *p )
+{
+ char *s;
+
+ if (( s = rindex( p, '/' )) == NULL ) {
+ s = p;
+ } else {
+ s++;
+ }
+ fprintf( stderr, "Usage:\t%s -d -n nbpname\n", s );
+ exit( 1 );
+}
+
+/*
+ * Unregister ourself on signal.
+ */
+void
+goaway(int signal)
+{
+ int regerr;
+ regerr = nbp_unrgstr( server, "Apple //gs", "*", NULL );
+ regerr += nbp_unrgstr( server, "Apple //e Boot", "*", NULL );
+ regerr += nbp_unrgstr( server, "ProDOS16 Image", "*", NULL );
+ if ( regerr < 0 ) {
+ LOG(log_error, logtype_default, "Can't unregister Apple II boot files %s", server );
+ exit( 1 );
+ }
+ LOG(log_info, logtype_default, "going down" );
+ exit( 0 );
+}
+
+int main( int ac, char **av )
+{
+ ATP atp;
+ struct sockaddr_at sat;
+ struct atp_block atpb;
+ struct iovec iov;
+ char hostname[ MAXHOSTNAMELEN ];
+ char *p;
+ int c;
+ long req, resp;
+ int regerr;
+ extern char *optarg;
+ extern int optind;
+
+
+ if ( gethostname( hostname, sizeof( hostname )) < 0 ) {
+ perror( "gethostname" );
+ exit( 1 );
+ }
+ if (( server = index( hostname, '.' )) != 0 ) {
+ *server = '\0';
+ }
+ server = hostname;
+
+ while (( c = getopt( ac, av, "dn:" )) != EOF ) {
+ switch ( c ) {
+ case 'd' :
+ debug++;
+ break;
+ case 'n' :
+ server = optarg;
+ break;
+ default :
+ fprintf( stderr, "Unknown option -- '%c'\n", c );
+ usage( *av );
+ }
+ }
+
+ /*
+ * Disassociate from controlling tty.
+ */
+ if ( !debug ) {
+ int i, dt;
+
+ switch ( fork()) {
+ case 0 :
+ dt = getdtablesize();
+ for ( i = 0; i < dt; i++ ) {
+ (void)close( i );
+ }
+ if (( i = open( "/dev/tty", O_RDWR )) >= 0 ) {
+ (void)ioctl( i, TIOCNOTTY, 0 );
+ setpgid( 0, getpid());
+ (void)close( i );
+ }
+ break;
+ case -1 :
+ perror( "fork" );
+ exit( 1 );
+ default :
+ exit( 0 );
+ }
+ }
+
+ if (( p = rindex( *av, '/' )) == NULL ) {
+ p = *av;
+ } else {
+ p++;
+ }
+
+#ifdef ultrix
+ openlog( p, LOG_PID );
+#else /* ultrix */
+ set_processname(p);
+ syslog_setup(log_debug, logtype_default, logoption_ndelay|logoption_pid, logfacility_daemon );
+#endif /* ultrix */
+
+ /* allocate memory */
+ memset (&sat.sat_addr, 0, sizeof (sat.sat_addr));
+
+/*
+ force port 3 as the semi-official ATP access port MJ 2002
+*/
+ if (( atp = atp_open( (u_int8_t)3, &sat.sat_addr )) == NULL ) {
+ LOG(log_error, logtype_default, "main: atp_open: %s", strerror( errno ) );
+ exit( 1 );
+ }
+
+ regerr = nbp_rgstr( atp_sockaddr( atp ), server, "Apple //gs", "*" );
+ regerr += nbp_rgstr( atp_sockaddr( atp ), server, "Apple //e Boot", "*" );
+ regerr += nbp_rgstr( atp_sockaddr( atp ), server, "ProDOS16 Image", "*" );
+ if ( regerr < 0 ) {
+ LOG(log_error, logtype_default, "Can't register Apple II boot files %s", server );
+ exit( 1 );
+ }
+
+ LOG(log_info, logtype_default, "%s:Apple 2 Boot started", server );
+
+ signal(SIGHUP, goaway);
+ signal(SIGTERM, goaway);
+
+ for (;;) {
+ /*
+ * Something seriously wrong with atp, since these assigns must
+ * be in the loop...
+ */
+ atpb.atp_saddr = &sat;
+ atpb.atp_rreqdata = buf;
+ bzero( &sat, sizeof( struct sockaddr_at ));
+ atpb.atp_rreqdlen = sizeof( buf );
+
+ if ( atp_rreq( atp, &atpb ) < 0 ) {
+ LOG(log_error, logtype_default, "main: atp_rreq: %s", strerror( errno ) );
+ exit( 1 );
+ }
+
+ p = buf;
+ bcopy( p, &req, sizeof( long ));
+ req = ntohl( req );
+ p += sizeof( long );
+
+/*
+ LOG(log_info, logtype_default, "req = %08lx",(long)req );
+*/
+
+ reqblklo = (int)(( req & 0x00FF0000 ) >> 7); /* ie block 1 >> to 0x0200, blk 3 >> 0x0600 */
+ reqblkhi = (int)(( req & 0x0000FF00 ) << 9); /* simmilar fake multiply is needed here */
+ req &= 0xFF000000;
+
+/*
+ LOG(log_info, logtype_default, " reqblklo = %02x",(int)reqblklo );
+ LOG(log_info, logtype_default, " reqblkhi = %02x",(int)reqblkhi );
+ LOG(log_info, logtype_default, " req now = %08lx",(long)req );
+*/
+
+ switch( req ) {
+ case 0x01000000 : /* Apple IIgs both ROM 1 and ROM 3 */
+/* LOG(log_info, logtype_default, " Req ProDOS16 Boot Blocks" ); */
+ resp = a2bootreq(_PATH_A_GS_BLOCKS);
+ break;
+
+ case 0x02000000 : /* Apple 2 Workstation card */
+/* LOG(log_info, logtype_default, " Req Apple //e Boot" ); */
+ resp = a2bootreq(_PATH_A_2E_BLOCKS);
+ break;
+
+ case 0x03000000 : /* Apple IIgs both ROM 1 and ROM 3 */
+/* LOG(log_info, logtype_default, " Req ProDOS16 Image" ); */
+ resp = a2bootreq(_PATH_P16_IMAGE);
+ break;
+
+ default :
+ LOG(log_error, logtype_default, bad );
+
+ resp = TL_EOF;
+ *( buf + sizeof( long ) ) = (unsigned char)strlen( bad );
+ strcpy( buf + 1 + sizeof( long ), bad );
+
+ break;
+ }
+
+ bcopy( &resp, buf, sizeof( long ));
+
+ iov.iov_len = sizeof( long ) + 0X200;
+ iov.iov_base = buf;
+ atpb.atp_sresiov = &iov;
+ atpb.atp_sresiovcnt = 1;
+
+ if ( atp_sresp( atp, &atpb ) < 0 ) {
+ LOG(log_error, logtype_default, "main: atp_sresp: %s", strerror( errno ) );
+ exit( 1 );
+ }
+ }
+}
+
+
+/* below MJ 2002 (initially borrowed from aep_packet */
+long a2bootreq(fname)
+ char *fname;
+{
+ int f,m;
+ long readlen;
+ long reqpos;
+/*
+ LOG(log_info, logtype_default, " a2bootreq( %s )",fname );
+*/
+ f=open(fname,O_RDONLY );
+ if(f==EOF) {
+ LOG(log_error, logtype_default, "a2boot open error on %s",fname);
+ return close(f);
+ }
+
+ reqpos = reqblklo + reqblkhi;
+/*
+ LOG(log_info, logtype_default, "would lseek to %08lx",reqpos);
+*/
+ lseek(f,reqpos,0);
+ readlen=read(f, buf + sizeof( long ), 0x200 );
+
+/*
+ LOG(log_info, logtype_default, "length is %08lx", readlen);
+*/
+
+ if(readlen < 0x200) {
+/* LOG(log_info, logtype_default, "Read to EOF"); */
+ close(f);
+ return TL_EOF;
+ }
+ close(f);
+ return TL_OK;
+}
+