xref: /plan9/sys/src/9/pcboot/diskload.c (revision 4fa3bc585d2612e6bb007aaec8a7fe23f7fa9940)
125210b06SDavid du Colombier /*
225210b06SDavid du Colombier  * 9load - load next kernel from disk and start it
325210b06SDavid du Colombier  */
425210b06SDavid du Colombier #include	"u.h"
525210b06SDavid du Colombier #include	"../port/lib.h"
625210b06SDavid du Colombier #include	"mem.h"
725210b06SDavid du Colombier #include	"dat.h"
825210b06SDavid du Colombier #include	"fns.h"
925210b06SDavid du Colombier #include	"io.h"
1025210b06SDavid du Colombier #include	"ureg.h"
1125210b06SDavid du Colombier #include	"pool.h"
1225210b06SDavid du Colombier #include	"../port/error.h"
1325210b06SDavid du Colombier #include	"../port/netif.h"
1425210b06SDavid du Colombier #include	"dosfs.h"
1525210b06SDavid du Colombier #include	"../port/sd.h"
1625210b06SDavid du Colombier 
1725210b06SDavid du Colombier /* from <libc.h> */
1825210b06SDavid du Colombier #define	DIRMAX	(sizeof(Dir)+STATMAX)	/* max length of Dir structure */
1925210b06SDavid du Colombier #define	STATMAX	65535U	/* max length of machine-independent stat structure */
2025210b06SDavid du Colombier 
2125210b06SDavid du Colombier enum {
2225210b06SDavid du Colombier 	Bufsize = 8192,
2325210b06SDavid du Colombier };
2425210b06SDavid du Colombier 
2525210b06SDavid du Colombier int	dosdirread(File *f, char ***nmarray);
2625210b06SDavid du Colombier int	isconf(char *name);
2725210b06SDavid du Colombier 
2825210b06SDavid du Colombier static int progress = 1;
2925210b06SDavid du Colombier static Bootfs fs;
3025210b06SDavid du Colombier 
3125210b06SDavid du Colombier /*
3225210b06SDavid du Colombier  * from 9load's bootp.c:
3325210b06SDavid du Colombier  */
3425210b06SDavid du Colombier 
3525210b06SDavid du Colombier static int
dumpfile(char * file)3625210b06SDavid du Colombier dumpfile(char *file)
3725210b06SDavid du Colombier {
3825210b06SDavid du Colombier 	int n;
3925210b06SDavid du Colombier 	char *buf;
4025210b06SDavid du Colombier 
4125210b06SDavid du Colombier 	buf = smalloc(Maxfile + 1);
4225210b06SDavid du Colombier 	n = readfile(file, buf, Maxfile);
4325210b06SDavid du Colombier 	if (n < 0)
4425210b06SDavid du Colombier 		return -1;
4525210b06SDavid du Colombier 	buf[n] = 0;
4625210b06SDavid du Colombier 	print("%s (%d bytes):\n", file, n);
4725210b06SDavid du Colombier 	print("%s\n", buf);
4825210b06SDavid du Colombier 	free(buf);
4925210b06SDavid du Colombier 	return 0;
5025210b06SDavid du Colombier }
5125210b06SDavid du Colombier 
5225210b06SDavid du Colombier long
dirread0(Chan * c,uchar * p,long n)5325210b06SDavid du Colombier dirread0(Chan *c, uchar *p, long n)
5425210b06SDavid du Colombier {
5525210b06SDavid du Colombier 	long nn, nnn;
5625210b06SDavid du Colombier 	vlong off;
5725210b06SDavid du Colombier 
5825210b06SDavid du Colombier 	/*
5925210b06SDavid du Colombier 	 * The offset is passed through on directories, normally.
6025210b06SDavid du Colombier 	 * Sysseek complains, but pread is used by servers like exportfs,
6125210b06SDavid du Colombier 	 * that shouldn't need to worry about this issue.
6225210b06SDavid du Colombier 	 *
6325210b06SDavid du Colombier 	 * Notice that c->devoffset is the offset that c's dev is seeing.
6425210b06SDavid du Colombier 	 * The number of bytes read on this fd (c->offset) may be different
6525210b06SDavid du Colombier 	 * due to rewritings in rockfix.
6625210b06SDavid du Colombier 	 */
6725210b06SDavid du Colombier 	/* use and maintain channel's offset */
6825210b06SDavid du Colombier 	off = c->offset;
6925210b06SDavid du Colombier 	if(off < 0)
7025210b06SDavid du Colombier 		error(Enegoff);
7125210b06SDavid du Colombier 
7225210b06SDavid du Colombier 	if(off == 0){	/* rewind to the beginning of the directory */
7325210b06SDavid du Colombier 		c->offset = 0;
7425210b06SDavid du Colombier 		c->devoffset = 0;
7525210b06SDavid du Colombier 		mountrewind(c);
7625210b06SDavid du Colombier 		unionrewind(c);
7725210b06SDavid du Colombier 	}
7825210b06SDavid du Colombier 
7925210b06SDavid du Colombier 	if(c->qid.type & QTDIR){
8025210b06SDavid du Colombier 		if(mountrockread(c, p, n, &nn)){
8125210b06SDavid du Colombier 			/* do nothing: mountrockread filled buffer */
8225210b06SDavid du Colombier 		}else if(c->umh)
8325210b06SDavid du Colombier 			nn = unionread(c, p, n);
8425210b06SDavid du Colombier 		else{
8525210b06SDavid du Colombier 			if(off != c->offset)
8625210b06SDavid du Colombier 				error(Edirseek);
8725210b06SDavid du Colombier 			nn = devtab[c->type]->read(c, p, n, c->devoffset);
8825210b06SDavid du Colombier 		}
8925210b06SDavid du Colombier 		nnn = mountfix(c, p, nn, n);
9025210b06SDavid du Colombier 	}else
9125210b06SDavid du Colombier 		nnn = nn = devtab[c->type]->read(c, p, n, off);
9225210b06SDavid du Colombier 
9325210b06SDavid du Colombier 	lock(c);
9425210b06SDavid du Colombier 	c->devoffset += nn;
9525210b06SDavid du Colombier 	c->offset += nnn;
9625210b06SDavid du Colombier 	unlock(c);
9725210b06SDavid du Colombier 
9825210b06SDavid du Colombier 	/* nnn == 54, sizeof(Dir) == 60 */
9925210b06SDavid du Colombier 	return nnn;
10025210b06SDavid du Colombier }
10125210b06SDavid du Colombier 
10225210b06SDavid du Colombier long
dirread(Chan * c,Dir ** d)10325210b06SDavid du Colombier dirread(Chan *c, Dir **d)
10425210b06SDavid du Colombier {
10525210b06SDavid du Colombier 	uchar *buf;
10625210b06SDavid du Colombier 	long ts;
10725210b06SDavid du Colombier 
10825210b06SDavid du Colombier 	buf = malloc(DIRMAX);
10925210b06SDavid du Colombier 	if(buf == nil)
11025210b06SDavid du Colombier 		return -1;
11125210b06SDavid du Colombier 	ts = dirread0(c, buf, DIRMAX);
11225210b06SDavid du Colombier 	if(ts >= 0)
11325210b06SDavid du Colombier 		/* convert machine-independent representation to Dirs */
11425210b06SDavid du Colombier 		ts = dirpackage(buf, ts, d);
11525210b06SDavid du Colombier 	free(buf);
11625210b06SDavid du Colombier 	return ts;
11725210b06SDavid du Colombier }
11825210b06SDavid du Colombier 
11925210b06SDavid du Colombier static int
addsdev(Dir * dirp)12025210b06SDavid du Colombier addsdev(Dir *dirp)
12125210b06SDavid du Colombier {
12225210b06SDavid du Colombier 	int n, f, lines, flds;
12325210b06SDavid du Colombier 	vlong start, end;
12425210b06SDavid du Colombier 	char *buf, *part;
12525210b06SDavid du Colombier 	char *line[64], *fld[5];
12625210b06SDavid du Colombier 	char ctl[64], disk[64];
12725210b06SDavid du Colombier 
12825210b06SDavid du Colombier 	buf = smalloc(Maxfile + 1);
12925210b06SDavid du Colombier 	snprint(ctl, sizeof ctl, "#S/%s/ctl", dirp->name);
13025210b06SDavid du Colombier 	n = readfile(ctl, buf, Maxfile);
131e4575fb1SDavid du Colombier 	if (n < 0) {
132e4575fb1SDavid du Colombier 		free(buf);
13325210b06SDavid du Colombier 		return -1;
134e4575fb1SDavid du Colombier 	}
13525210b06SDavid du Colombier 	buf[n] = 0;
13625210b06SDavid du Colombier 
13725210b06SDavid du Colombier 	lines = getfields(buf, line, nelem(line), 0, "\r\n");
13825210b06SDavid du Colombier 	part = nil;
13925210b06SDavid du Colombier 	for (f = 0; f < lines; f++) {
14025210b06SDavid du Colombier 		flds = tokenize(line[f], fld, nelem(fld));
14125210b06SDavid du Colombier 		if (flds < 4 || strcmp(fld[0], "part") != 0)
14225210b06SDavid du Colombier 			continue;
14325210b06SDavid du Colombier 		kstrdup(&part, fld[1]);
14425210b06SDavid du Colombier 		start = strtoull(fld[2], nil, 0);
14525210b06SDavid du Colombier 		end   = strtoull(fld[3], nil, 0);
14625210b06SDavid du Colombier 		if (end > (vlong)100*(vlong)MB*MB) {
14725210b06SDavid du Colombier 			print("addsdev: implausible partition #S/%s/%s %lld %lld\n",
14825210b06SDavid du Colombier 				dirp->name, part, start, end);
14925210b06SDavid du Colombier 			continue;
15025210b06SDavid du Colombier 		}
15125210b06SDavid du Colombier 		/*
15225210b06SDavid du Colombier 		 * We are likely to only see a "data" partition on each disk.
15325210b06SDavid du Colombier 		 *
15425210b06SDavid du Colombier 		 * Read the on-disk partition tables & set in-core partitions
15525210b06SDavid du Colombier 		 * (disk, part, start, end).
15625210b06SDavid du Colombier 		 */
15725210b06SDavid du Colombier 		print("found partition #S/%s/%s %,lld %,lld\n",
15825210b06SDavid du Colombier 			dirp->name, part, start, end);
15925210b06SDavid du Colombier 		snprint(disk, sizeof disk, "#S/%s", dirp->name);
16025210b06SDavid du Colombier 		readparts(disk);
16125210b06SDavid du Colombier 	}
16225210b06SDavid du Colombier 	free(buf);
16325210b06SDavid du Colombier 	return 0;
16425210b06SDavid du Colombier }
16525210b06SDavid du Colombier 
16625210b06SDavid du Colombier static File file;
16725210b06SDavid du Colombier 
16825210b06SDavid du Colombier /*
16925210b06SDavid du Colombier  * look for kernels on a 9fat; if there's just one, return it.
17025210b06SDavid du Colombier  * could treat x and x.gz as one kernel.
17125210b06SDavid du Colombier  */
17225210b06SDavid du Colombier static char *
findonekernel(Bootfs * fs)17325210b06SDavid du Colombier findonekernel(Bootfs *fs)
17425210b06SDavid du Colombier {
17525210b06SDavid du Colombier 	int n, kerns;
17625210b06SDavid du Colombier 	char *bootfile, *name;
17725210b06SDavid du Colombier 	char **array;
17825210b06SDavid du Colombier 
17925210b06SDavid du Colombier 	if(fswalk(fs, "", &file) <= 0) {
18025210b06SDavid du Colombier 		print("can't walk to ''\n");
18125210b06SDavid du Colombier 		return nil;
18225210b06SDavid du Colombier 	}
18325210b06SDavid du Colombier 	dosdirread(&file, &array);
18425210b06SDavid du Colombier 	bootfile = nil;
18525210b06SDavid du Colombier 	kerns = 0;
18625210b06SDavid du Colombier 	for (n = 0; (name = array[n]) != nil; n++)
18725210b06SDavid du Colombier 		if(strncmp(name, "9pc", 3) == 0 ||
188*4fa3bc58SDavid du Colombier 		   strncmp(name, "9k8", 3) == 0 ||
189*4fa3bc58SDavid du Colombier 		   strncmp(name, "9k10", 4) == 0){
19025210b06SDavid du Colombier 			bootfile = name;
19125210b06SDavid du Colombier 			kerns++;
19225210b06SDavid du Colombier 		}
19325210b06SDavid du Colombier 	if (kerns > 1) {
19425210b06SDavid du Colombier 		print("found these kernels:");
19525210b06SDavid du Colombier 		for (n = 0; (name = array[n]) != nil; n++)
19625210b06SDavid du Colombier 			print(" %s", name);
19725210b06SDavid du Colombier 		print("\n");
19825210b06SDavid du Colombier 	}
19925210b06SDavid du Colombier 	return kerns == 1? bootfile: nil;
20025210b06SDavid du Colombier }
20125210b06SDavid du Colombier 
20225210b06SDavid du Colombier int
partboot(char * path)20325210b06SDavid du Colombier partboot(char *path)
20425210b06SDavid du Colombier {
20525210b06SDavid du Colombier 	long n;
20625210b06SDavid du Colombier 	char *buf;
20725210b06SDavid du Colombier 	Boot boot;
20825210b06SDavid du Colombier 	Boot *b;
20925210b06SDavid du Colombier 	Chan *ch;
21025210b06SDavid du Colombier 
21125210b06SDavid du Colombier 	b = &boot;
21225210b06SDavid du Colombier 	memset(b, 0, sizeof *b);
21325210b06SDavid du Colombier 	b->state = INITKERNEL;
21425210b06SDavid du Colombier 	ch = namecopen(path, OREAD);
21525210b06SDavid du Colombier 	if (ch == nil) {
21625210b06SDavid du Colombier 		print("can't open partition %s\n", path);
21725210b06SDavid du Colombier 		return -1;
21825210b06SDavid du Colombier 	}
21925210b06SDavid du Colombier 	print("loading %s\n", path);
22025210b06SDavid du Colombier 	buf = smalloc(Bufsize);
22125210b06SDavid du Colombier 	while((n = devtab[ch->type]->read(ch, buf, Bufsize, ch->offset)) > 0)
22225210b06SDavid du Colombier 		if(bootpass(b, buf, n) != MORE)
22325210b06SDavid du Colombier 			break;
22425210b06SDavid du Colombier 	bootpass(b, nil, 0);		/* attempts to boot */
22525210b06SDavid du Colombier 
22625210b06SDavid du Colombier 	free(buf);
22725210b06SDavid du Colombier 	cclose(ch);
22825210b06SDavid du Colombier 	return -1;
22925210b06SDavid du Colombier }
23025210b06SDavid du Colombier 
23125210b06SDavid du Colombier /* fsroot must be nil or a fat root directory already dosinit'ed */
23225210b06SDavid du Colombier static void
trybootfile(char * bootfile,Bootfs * fsroot)23325210b06SDavid du Colombier trybootfile(char *bootfile, Bootfs *fsroot)
23425210b06SDavid du Colombier {
23525210b06SDavid du Colombier 	int nf;
23625210b06SDavid du Colombier 	char fat[64];
23725210b06SDavid du Colombier 	char *disk, *part, *file, *bootcopy;
23825210b06SDavid du Colombier 	char *fields[4];
23925210b06SDavid du Colombier 	Boot boot;
24025210b06SDavid du Colombier 	static int didaddconf;
24125210b06SDavid du Colombier 
24225210b06SDavid du Colombier 	bootcopy = file = nil;
24325210b06SDavid du Colombier 	kstrdup(&bootcopy, bootfile);
24425210b06SDavid du Colombier 	nf = getfields(bootcopy, fields, nelem(fields), 0, "!");
24525210b06SDavid du Colombier 	switch(nf){
24625210b06SDavid du Colombier 	case 3:
24725210b06SDavid du Colombier 		file = fields[2];
24825210b06SDavid du Colombier 		/* fall through */
24925210b06SDavid du Colombier 	case 2:
25025210b06SDavid du Colombier 		disk = fields[0];
25125210b06SDavid du Colombier 		part = fields[1];
25225210b06SDavid du Colombier 		break;
25325210b06SDavid du Colombier 	default:
25425210b06SDavid du Colombier 		print("bad bootfile syntax: %s\n", bootfile);
25525210b06SDavid du Colombier 		return;
25625210b06SDavid du Colombier 	}
25725210b06SDavid du Colombier 
25825210b06SDavid du Colombier 	if(didaddconf == 0) {
25925210b06SDavid du Colombier 		didaddconf = 1;
26025210b06SDavid du Colombier 		sdaddallconfs(sdaddconf);
26125210b06SDavid du Colombier 	}
26225210b06SDavid du Colombier 
26325210b06SDavid du Colombier 	snprint(fat, sizeof fat, "#S/%s/%s", disk, part);
26425210b06SDavid du Colombier 	if (file == nil) { /* if no file, try to load from partition directly */
26525210b06SDavid du Colombier 		partboot(fat);
26625210b06SDavid du Colombier 		return;
26725210b06SDavid du Colombier 	}
26825210b06SDavid du Colombier 
26925210b06SDavid du Colombier 	if (fsroot == nil) {
27025210b06SDavid du Colombier 		fsroot = &fs;
27125210b06SDavid du Colombier 		memset(fsroot, 0, sizeof *fsroot);
27225210b06SDavid du Colombier 		if (dosinit(fsroot, fat) < 0) {
27325210b06SDavid du Colombier 			print("dosinit %s failed\n", fat);
27425210b06SDavid du Colombier 			return;
27525210b06SDavid du Colombier 		}
27625210b06SDavid du Colombier 	}
27725210b06SDavid du Colombier 
27825210b06SDavid du Colombier 	/* load kernel and jump to it */
27925210b06SDavid du Colombier 	memset(&boot, 0, sizeof boot);
28025210b06SDavid du Colombier 	boot.state = INITKERNEL;
28125210b06SDavid du Colombier 	fsboot(fsroot, file, &boot);
28225210b06SDavid du Colombier 
28325210b06SDavid du Colombier 	/* failed to boot */
28425210b06SDavid du Colombier }
28525210b06SDavid du Colombier 
28625210b06SDavid du Colombier /*
28725210b06SDavid du Colombier  * for a given disk's 9fat, find & load plan9.ini, parse it,
28825210b06SDavid du Colombier  * extract kernel filename, load that kernel and jump to it.
28925210b06SDavid du Colombier  */
29025210b06SDavid du Colombier static void
trydiskboot(char * disk)29125210b06SDavid du Colombier trydiskboot(char *disk)
29225210b06SDavid du Colombier {
29325210b06SDavid du Colombier 	int n;
29425210b06SDavid du Colombier 	char fat[80];
29525210b06SDavid du Colombier 	char *ini, *bootfile;
29625210b06SDavid du Colombier 
29725210b06SDavid du Colombier 	/* mount the disk's 9fat */
29825210b06SDavid du Colombier 	memset(&fs, 0, sizeof fs);
29925210b06SDavid du Colombier 	snprint(fat, sizeof fat, "#S/%s/9fat", disk);
30025210b06SDavid du Colombier 	if (dosinit(&fs, fat) < 0) {
30125210b06SDavid du Colombier 		print("dosinit %s failed\n", fat);
30225210b06SDavid du Colombier 		return;
30325210b06SDavid du Colombier 	}
30425210b06SDavid du Colombier 
30525210b06SDavid du Colombier 	/* open plan9.ini, read it */
30625210b06SDavid du Colombier 	ini = smalloc(Maxfile+1);
30725210b06SDavid du Colombier 	if(fswalk(&fs, "plan9.ini", &file) <= 0) {
30825210b06SDavid du Colombier 		print("no plan9.ini in %s\n", fat);
30925210b06SDavid du Colombier 		n = 0;
31025210b06SDavid du Colombier 	} else {
31125210b06SDavid du Colombier 		n = fsread(&file, ini, Maxfile);
31225210b06SDavid du Colombier 		if (n < 0)
31325210b06SDavid du Colombier 			panic("error reading %s", ini);
31425210b06SDavid du Colombier 	}
31525210b06SDavid du Colombier 	ini[n] = 0;
31625210b06SDavid du Colombier 
31725210b06SDavid du Colombier 	/*
31825210b06SDavid du Colombier 	 * take note of plan9.ini contents.  consumes ini to make config vars,
31925210b06SDavid du Colombier 	 * thus we can't free ini.
32025210b06SDavid du Colombier 	 */
32125210b06SDavid du Colombier 	dotini(ini);
32225210b06SDavid du Colombier 	i8250console();			/* (re)configure serial port */
32325210b06SDavid du Colombier 
32425210b06SDavid du Colombier 	bootfile = nil;			/* for kstrdup in askbootfile */
32525210b06SDavid du Colombier 	if(isconf("bootfile")) {
32625210b06SDavid du Colombier 		kstrdup(&bootfile, getconf("bootfile"));
32725210b06SDavid du Colombier 		if(strcmp(bootfile, "manual") == 0)
328e4575fb1SDavid du Colombier 			askbootfile(fat, sizeof fat, &bootfile, 0, "");
32925210b06SDavid du Colombier 
33025210b06SDavid du Colombier 		/* pass arguments to kernels that can use them */
33125210b06SDavid du Colombier 		strecpy(BOOTLINE, BOOTLINE+BOOTLINELEN, bootfile);
33225210b06SDavid du Colombier 	} else if ((bootfile = findonekernel(&fs)) != nil) {  /* look in fat */
33325210b06SDavid du Colombier 		snprint(fat, sizeof fat, "%s!9fat!%s", disk, bootfile);
33425210b06SDavid du Colombier 		bootfile = fat;
33525210b06SDavid du Colombier 		print("no bootfile named in plan9.ini; found %s\n", bootfile);
33625210b06SDavid du Colombier 	} else {
33725210b06SDavid du Colombier 		/* if #S/disk/kernel partition exists, load from it. */
33825210b06SDavid du Colombier 		snprint(fat, sizeof fat, "#S/%s/kernel", disk);
33925210b06SDavid du Colombier 		partboot(fat);
34025210b06SDavid du Colombier 		/* last resort: ask the user */
341e4575fb1SDavid du Colombier 		askbootfile(fat, sizeof fat, &bootfile, Promptsecs,
342e4575fb1SDavid du Colombier 			"sdC0!9fat!9pccpu");
34325210b06SDavid du Colombier 	}
34425210b06SDavid du Colombier 	trybootfile(bootfile, &fs);
34525210b06SDavid du Colombier 
34625210b06SDavid du Colombier 	/* failed; try again */
34725210b06SDavid du Colombier }
34825210b06SDavid du Colombier 
34925210b06SDavid du Colombier /*
35025210b06SDavid du Colombier  * find all the disks in #S, read their partition tables and set those
35125210b06SDavid du Colombier  * partitions in core, mainly so that we can access 9fat file systems.
35225210b06SDavid du Colombier  * for each disk's 9fat, read plan9.ini and boot the named kernel.
35325210b06SDavid du Colombier  */
35425210b06SDavid du Colombier void
bootloadproc(void *)35525210b06SDavid du Colombier bootloadproc(void *)
35625210b06SDavid du Colombier {
35725210b06SDavid du Colombier 	int n, dirs, sdev;
35825210b06SDavid du Colombier 	char kern[64];
35925210b06SDavid du Colombier 	char *sdevs[128];
36025210b06SDavid du Colombier 	Chan *sdch;
36125210b06SDavid du Colombier 	Dir *dirp, *dp;
36225210b06SDavid du Colombier 
363e4575fb1SDavid du Colombier 	memset(sdevs, 0, sizeof sdevs);
36425210b06SDavid du Colombier 	sdch = nil;
36525210b06SDavid du Colombier 	while(waserror()) {
36625210b06SDavid du Colombier 		print("error caught at top level in bootload\n");
36725210b06SDavid du Colombier 		if(sdch) {
36825210b06SDavid du Colombier 			cclose(sdch);
36925210b06SDavid du Colombier 			sdch = nil;
37025210b06SDavid du Colombier 		}
37125210b06SDavid du Colombier 	}
37225210b06SDavid du Colombier 	bind("#S", "/dev", MAFTER);		/* try to force an attach */
37325210b06SDavid du Colombier 	sdch = namecopen("#S", OREAD);
37425210b06SDavid du Colombier 	if (sdch == nil)
37525210b06SDavid du Colombier 		panic("no disks (no #S)");
37625210b06SDavid du Colombier 	sdev = 0;
37725210b06SDavid du Colombier 	while ((dirs = dirread(sdch, &dirp)) > 0) {
37825210b06SDavid du Colombier 		for (dp = dirp; dirs-- > 0; dp++)
37925210b06SDavid du Colombier 			if (strcmp(dp->name, "sdctl") != 0) {
38025210b06SDavid du Colombier 				addsdev(dp);
38125210b06SDavid du Colombier 				if (sdev >= nelem(sdevs))
38225210b06SDavid du Colombier 					print("too many sdevs; ignoring %s\n",
38325210b06SDavid du Colombier 						dp->name);
38425210b06SDavid du Colombier 				else
38525210b06SDavid du Colombier 					kstrdup(&sdevs[sdev++], dp->name);
38625210b06SDavid du Colombier 			}
38725210b06SDavid du Colombier 		free(dirp);
38825210b06SDavid du Colombier 	}
38925210b06SDavid du Colombier 	cclose(sdch);
39025210b06SDavid du Colombier 	sdch = nil;
39125210b06SDavid du Colombier 	if (sdev == 0)
39225210b06SDavid du Colombier 		panic("no disks (in #S)");
39325210b06SDavid du Colombier 
39425210b06SDavid du Colombier 	print("disks:");
39525210b06SDavid du Colombier 	for (n = 0; n < sdev; n++)
39625210b06SDavid du Colombier 		print(" %s", sdevs[n]);
39725210b06SDavid du Colombier 	print("\n");
39825210b06SDavid du Colombier 
39925210b06SDavid du Colombier 	for (n = 0; n < sdev; n++) {
40025210b06SDavid du Colombier 		print("trying %s...", sdevs[n]);
40125210b06SDavid du Colombier 		trydiskboot(sdevs[n]);
40225210b06SDavid du Colombier 	}
40325210b06SDavid du Colombier 	USED(sdch);
40425210b06SDavid du Colombier 	for (;;) {
405e4575fb1SDavid du Colombier 		askbootfile(kern, sizeof kern, nil, 0, "");
40625210b06SDavid du Colombier 		trybootfile(kern, nil);
40725210b06SDavid du Colombier 	}
40825210b06SDavid du Colombier 	// poperror();
40925210b06SDavid du Colombier }
410