]> arthur.barton.de Git - netatalk.git/blob - contrib/a2boot/a2boot.c
77fc641f20c45378f47e00daec7d0e6ce290da34
[netatalk.git] / contrib / a2boot / a2boot.c
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
69 int     debug = 0;
70 char    *bad = "Bad request!";
71 char    buf[ 4624 ];
72 char    *server;
73 int32_t fileoff;
74
75 long a2bootreq(char *fname);
76
77 void 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  */
93 void
94 goaway(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
108 int 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 */
285 long 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