#include #include #include Fcall hdr; char buf[100]; char bootline[64]; char bootdevice; char bootserver[64]; int format; int manual; void error(char*); void sendmsg(int, char*); void bootparams(void); void dkconfig(void); int dkdial(void); void nop(int); void session(int); int cache(int); main(int argc, char *argv[]) { int fd, f; char buf[256]; Dir dir; open("#c/cons", OREAD); open("#c/cons", OWRITE); open("#c/cons", OWRITE); bootparams(); dkconfig(); fd = dkdial(); nop(fd); session(fd); fd = cache(fd); /* * make a /srv/boot and a /srv/bootes */ print("post..."); sprint(buf, "#s/%s", "bootes"); f = create(buf, 1, 0666); if(f < 0) error("create"); sprint(buf, "%d", fd); if(write(f, buf, strlen(buf)) != strlen(buf)) error("write"); close(f); sprint(buf, "#s/%s", "bootes"); f = create("#s/boot", 1, 0666); if(f < 0) error("create"); sprint(buf, "%d", fd); if(write(f, buf, strlen(buf)) != strlen(buf)) error("write"); close(f); /* * mount file server root after #/ root */ if(bind("/", "/", MREPL) < 0) error("bind"); print("mount..."); if(mount(fd, "/", MAFTER|MCREATE, "", "") < 0) error("mount"); /* * set the time from the access time of the root of the file server, * accessible as /.. */ print("time..."); if(stat("/..", buf) < 0) error("stat"); convM2D(buf, &dir); f = open("#c/time", OWRITE); sprint(buf, "%ld", dir.atime); write(f, buf, strlen(buf)); close(f); print("success\n"); bind("#k", "/net/net", MREPL); bind("#k", "/net/dk", MREPL); if(manual) execl("/68020/init", "init", "-m", 0); else execl("/68020/init", "init", 0); error("/68020/init"); } /* * open the network device, push on the needed multiplexors */ void dkconfig(void) { int cfd; switch(bootdevice){ case 'A': /* * grab the rs232 line, * make it 9600 baud, * push the async protocol onto it, */ cfd = open("#c/rs232ctl", 2); if(cfd < 0) error("opening #c/rs232ctl"); sendmsg(cfd, "B9600"); sendmsg(cfd, "push async"); break; case 'a': case 's': /* * grab the rs232 line, * make it 19200 baud, * push the async protocol onto it, */ cfd = open("#c/rs232ctl", 2); if(cfd < 0) error("opening #c/rs232ctl"); sendmsg(cfd, "B19200"); sendmsg(cfd, "push async"); break; default: /* * grab the incon, */ cfd = open("#i/ctl", 2); if(cfd < 0) error("opening #i/ctl"); break; } /* * push the dk multiplexor onto the communications link, * and use line 1 as the signalling channel. */ sendmsg(cfd, "push dkmux"); sendmsg(cfd, "config 1 16 norestart"); /* * fork a process to hold the device channel open * forever */ switch(fork()){ case -1: break; case 0: for(;;) sleep(60*1000); exit(0); default: close(cfd); break; } } /* * open a datakit channel and call ken, return an fd to the * connection. */ int dkdial(void) { int fd, cfd; int i; long n; for(i = 0; ; i++){ fd = open("#k/2/data", 2); if(fd < 0) error("opening #k/2/data"); cfd = open("#k/2/ctl", 2); if(cfd < 0) error("opening #k/2/ctl"); sprint(buf, "connect %s", bootserver); n = strlen(buf); if(write(cfd, buf, n) == n) break; if(i == 5) error("dialing"); print("error dialing %s, retrying ...\n", bootserver); close(fd); close(cfd); } print("connected to %s\n", bootserver); close(cfd); return fd; } /* * read arguments passed by kernel as * environment variables - YECH! */ void bootparams(void) { int f; char *cp; format = 0; manual = 0; f = open("#e/bootline", OREAD); if(f >= 0){ read(f, bootline, sizeof(bootline)-1); close(f); cp = bootline; while(cp = strchr(cp, ' ')){ if(*++cp != '-') continue; while(*cp && *cp!=' ') switch(*cp++){ case 'f': format = 1; break; case 'm': manual = 1; break; } } } f = open("#e/bootdevice", OREAD); if(f >= 0){ read(f, &bootdevice, 1); close(f); } f = open("#e/bootserver", OREAD); if(f >= 0){ read(f, bootserver, 64); close(f); } else strcpy(bootserver, "nfs"); } /* * send nop to file server */ void nop(int fd) { long n; print("nop..."); hdr.type = Tnop; hdr.tag = ~0; n = convS2M(&hdr, buf); if(write(fd, buf, n) != n) error("write nop"); n = read(fd, buf, sizeof buf); if(n==2 && buf[0]=='O' && buf[1]=='K') n = read(fd, buf, sizeof buf); if(n <= 0) error("read nop"); if(convM2S(buf, &hdr, n) == 0) { print("n = %d; buf = %.2x %.2x %.2x %.2x\n", n, buf[0], buf[1], buf[2], buf[3]); error("format nop"); } if(hdr.type != Rnop) error("not Rnop"); } /* * send nop to file server */ void session(int fd) { long n; print("session..."); hdr.type = Tsession; hdr.tag = ~0; n = convS2M(&hdr, buf); if(write(fd, buf, n) != n) error("write session"); n = read(fd, buf, sizeof buf); if(n <= 0) error("read session"); if(convM2S(buf, &hdr, n) == 0) error("format session"); if(hdr.type == Rerror){ print("error %s;", hdr.ename); error(hdr.ename); } if(hdr.type != Rsession) error("not Rsession"); } /* * see if we have a cache file system server in the kernel, * and use it if we do */ int cache(int fd) { int f; ulong i; int p[2]; /* * if there's no /cfs, just return the fd to the * file server */ f = open("/cfs", OREAD); if(f < 0) return fd; print("cfs..."); /* * if we have a cfs, give it the file server as fd 0 * and requests on fd 1 */ if(pipe(p)<0) error("pipe"); switch(fork()){ case -1: error("fork"); case 0: close(p[1]); dup(fd, 0); close(fd); dup(p[0], 1); close(p[0]); if(format) execl("/cfs", "bootcfs", "-fs", 0); else execl("/cfs", "bootcfs", "-s", 0); break; default: close(p[0]); close(fd); fd = p[1]; break; } return fd; } void sendmsg(int fd, char *msg) { int n; n = strlen(msg); if(write(fd, msg, n) != n) error(msg); } void error(char *s) { char buf[64]; errstr(buf); fprint(2, "boot: %s: %s\n", s, buf); exits(0); }