jehanne/sys/src/kern/boot/boot.c

509 lines
10 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* This file is part of the UCB release of Plan 9. It is subject to the license
* terms in the LICENSE file found in the top-level directory of this
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
* part of the UCB release of Plan 9, including this file, may be copied,
* modified, propagated, or distributed except according to the terms contained
* in the LICENSE file.
*/
#include <u.h>
#include <libc.h>
#include <envvars.h>
#include <auth.h>
#include <9P2000.h>
#include "../boot/boot.h"
char cputype[64];
char sys[2*64];
int printcol;
int mflag;
int fflag;
int kflag;
char *bargv[Nbarg];
int bargc;
static Method *rootserver(char*);
static void usbinit(void);
static int startconsole(void);
static int startcomconsole(void);
static void bindBoot(void);
static void unbindBoot(void);
static void kbmap(void);
void
boot(int argc, char *argv[])
{
int fd, afd;
Method *mp;
char *cmd, cmdbuf[64], *iargv[16];
char rootbuf[64];
int islocal, ishybrid;
char *rp, *rsp;
int iargc, n;
char buf[32];
AuthInfo *ai;
open("/dev/cons", OREAD);
open("/dev/cons", OWRITE);
open("/dev/cons", OWRITE);
jehanne_fmtinstall('r', jehanne_errfmt);
bindBoot();
/*
* start /dev/cons
*/
if(readfile("#ec/bootconsole", buf, sizeof(buf)) >= 0
&& jehanne_strcmp("comconsole", buf) == 0){
if(startcomconsole() < 0)
fatal("no console found");
} else if(startconsole() < 0){
if(startcomconsole() < 0)
fatal("no console found");
}
/*
* init will reinitialize its namespace.
* #ec gets us plan9.ini settings (*var variables).
*/
bind("#ec", "/env", MREPL);
bind("#e", "/env", MBEFORE|MCREATE);
bind("#s", "/srv", MREPL|MCREATE);
bind("#p", "/proc", MREPL|MCREATE);
bind("#σ", "/shr", MREPL);
jehanne_print("Diex vos sait! Je m'appelle Jehanne O:-)\n");
#ifdef DEBUG
jehanne_print("argc=%d\n", argc);
for(fd = 0; fd < argc; fd++)
jehanne_print("%#p %s ", argv[fd], argv[fd]);
jehanne_print("\n");
#endif //DEBUG
ARGBEGIN{
case 'k':
kflag = 1;
break;
case 'm':
mflag = 1;
break;
case 'f':
fflag = 1;
break;
}ARGEND
readfile("#e/" ENV_CPUTYPE, cputype, sizeof(cputype));
/*
* set up usb keyboard, mouse and disk, if any.
*/
usbinit();
/*
* pick a method and initialize it
*/
if(method[0].name == nil)
fatal("no boot methods");
mp = rootserver(argc ? *argv : 0);
(*mp->config)(mp);
islocal = jehanne_strcmp(mp->name, "local") == 0;
ishybrid = jehanne_strcmp(mp->name, "hybrid") == 0;
/*
* load keymap if it is there.
*/
kbmap();
/*
* authentication agent
*/
authentication(cpuflag);
jehanne_print("connect...");
/*
* connect to the root file system
*/
fd = (*mp->connect)();
if(fd < 0)
fatal("can't connect to file server");
if(!islocal && !ishybrid){
if(cfs)
fd = (*cfs)(fd);
}
jehanne_print("\n");
jehanne_print("version...");
buf[0] = '\0';
n = fversion(fd, 0, buf, sizeof buf);
if(n < 0)
fatal("can't init 9P");
if(jehanne_access("#s/boot", AEXIST) < 0)
srvcreate("boot", fd);
unbindBoot();
/*
* create the name space, mount the root fs
*/
if(bind("/", "/", MREPL) < 0)
fatal("bind /");
rp = jehanne_getenv("rootspec");
if(rp == nil)
rp = "";
afd = fauth(fd, rp);
if(afd >= 0){
ai = auth_proxy(afd, auth_getkey, "proto=p9any role=client");
if(ai == nil)
jehanne_print("authentication failed (%r), trying mount anyways\n");
}
if(mount(fd, afd, "/root", MREPL|MCREATE, rp, '9') < 0)
fatal("mount /");
rsp = rp;
rp = jehanne_getenv("rootdir");
if(rp == nil)
rp = rootdir;
if(bind(rp, "/", MAFTER|MCREATE) < 0){
if(jehanne_strncmp(rp, "/root", 5) == 0){
jehanne_fprint(2, "boot: couldn't bind $rootdir=%s to root: %r\n", rp);
fatal("second bind /");
}
jehanne_snprint(rootbuf, sizeof rootbuf, "/root/%s", rp);
rp = rootbuf;
if(bind(rp, "/", MAFTER|MCREATE) < 0){
jehanne_fprint(2, "boot: couldn't bind $rootdir=%s to root: %r\n", rp);
if(jehanne_strcmp(rootbuf, "/root//plan9") == 0){
jehanne_fprint(2, "**** warning: remove rootdir=/plan9 entry from plan9.ini\n");
rp = "/root";
if(bind(rp, "/", MAFTER|MCREATE) < 0)
fatal("second bind /");
}else
fatal("second bind /");
}
}
close(fd);
setenv("rootdir", rp);
savelogs();
settime(islocal, afd, rsp);
if(afd > 0)
close(afd);
cmd = jehanne_getenv("init");
if(cmd == nil){
jehanne_sprint(cmdbuf, "/arch/%s/cmd/init -%s%s", cputype,
cpuflag ? "c" : "t", mflag ? "m" : "");
cmd = cmdbuf;
}
iargc = jehanne_tokenize(cmd, iargv, nelem(iargv)-1);
cmd = iargv[0];
/* make iargv[0] basename(iargv[0]) */
if(iargv[0] = jehanne_strrchr(iargv[0], '/'))
iargv[0]++;
else
iargv[0] = cmd;
iargv[iargc] = nil;
exec(cmd, (const char**)iargv);
fatal(cmd);
}
static Method*
findmethod(char *a)
{
Method *mp;
int i, j;
char *cp;
if((i = jehanne_strlen(a)) == 0)
return nil;
cp = jehanne_strchr(a, '!');
if(cp)
i = cp - a;
for(mp = method; mp->name; mp++){
j = jehanne_strlen(mp->name);
if(j > i)
j = i;
if(jehanne_strncmp(a, mp->name, j) == 0)
break;
}
if(mp->name)
return mp;
return nil;
}
/*
* ask user from whence cometh the root file system
*/
static Method*
rootserver(char *arg)
{
char prompt[256];
int rc;
Method *mp;
char *cp;
char reply[256];
int n;
/* look for required reply */
rc = readfile("#ec/nobootprompt", reply, sizeof(reply));
if(rc == 0 && reply[0]){
mp = findmethod(reply);
if(mp)
goto HaveMethod;
jehanne_print("boot method %s not found\n", reply);
reply[0] = 0;
}
/* make list of methods */
mp = method;
n = jehanne_sprint(prompt, "root is from (%s", mp->name);
for(mp++; mp->name; mp++)
n += jehanne_sprint(prompt+n, ", %s", mp->name);
jehanne_sprint(prompt+n, ")");
/* create default reply */
readfile("#ec/bootargs", reply, sizeof(reply));
if(reply[0] == 0 && arg != 0)
jehanne_strcpy(reply, arg);
if(reply[0]){
mp = findmethod(reply);
if(mp == 0)
reply[0] = 0;
}
if(reply[0] == 0)
jehanne_strcpy(reply, method->name);
/* parse replies */
do{
outin(prompt, reply, sizeof(reply));
mp = findmethod(reply);
}while(mp == nil);
HaveMethod:
bargc = jehanne_tokenize(reply, bargv, Nbarg-2);
bargv[bargc] = nil;
cp = jehanne_strchr(reply, '!');
if(cp)
jehanne_strcpy(sys, cp+1);
return mp;
}
static void
usbinit(void)
{
Waitmsg *w;
static char *argv[] = {"usbrc", nil};
int pid;
if (jehanne_access(usbrcPath, AEXIST) < 0) {
jehanne_print("usbinit: no %s\n", usbrcPath);
return;
}
switch(pid = jehanne_fork()){
case -1:
jehanne_print("usbinit: fork failed: %r\n");
case 0:
exec(usbrcPath, (const char**)argv);
fatal("can't exec usbd");
default:
break;
}
jehanne_print("usbinit: waiting usbrc...");
for(;;){
w = jehanne_wait();
if(w != nil && w->pid == pid){
if(w->msg[0] != 0)
fatal(w->msg);
jehanne_free(w);
break;
} else if(w == nil) {
fatal("configuring usbinit");
} else if(w->msg[0] != 0){
jehanne_print("usbinit: wait: %d %s\n", w->pid, w->msg);
}
jehanne_free(w);
}
jehanne_print("done\n");
}
static int
startconsole(void)
{
char *dbgfile, *argv[16], **av;
int i;
if(jehanne_access(screenconsolePath, AEXEC) < 0){
jehanne_print("cannot find screenconsole: %r\n");
return -1;
}
/* start agent */
i = 0;
av = argv;
av[i++] = "screenconsole";
if(dbgfile = jehanne_getenv("debugconsole")){
av[i++] = "-d";
av[i++] = dbgfile;
}
av[i] = 0;
switch(jehanne_fork()){
case -1:
fatal("starting screenconsole");
case 0:
exec(screenconsolePath, (const char**)av);
fatal("execing screenconsole");
default:
break;
}
/* wait for agent to really be there */
while(jehanne_access("#s/screenconsole", AEXIST) < 0){
jehanne_sleep(250);
}
/* replace 0, 1 and 2 */
if((i = open("#s/screenconsole", ORDWR)) < 0)
fatal("open #s/screenconsole");
if(mount(i, -1, "/dev", MBEFORE, "", '9') < 0)
fatal("mount /dev");
if((i = open("/dev/cons", OREAD))<0)
fatal("open /dev/cons, OREAD");
if(jehanne_dup(i, 0) != 0)
fatal("jehanne_dup(i, 0)");
close(i);
if((i = open("/dev/cons", OWRITE))<0)
fatal("open /dev/cons, OWRITE");
if(jehanne_dup(i, 1) != 1)
fatal("jehanne_dup(i, 1)");
close(i);
if(jehanne_dup(1, 2) != 2)
fatal("jehanne_dup(1, 2)");
return 0;
}
static int
startcomconsole(void)
{
char *dbgfile, *argv[16], **av;
int i;
if(jehanne_access(comconsolePath, AEXEC) < 0){
jehanne_print("cannot find comconsole: %r\n");
return -1;
}
/* start agent */
i = 0;
av = argv;
av[i++] = "comconsole";
if(dbgfile = jehanne_getenv("debugconsole")){
av[i++] = "-d";
av[i++] = dbgfile;
}
av[i++] = "-s";
av[i++] = "comconsole";
av[i++] = "#t/eia0";
av[i] = 0;
switch(jehanne_fork()){
case -1:
fatal("starting comconsole");
case 0:
exec(comconsolePath, (const char**)av);
fatal("execing comconsole");
default:
break;
}
/* wait for agent to really be there */
while(jehanne_access("#s/comconsole", AEXIST) < 0){
jehanne_sleep(250);
}
/* replace 0, 1 and 2 */
if((i = open("#s/comconsole", ORDWR)) < 0)
fatal("open #s/comconsole");
if(mount(i, -1, "/dev", MBEFORE, "", '9') < 0)
fatal("mount /dev");
if((i = open("/dev/cons", OREAD))<0)
fatal("open /dev/cons, OREAD");
if(jehanne_dup(i, 0) != 0)
fatal("jehanne_dup(i, 0)");
close(i);
if((i = open("/dev/cons", OWRITE))<0)
fatal("open /dev/cons, OWRITE");
if(jehanne_dup(i, 1) != 1)
fatal("jehanne_dup(i, 1)");
close(i);
if(jehanne_dup(1, 2) != 2)
fatal("jehanne_dup(1, 2)");
return 0;
}
static void
bindBoot(void)
{
BootBind *b = bootbinds;
if(b == nil || b->name == nil)
return;
while(b->name){
bind(b->name, b->old, b->flag);
++b;
}
}
static void
unbindBoot(void)
{
BootBind *b = bootbinds;
if(b == nil || b->name == nil)
return;
while(b->name)
++b;
while(--b >= bootbinds){
unmount(b->name, b->old);
}
}
static void
kbmap(void)
{
char *f;
int n, in, out;
char buf[1024];
f = jehanne_getenv("kbmap");
if(f == nil)
return;
if(bind("", "/dev", MAFTER) < 0){
warning("can't bind #κ");
return;
}
in = open(f, OREAD);
if(in < 0){
warning("can't open kbd map");
return;
}
out = open("/dev/kbmap", OWRITE);
if(out < 0) {
warning("can't open /dev/kbmap");
close(in);
return;
}
while((n = read(in, buf, sizeof(buf))) > 0)
if(write(out, buf, n) != n){
warning("write to /dev/kbmap failed");
break;
}
close(in);
close(out);
}