1/* 2 * $Id: a2boot.c,v 1.2 2003-01-15 06:24:28 jmarcus Exp $ 3 * Apple II boot support code. with aid of Steven N. Hirsch 4 * 5 * based on timelord 1.6 so below copyrights still apply 6 * 7 * Copyright (c) 1990,1992 Regents of The University of Michigan. 8 * All Rights Reserved. See COPYRIGHT. 9 * 10 * The "timelord protocol" was reverse engineered from Timelord, 11 * distributed with CAP, Copyright (c) 1990, The University of 12 * Melbourne. The following copyright, supplied by The University 13 * of Melbourne, may apply to this code: 14 * 15 * This version of timelord.c is based on code distributed 16 * by the University of Melbourne as part of the CAP package. 17 * 18 * The tardis/Timelord package for Macintosh/CAP is 19 * Copyright (c) 1990, The University of Melbourne. 20 */ 21 22#ifdef HAVE_CONFIG_H 23#include "config.h" 24#endif /* HAVE_CONFIG_H */ 25 26#include <sys/param.h> 27#include <sys/types.h> 28#include <sys/file.h> 29#include <sys/uio.h> 30 31#include <unistd.h> 32 33#include <netatalk/at.h> 34#include <netatalk/endian.h> 35#include <atalk/atp.h> 36#include <atalk/nbp.h> 37 38#ifdef HAVE_SGTTY_H 39#include <sgtty.h> 40#endif /* HAVE_SGTTY_H */ 41 42#include <errno.h> 43#include <signal.h> 44#include <atalk/logger.h> 45#include <stdio.h> 46#include <string.h> 47 48#ifdef HAVE_NETDB_H 49#include <netdb.h> 50#endif /* HAVE_NETDB_H */ 51 52#ifdef HAVE_FCNTL_H 53#include <fcntl.h> 54#endif /* HAVE_FCNTL_H */ 55#ifdef HAVE_SYS_FCNTL_H 56#include <sys/fcntl.h> 57#endif /* HAVE_SYS_FCNTL_H */ 58 59#ifdef HAVE_TERMIOS_H 60#include <termios.h> 61#endif /* HAVE_TERMIOS_H */ 62#ifdef HAVE_SYS_TERMIOS_H 63#include <sys/termios.h> 64#endif /* HAVE_SYS_TERMIOS_H */ 65 66#define TL_OK '\0' 67#define TL_EOF '\1' 68 69int debug = 0; 70char *bad = "Bad request!"; 71char buf[ 4624 ]; 72char *server; 73int32_t fileoff; 74 75long a2bootreq(char *fname); 76 77void usage( char *p ) 78{ 79 char *s; 80 81 if (( s = rindex( p, '/' )) == NULL ) { 82 s = p; 83 } else { 84 s++; 85 } 86 fprintf( stderr, "Usage:\t%s -d -n nbpname\n", s ); 87 exit( 1 ); 88} 89 90/* 91 * Unregister ourself on signal. 92 */ 93void 94goaway(int signal) 95{ 96 int regerr; 97 regerr = nbp_unrgstr( server, "Apple //gs", "*", NULL ); 98 regerr += nbp_unrgstr( server, "Apple //e Boot", "*", NULL ); 99 regerr += nbp_unrgstr( server, "ProDOS16 Image", "*", NULL ); 100 if ( regerr < 0 ) { 101 LOG(log_error, logtype_default, "Can't unregister Apple II boot files %s", server ); 102 exit( 1 ); 103 } 104 LOG(log_info, logtype_default, "going down" ); 105 exit( 0 ); 106} 107 108int main( int ac, char **av ) 109{ 110 ATP atp; 111 struct sockaddr_at sat; 112 struct atp_block atpb; 113 struct iovec iov; 114 char hostname[ MAXHOSTNAMELEN ]; 115 char *p; 116 int c; 117 int32_t req, resp; 118 int regerr; 119 extern char *optarg; 120 extern int optind; 121 122 123 if ( gethostname( hostname, sizeof( hostname )) < 0 ) { 124 perror( "gethostname" ); 125 exit( 1 ); 126 } 127 if (( server = index( hostname, '.' )) != 0 ) { 128 *server = '\0'; 129 } 130 server = hostname; 131 132 while (( c = getopt( ac, av, "dn:" )) != EOF ) { 133 switch ( c ) { 134 case 'd' : 135 debug++; 136 break; 137 case 'n' : 138 server = optarg; 139 break; 140 default : 141 fprintf( stderr, "Unknown option -- '%c'\n", c ); 142 usage( *av ); 143 } 144 } 145 146 /* 147 * Disassociate from controlling tty. 148 */ 149 if ( !debug ) { 150 int i, dt; 151 152 switch ( fork()) { 153 case 0 : 154 dt = getdtablesize(); 155 for ( i = 0; i < dt; i++ ) { 156 (void)close( i ); 157 } 158 if (( i = open( "/dev/tty", O_RDWR )) >= 0 ) { 159 (void)ioctl( i, TIOCNOTTY, 0 ); 160 setpgid( 0, getpid()); 161 (void)close( i ); 162 } 163 break; 164 case -1 : 165 perror( "fork" ); 166 exit( 1 ); 167 default : 168 exit( 0 ); 169 } 170 } 171 172 if (( p = rindex( *av, '/' )) == NULL ) { 173 p = *av; 174 } else { 175 p++; 176 } 177 178#ifdef ultrix 179 openlog( p, LOG_PID ); 180#else /* ultrix */ 181 set_processname(p); 182 syslog_setup(log_debug, logtype_default, logoption_ndelay|logoption_pid, logfacility_daemon ); 183#endif /* ultrix */ 184 185 /* allocate memory */ 186 memset (&sat.sat_addr, 0, sizeof (sat.sat_addr)); 187 188/* 189 force port 3 as the semi-official ATP access port MJ 2002 190*/ 191 if (( atp = atp_open( (u_int8_t)3, &sat.sat_addr )) == NULL ) { 192 LOG(log_error, logtype_default, "main: atp_open: %s", strerror( errno ) ); 193 exit( 1 ); 194 } 195 196 regerr = nbp_rgstr( atp_sockaddr( atp ), server, "Apple //gs", "*" ); 197 regerr += nbp_rgstr( atp_sockaddr( atp ), server, "Apple //e Boot", "*" ); 198 regerr += nbp_rgstr( atp_sockaddr( atp ), server, "ProDOS16 Image", "*" ); 199 if ( regerr < 0 ) { 200 LOG(log_error, logtype_default, "Can't register Apple II boot files %s", server ); 201 exit( 1 ); 202 } 203 204 LOG(log_info, logtype_default, "%s:Apple 2 Boot started", server ); 205 206 signal(SIGHUP, goaway); 207 signal(SIGTERM, goaway); 208 209 for (;;) { 210 /* 211 * Something seriously wrong with atp, since these assigns must 212 * be in the loop... 213 */ 214 atpb.atp_saddr = &sat; 215 atpb.atp_rreqdata = buf; 216 bzero( &sat, sizeof( struct sockaddr_at )); 217 atpb.atp_rreqdlen = sizeof( buf ); 218 219 if ( atp_rreq( atp, &atpb ) < 0 ) { 220 LOG(log_error, logtype_default, "main: atp_rreq: %s", strerror( errno ) ); 221 exit( 1 ); 222 } 223 224 p = buf; 225 bcopy( p, &req, sizeof( int32_t )); 226 req = ntohl( req ); 227 p += sizeof( int32_t ); 228 229/* 230 LOG(log_info, logtype_default, "req = %08lx",(long)req ); 231*/ 232 /* Byte-swap and multiply by 0x200. Converts block number to 233 file offset. */ 234 fileoff = (( req & 0x00ff0000 ) >> 7 ) | (( req & 0x0000ff00 ) << 9 ); 235 req &= 0xff000000; 236 237/* 238 LOG(log_info, logtype_default, " reqblklo = %02x",(int)reqblklo ); 239 LOG(log_info, logtype_default, " reqblkhi = %02x",(int)reqblkhi ); 240 LOG(log_info, logtype_default, " req now = %08lx",(long)req ); 241*/ 242 243 switch( req ) { 244 case 0x01000000 : /* Apple IIgs both ROM 1 and ROM 3 */ 245/* LOG(log_info, logtype_default, " Req ProDOS16 Boot Blocks" ); */ 246 resp = a2bootreq(_PATH_A_GS_BLOCKS); 247 break; 248 249 case 0x02000000 : /* Apple 2 Workstation card */ 250/* LOG(log_info, logtype_default, " Req Apple //e Boot" ); */ 251 resp = a2bootreq(_PATH_A_2E_BLOCKS); 252 break; 253 254 case 0x03000000 : /* Apple IIgs both ROM 1 and ROM 3 */ 255/* LOG(log_info, logtype_default, " Req ProDOS16 Image" ); */ 256 resp = a2bootreq(_PATH_P16_IMAGE); 257 break; 258 259 default : 260 LOG(log_error, logtype_default, bad ); 261 262 resp = TL_EOF; 263 *( buf + sizeof( int32_t ) ) = (unsigned char)strlen( bad ); 264 strcpy( buf + 1 + sizeof( int32_t ), bad ); 265 266 break; 267 } 268 269 bcopy( &resp, buf, sizeof( int32_t )); 270 271 iov.iov_len = sizeof( int32_t ) + 512; 272 iov.iov_base = buf; 273 atpb.atp_sresiov = &iov; 274 atpb.atp_sresiovcnt = 1; 275 276 if ( atp_sresp( atp, &atpb ) < 0 ) { 277 LOG(log_error, logtype_default, "main: atp_sresp: %s", strerror( errno ) ); 278 exit( 1 ); 279 } 280 } 281} 282 283 284/* below MJ 2002 (initially borrowed from aep_packet */ 285long a2bootreq(fname) 286 char *fname; 287{ 288 int f,m; 289 int32_t readlen; 290/* 291 LOG(log_info, logtype_default, " a2bootreq( %s )",fname ); 292*/ 293 f=open(fname,O_RDONLY ); 294 if(f==EOF) { 295 LOG(log_error, logtype_default, "a2boot open error on %s",fname); 296 return close(f); 297 } 298 299/* 300 LOG(log_info, logtype_default, "would lseek to %08lx",fileoff); 301*/ 302 lseek(f,fileoff,0); 303 readlen=read(f, buf + sizeof( int32_t ), 512 ); 304 305/* 306 LOG(log_info, logtype_default, "length is %08lx", readlen); 307*/ 308 309 if(readlen < 0x200) { 310/* LOG(log_info, logtype_default, "Read to EOF"); */ 311 close(f); 312 return TL_EOF; 313 } 314 close(f); 315 return TL_OK; 316} 317 318