boot1.c revision 95346
190699Srobert/*
290699Srobert * Copyright (c) 1998 Robert Nordier
390699Srobert * All rights reserved.
490699Srobert * Copyright (c) 2001 Robert Drehmel
590699Srobert * All rights reserved.
690699Srobert *
790699Srobert * Redistribution and use in source and binary forms are freely
890699Srobert * permitted provided that the above copyright notice and this
990699Srobert * paragraph and the following disclaimer are duplicated in all
1090699Srobert * such forms.
1190699Srobert *
1290699Srobert * This software is provided "AS IS" and without any express or
1390699Srobert * implied warranties, including, without limitation, the implied
1490699Srobert * warranties of merchantability and fitness for a particular
1590699Srobert * purpose.
1690699Srobert *
1790699Srobert */
1891295Srobert
1991295Srobert#include <sys/cdefs.h>
2091295Srobert__FBSDID("$FreeBSD: head/sys/boot/sparc64/boot1/boot1.c 95346 2002-04-24 04:27:49Z jake $");
2191295Srobert
2290699Srobert#include <sys/param.h>
2390699Srobert#include <sys/reboot.h>
2490699Srobert#include <sys/diskslice.h>
2590699Srobert#include <sys/disklabel.h>
2690699Srobert#include <sys/dirent.h>
2790699Srobert#include <machine/elf.h>
2890699Srobert#include <machine/stdarg.h>
2990699Srobert
3090699Srobert#include <ufs/ffs/fs.h>
3190699Srobert#include <ufs/ufs/dinode.h>
3290699Srobert
3395337Sjake#define _PATH_LOADER	"/boot/loader"
3495337Sjake#define _PATH_KERNEL	"/boot/kernel/kernel"
3590699Srobert
3690699Srobert#define BSIZEMAX	8192
3790699Srobert
3890699Srobert/*
3990699Srobert * This structure will be refined along with the addition of a bootpath
4090699Srobert * parsing routine when it is necessary to cope with bootpaths that are
4190699Srobert * not in the exact <devpath>@<controller>,<disk>:<partition> format and
4290699Srobert * for which we need to evaluate the disklabel ourselves.
4390699Srobert */
4490699Srobertstruct disk {
4590699Srobert	int meta;
4690699Srobert};
4790699Srobertstruct disk dsk;
4890699Srobert
4995346Sjakestatic const char digits[] = "0123456789abcdef";
5090699Srobert
5195346Sjakestatic char bootpath[128];
5295346Sjakestatic char bootargs[128];
5395346Sjake
5495346Sjakestatic int kflag;
5595346Sjake
5690699Srobertstatic uint32_t fs_off;
5790699Srobert
5895346Sjaketypedef int putc_func_t(int c, void *arg);
5995346Sjake
6095346Sjakeint main(int ac, char **av);
6195346Sjake
6295342Sjakestatic void exit(int);
6390699Srobertstatic void load(const char *);
6490699Srobertstatic ino_t lookup(const char *);
6590699Srobertstatic ssize_t fsread(ino_t, void *, size_t);
6690699Srobertstatic int dskread(void *, u_int64_t, int);
6790699Srobert
6895340Sjakestatic void bcopy(const void *src, void *dst, size_t len);
6995340Sjakestatic void bzero(void *b, size_t len);
7090699Srobert
7195346Sjakestatic int printf(const char *fmt, ...);
7295346Sjakestatic int vprintf(const char *fmt, va_list ap);
7395346Sjakestatic int putchar(int c, void *arg);
7495346Sjake
7595346Sjakestatic int __printf(const char *fmt, putc_func_t *putc, void *arg, va_list ap);
7695346Sjakestatic int __putc(int c, void *arg);
7795346Sjakestatic int __puts(const char *s, putc_func_t *putc, void *arg);
7895346Sjakestatic char *__uitoa(char *buf, u_int val, int base);
7995346Sjakestatic char *__ultoa(char *buf, u_long val, int base);
8095346Sjake
8190699Srobert/*
8290699Srobert * Open Firmware interface functions
8390699Srobert */
8490699Sroberttypedef u_int64_t	ofwcell_t;
8590699Sroberttypedef int32_t		ofwh_t;
8690699Sroberttypedef u_int32_t	u_ofwh_t;
8790699Sroberttypedef int (*ofwfp_t)(ofwcell_t []);
8890699Srobertofwfp_t ofw;			/* the prom Open Firmware entry */
8990699Srobert
9090699Srobertvoid ofw_init(int, int, int, int, ofwfp_t);
9190699Srobertofwh_t ofw_finddevice(const char *);
9290699Srobertofwh_t ofw_open(const char *);
9390699Srobertint ofw_getprop(ofwh_t, const char *, void *, size_t);
9490699Srobertint ofw_read(ofwh_t, void *, size_t);
9590699Srobertint ofw_write(ofwh_t, const void *, size_t);
9690699Srobertint ofw_seek(ofwh_t, u_int64_t);
9790699Srobert
9890699Srobertofwh_t bootdevh;
9990699Srobertofwh_t stdinh, stdouth;
10090699Srobert
10190699Srobert/*
10290699Srobert * This has to stay here, as the PROM seems to ignore the
10390699Srobert * entry point specified in the a.out header.  (or elftoaout is broken)
10490699Srobert */
10590699Srobert
10690699Srobertvoid
10790699Srobertofw_init(int d, int d1, int d2, int d3, ofwfp_t ofwaddr)
10890699Srobert{
10990699Srobert	ofwh_t chosenh;
11095346Sjake	char *av[16];
11195346Sjake	char *p;
11295346Sjake	int ac;
11390699Srobert
11490699Srobert	ofw = ofwaddr;
11590699Srobert
11690699Srobert	chosenh = ofw_finddevice("/chosen");
11790699Srobert	ofw_getprop(chosenh, "stdin", &stdinh, sizeof(stdinh));
11890699Srobert	ofw_getprop(chosenh, "stdout", &stdouth, sizeof(stdouth));
11995346Sjake	ofw_getprop(chosenh, "bootargs", bootargs, sizeof(bootargs));
12090699Srobert	ofw_getprop(chosenh, "bootpath", bootpath, sizeof(bootpath));
12190699Srobert
12295346Sjake	bootargs[sizeof(bootargs) - 1] = '\0';
12395346Sjake	bootpath[sizeof(bootpath) - 1] = '\0';
12495346Sjake
12590699Srobert	if ((bootdevh = ofw_open(bootpath)) == -1) {
12690699Srobert		printf("Could not open boot device.\n");
12795346Sjake	}
12890699Srobert
12995346Sjake	ac = 0;
13095346Sjake	p = bootargs;
13195346Sjake	for (;;) {
13295346Sjake		while (*p == ' ' && *p != '\0')
13395346Sjake			p++;
13495346Sjake		if (*p == '\0' || ac >= 16)
13595346Sjake			break;
13695346Sjake		av[ac++] = p;
13795346Sjake		while (*p != ' ' && *p != '\0')
13895346Sjake			p++;
13995346Sjake		if (*p != '\0')
14095346Sjake			*p++ = '\0';
14195346Sjake	}
14295346Sjake
14395346Sjake	exit(main(ac, av));
14490699Srobert}
14590699Srobert
14690699Srobertofwh_t
14790699Srobertofw_finddevice(const char *name)
14890699Srobert{
14991295Srobert	ofwcell_t args[] = {
15091295Srobert		(ofwcell_t)"finddevice",
15191295Srobert		1,
15291295Srobert		1,
15391295Srobert		(ofwcell_t)name,
15491295Srobert		0
15591295Srobert	};
15691295Srobert
15791295Srobert	if ((*ofw)(args)) {
15891295Srobert		printf("ofw_finddevice: name=\"%s\"\n", name);
15991295Srobert		return (1);
16091295Srobert	}
16191295Srobert	return (args[4]);
16290699Srobert}
16390699Srobert
16490699Srobertint
16590699Srobertofw_getprop(ofwh_t ofwh, const char *name, void *buf, size_t len)
16690699Srobert{
16791295Srobert	ofwcell_t args[] = {
16891295Srobert		(ofwcell_t)"getprop",
16991295Srobert		4,
17091295Srobert		1,
17191295Srobert		(u_ofwh_t)ofwh,
17291295Srobert		(ofwcell_t)name,
17391295Srobert		(ofwcell_t)buf,
17491295Srobert		len,
17590699Srobert	0
17691295Srobert	};
17791295Srobert
17891295Srobert	if ((*ofw)(args)) {
17991295Srobert		printf("ofw_getprop: ofwh=0x%x buf=%p len=%u\n",
18091295Srobert			ofwh, buf, len);
18191295Srobert		return (1);
18291295Srobert	}
18391295Srobert	return (0);
18490699Srobert}
18590699Srobert
18690699Srobertofwh_t
18790699Srobertofw_open(const char *path)
18890699Srobert{
18991295Srobert	ofwcell_t args[] = {
19091295Srobert		(ofwcell_t)"open",
19191295Srobert		1,
19291295Srobert		1,
19391295Srobert		(ofwcell_t)path,
19491295Srobert		0
19591295Srobert	};
19691295Srobert
19791295Srobert	if ((*ofw)(args)) {
19891295Srobert		printf("ofw_open: path=\"%s\"\n", path);
19991295Srobert		return (-1);
20091295Srobert	}
20191295Srobert	return (args[4]);
20290699Srobert}
20390699Srobert
20490699Srobertint
20590699Srobertofw_close(ofwh_t devh)
20690699Srobert{
20791295Srobert	ofwcell_t args[] = {
20891295Srobert		(ofwcell_t)"close",
20991295Srobert		1,
21091295Srobert		0,
21191295Srobert		(u_ofwh_t)devh
21291295Srobert	};
21391295Srobert
21491295Srobert	if ((*ofw)(args)) {
21591295Srobert		printf("ofw_close: devh=0x%x\n", devh);
21691295Srobert		return (1);
21791295Srobert	}
21891295Srobert	return (0);
21990699Srobert}
22090699Srobert
22190699Srobertint
22290699Srobertofw_read(ofwh_t devh, void *buf, size_t len)
22390699Srobert{
22491295Srobert	ofwcell_t args[] = {
22591295Srobert		(ofwcell_t)"read",
22691295Srobert		4,
22791295Srobert		1,
22891295Srobert		(u_ofwh_t)devh,
22991295Srobert		(ofwcell_t)buf,
23091295Srobert		len,
23191295Srobert		0
23291295Srobert	};
23391295Srobert
23491295Srobert	if ((*ofw)(args)) {
23591295Srobert		printf("ofw_read: devh=0x%x buf=%p len=%u\n", devh, buf, len);
23691295Srobert		return (1);
23791295Srobert	}
23891295Srobert	return (0);
23990699Srobert}
24090699Srobert
24190699Srobertint
24290699Srobertofw_write(ofwh_t devh, const void *buf, size_t len)
24390699Srobert{
24491295Srobert	ofwcell_t args[] = {
24591295Srobert		(ofwcell_t)"write",
24691295Srobert		3,
24791295Srobert		1,
24891295Srobert		(u_ofwh_t)devh,
24991295Srobert		(ofwcell_t)buf,
25091295Srobert		len,
25191295Srobert		0
25291295Srobert	};
25391295Srobert
25491295Srobert	if ((*ofw)(args)) {
25591295Srobert		printf("ofw_write: devh=0x%x buf=%p len=%u\n", devh, buf, len);
25691295Srobert		return (1);
25791295Srobert	}
25891295Srobert	return (0);
25990699Srobert}
26090699Srobert
26190699Srobertint
26290699Srobertofw_seek(ofwh_t devh, u_int64_t off)
26390699Srobert{
26491295Srobert	ofwcell_t args[] = {
26591295Srobert		(ofwcell_t)"seek",
26691295Srobert		4,
26791295Srobert		1,
26891295Srobert		(u_ofwh_t)devh,
26991295Srobert		off >> 32,
27091678Srobert		off,
27191295Srobert		0
27291295Srobert	};
27391295Srobert
27491295Srobert	if ((*ofw)(args)) {
27591295Srobert		printf("ofw_seek: devh=0x%x off=0x%lx\n", devh, off);
27691295Srobert		return (1);
27791295Srobert	}
27891295Srobert	return (0);
27990699Srobert}
28090699Srobert
28195342Sjakevoid
28295342Sjakeofw_exit(void)
28395342Sjake{
28495342Sjake	ofwcell_t args[3];
28595342Sjake
28695342Sjake	args[0] = (ofwcell_t)"exit";
28795342Sjake	args[1] = 0;
28895342Sjake	args[2] = 0;
28995342Sjake
29095342Sjake	(*ofw)(args);
29195342Sjake}
29295342Sjake
29395340Sjakestatic void
29495340Sjakebcopy(const void *dst, void *src, size_t len)
29595340Sjake{
29695340Sjake	const char *d = dst;
29795340Sjake	char *s = src;
29895340Sjake
29995340Sjake	while (len-- != 0)
30095340Sjake		*s++ = *d++;
30195340Sjake}
30295340Sjake
30395340Sjakestatic void
30495340Sjakebzero(void *b, size_t len)
30595340Sjake{
30695340Sjake	char *p = b;
30795340Sjake
30895340Sjake	while (len-- != 0)
30995340Sjake		*p++ = 0;
31095340Sjake}
31195340Sjake
31290699Srobertstatic int
31390699Srobertstrcmp(const char *s1, const char *s2)
31490699Srobert{
31591295Srobert	for (; *s1 == *s2 && *s1; s1++, s2++)
31691295Srobert		;
31791295Srobert	return ((u_char)*s1 - (u_char)*s2);
31890699Srobert}
31990699Srobert
32090699Srobertstatic int
32190699Srobertfsfind(const char *name, ino_t * ino)
32290699Srobert{
32391295Srobert	char buf[DEV_BSIZE];
32491295Srobert	struct dirent *d;
32591295Srobert	char *s;
32691295Srobert	ssize_t n;
32790699Srobert
32891295Srobert	fs_off = 0;
32991295Srobert	while ((n = fsread(*ino, buf, DEV_BSIZE)) > 0) {
33091295Srobert		for (s = buf; s < buf + DEV_BSIZE;) {
33191295Srobert			d = (void *)s;
33295337Sjake			if (!strcmp(name, d->d_name)) {
33391295Srobert				*ino = d->d_fileno;
33491295Srobert				return (d->d_type);
33591295Srobert			}
33691295Srobert			s += d->d_reclen;
33791295Srobert		}
33890699Srobert	}
33991295Srobert	return (0);
34090699Srobert}
34190699Srobert
34295346Sjakeint
34395346Sjakemain(int ac, char **av)
34490699Srobert{
34595346Sjake	const char *path;
34695346Sjake	int i;
34791295Srobert
34895346Sjake	path = _PATH_LOADER;
34995346Sjake	for (i = 0; i < ac; i++) {
35095346Sjake		switch (av[i][0]) {
35195346Sjake		case '-':
35295346Sjake			switch (av[i][1]) {
35395346Sjake			case 'k':
35495346Sjake				kflag = 1;
35595346Sjake				break;
35695346Sjake			default:
35795346Sjake				break;
35895346Sjake			}
35995346Sjake			break;
36095346Sjake		default:
36195346Sjake			path = av[i];
36295346Sjake			break;
36395346Sjake		}
36495346Sjake	}
36590699Srobert
36691295Srobert	printf(" \n>> FreeBSD/sparc64 boot block\n"
36790699Srobert	"   Boot path:   %s\n"
36895346Sjake	"   Boot loader: %s\n", bootpath, path);
36995346Sjake	load(path);
37091295Srobert	return (1);
37190699Srobert}
37290699Srobert
37390699Srobertstatic void
37495342Sjakeexit(int code)
37595342Sjake{
37695342Sjake
37795342Sjake	ofw_exit();
37895342Sjake}
37995342Sjake
38095342Sjakestatic void
38190699Srobertload(const char *fname)
38290699Srobert{
38391295Srobert	Elf64_Ehdr eh;
38495339Sjake	Elf64_Phdr ph;
38591295Srobert	caddr_t p;
38691295Srobert	ino_t ino;
38795339Sjake	int i;
38890699Srobert
38991295Srobert	if ((ino = lookup(fname)) == 0) {
39095337Sjake		printf("File %s not found\n", fname);
39190699Srobert		return;
39290699Srobert	}
39395339Sjake	if (fsread(ino, &eh, sizeof(eh)) != sizeof(eh)) {
39495339Sjake		printf("Can't read elf header\n");
39591295Srobert		return;
39695339Sjake	}
39791295Srobert	if (!IS_ELF(eh)) {
39891295Srobert		printf("Not an ELF file\n");
39991295Srobert		return;
40091295Srobert	}
40195339Sjake	for (i = 0; i < eh.e_phnum; i++) {
40295339Sjake		fs_off = eh.e_phoff + i * eh.e_phentsize;
40395339Sjake		if (fsread(ino, &ph, sizeof(ph)) != sizeof(ph)) {
40495339Sjake			printf("Can't read program header %d\n", i);
40591295Srobert			return;
40691295Srobert		}
40795339Sjake		if (ph.p_type != PT_LOAD)
40895339Sjake			continue;
40995339Sjake		fs_off = ph.p_offset;
41095339Sjake		p = (caddr_t)ph.p_vaddr;
41195339Sjake		if (fsread(ino, p, ph.p_filesz) != ph.p_filesz) {
41295339Sjake			printf("Can't read content of section %d\n", i);
41391295Srobert			return;
41491295Srobert		}
41595339Sjake		if (ph.p_filesz != ph.p_memsz)
41695340Sjake			bzero(p + ph.p_filesz, ph.p_memsz - ph.p_filesz);
41791295Srobert	}
41891295Srobert	ofw_close(bootdevh);
41995339Sjake	(*(void (*)(int, int, int, int, ofwfp_t))eh.e_entry)(0, 0, 0, 0, ofw);
42090699Srobert}
42190699Srobert
42290699Srobertstatic ino_t
42390699Srobertlookup(const char *path)
42490699Srobert{
42591295Srobert	char name[MAXNAMLEN + 1];
42691295Srobert	const char *s;
42791295Srobert	ino_t ino;
42891295Srobert	ssize_t n;
42991295Srobert	int dt;
43090699Srobert
43191295Srobert	ino = ROOTINO;
43291295Srobert	dt = DT_DIR;
43391678Srobert	name[0] = '/';
43491678Srobert	name[1] = '\0';
43591295Srobert	for (;;) {
43691295Srobert		if (*path == '/')
43791295Srobert			path++;
43891295Srobert		if (!*path)
43991295Srobert			break;
44091295Srobert		for (s = path; *s && *s != '/'; s++)
44191295Srobert			;
44291295Srobert		if ((n = s - path) > MAXNAMLEN)
44391295Srobert			return (0);
44495340Sjake		bcopy(path, name, n);
44591295Srobert		name[n] = 0;
44691678Srobert		if (dt != DT_DIR) {
44791678Srobert			printf("%s: not a directory.\n", name);
44891678Srobert			return (0);
44991678Srobert		}
45091295Srobert		if ((dt = fsfind(name, &ino)) <= 0)
45191295Srobert			break;
45291295Srobert		path = s;
45391295Srobert	}
45491295Srobert	return (dt == DT_REG ? ino : 0);
45590699Srobert}
45690699Srobert
45790699Srobertstatic ssize_t
45890699Srobertfsread(ino_t inode, void *buf, size_t nbyte)
45990699Srobert{
46091295Srobert	static struct fs fs;
46191295Srobert	static struct dinode din;
46295337Sjake	static char blkbuf[BSIZEMAX];
46395337Sjake	static ufs_daddr_t indbuf[BSIZEMAX / sizeof(ufs_daddr_t)];
46491295Srobert	static ino_t inomap;
46591295Srobert	static ufs_daddr_t blkmap, indmap;
46691295Srobert	static unsigned int fsblks;
46791295Srobert	char *s;
46891295Srobert	ufs_daddr_t lbn, addr;
46991295Srobert	size_t n, nb, off;
47090699Srobert
47191295Srobert	if (!dsk.meta) {
47291295Srobert		inomap = 0;
47391295Srobert		if (dskread(blkbuf, SBOFF / DEV_BSIZE, SBSIZE / DEV_BSIZE))
47491295Srobert			return (-1);
47595340Sjake		bcopy(blkbuf, &fs, sizeof(fs));
47691295Srobert		if (fs.fs_magic != FS_MAGIC) {
47791295Srobert			printf("Not ufs\n");
47895337Sjake			return (-1);
47991295Srobert		}
48091295Srobert		fsblks = fs.fs_bsize >> DEV_BSHIFT;
48191295Srobert		dsk.meta++;
48290699Srobert	}
48391295Srobert	if (!inode)
48491295Srobert		return (0);
48591295Srobert	if (inomap != inode) {
48691295Srobert		if (dskread(blkbuf, fsbtodb(&fs, ino_to_fsba(&fs, inode)),
48790699Srobert		    fsblks))
48891295Srobert			return (-1);
48995340Sjake		bcopy(blkbuf + ((inode % INOPB(&fs)) * sizeof(din)), &din,
49095340Sjake		    sizeof(din));
49191295Srobert		inomap = inode;
49291295Srobert		fs_off = 0;
49391295Srobert		blkmap = indmap = 0;
49490699Srobert	}
49591295Srobert	s = buf;
49691295Srobert	if (nbyte > (n = din.di_size - fs_off))
49791295Srobert		nbyte = n;
49891295Srobert	nb = nbyte;
49991295Srobert	while (nb) {
50091295Srobert		lbn = lblkno(&fs, fs_off);
50191295Srobert		if (lbn < NDADDR)
50291295Srobert			addr = din.di_db[lbn];
50391295Srobert		else {
50491295Srobert			if (indmap != din.di_ib[0]) {
50591295Srobert				if (dskread(indbuf, fsbtodb(&fs, din.di_ib[0]),
50691295Srobert				    fsblks))
50791295Srobert					return (-1);
50891295Srobert				indmap = din.di_ib[0];
50991295Srobert			}
51091295Srobert			addr = indbuf[(lbn - NDADDR) % NINDIR(&fs)];
51191295Srobert		}
51291295Srobert		n = dblksize(&fs, &din, lbn);
51391295Srobert		if (blkmap != addr) {
51491295Srobert			if (dskread(blkbuf, fsbtodb(&fs, addr),
51591295Srobert			    n >> DEV_BSHIFT)) {
51691295Srobert				return (-1);
51791295Srobert			}
51891295Srobert			blkmap = addr;
51991295Srobert		}
52091295Srobert		off = blkoff(&fs, fs_off);
52191295Srobert		n -= off;
52291295Srobert		if (n > nb)
52391295Srobert			n = nb;
52495340Sjake		bcopy(blkbuf + off, s, n);
52591295Srobert		s += n;
52691295Srobert		fs_off += n;
52791295Srobert		nb -= n;
52890699Srobert	}
52991295Srobert	return (nbyte);
53090699Srobert}
53190699Srobert
53290699Srobertstatic int
53390699Srobertdskread(void *buf, u_int64_t lba, int nblk)
53490699Srobert{
53591295Srobert	/*
53691295Srobert	 * The OpenFirmware should open the correct partition for us.
53791295Srobert	 * That means, if we read from offset zero on an open instance handle,
53891295Srobert	 * we should read from offset zero of that partition.
53991295Srobert	 */
54091295Srobert	ofw_seek(bootdevh, lba * DEV_BSIZE);
54191295Srobert	ofw_read(bootdevh, buf, nblk * DEV_BSIZE);
54291295Srobert	return (0);
54390699Srobert}
54490699Srobert
54590699Srobertstatic int
54695346Sjakeprintf(const char *fmt, ...)
54790699Srobert{
54891295Srobert	va_list ap;
54995346Sjake	int ret;
55095346Sjake
55195346Sjake	va_start(ap, fmt);
55295346Sjake	ret = vprintf(fmt, ap);
55395346Sjake	va_end(ap);
55495346Sjake	return (ret);
55595346Sjake}
55695346Sjake
55795346Sjakestatic int
55895346Sjakevprintf(const char *fmt, va_list ap)
55995346Sjake{
56095346Sjake	int ret;
56195346Sjake
56295346Sjake	ret = __printf(fmt, putchar, 0, ap);
56395346Sjake	return (ret);
56495346Sjake}
56595346Sjake
56695346Sjakestatic int
56795346Sjakeputchar(int c, void *arg)
56895346Sjake{
56995346Sjake	char buf;
57095346Sjake
57195346Sjake	if (c == '\n') {
57295346Sjake		buf = '\r';
57395346Sjake		ofw_write(stdouth, &buf, 1);
57495346Sjake	}
57595346Sjake	buf = c;
57695346Sjake	ofw_write(stdouth, &buf, 1);
57795346Sjake	return (1);
57895346Sjake}
57995346Sjake
58095346Sjakestatic int
58195346Sjake__printf(const char *fmt, putc_func_t *putc, void *arg, va_list ap)
58295346Sjake{
58395346Sjake	char buf[(sizeof(long) * 8) + 1];
58495346Sjake	char *nbuf;
58595346Sjake	u_long ul;
58695346Sjake	u_int ui;
58795346Sjake	int lflag;
58895346Sjake	int sflag;
58991295Srobert	char *s;
59095346Sjake	int pad;
59195346Sjake	int ret;
59295346Sjake	int c;
59390699Srobert
59495346Sjake	nbuf = &buf[sizeof buf - 1];
59595346Sjake	ret = 0;
59695346Sjake	while ((c = *fmt++) != 0) {
59795346Sjake		if (c != '%') {
59895346Sjake			ret += putc(c, arg);
59995346Sjake			continue;
60095346Sjake		}
60195346Sjake		lflag = 0;
60295346Sjake		sflag = 0;
60395346Sjake		pad = 0;
60495346Sjakereswitch:	c = *fmt++;
60595346Sjake		switch (c) {
60695346Sjake		case '#':
60795346Sjake			sflag = 1;
60895346Sjake			goto reswitch;
60995346Sjake		case '%':
61095346Sjake			ret += putc('%', arg);
61195346Sjake			break;
61295346Sjake		case 'c':
61395346Sjake			c = va_arg(ap, int);
61495346Sjake			ret += putc(c, arg);
61595346Sjake			break;
61695346Sjake		case 'd':
61795346Sjake			if (lflag == 0) {
61895346Sjake				ui = (u_int)va_arg(ap, int);
61995346Sjake				if (ui < (int)ui) {
62095346Sjake					ui = -ui;
62195346Sjake					ret += putc('-', arg);
62291295Srobert				}
62395346Sjake				s = __uitoa(nbuf, ui, 10);
62495346Sjake			} else {
62595346Sjake				ul = (u_long)va_arg(ap, long);
62695346Sjake				if (ul < (long)ul) {
62795346Sjake					ul = -ul;
62895346Sjake					ret += putc('-', arg);
62995346Sjake				}
63095346Sjake				s = __ultoa(nbuf, ul, 10);
63191295Srobert			}
63295346Sjake			ret += __puts(s, putc, arg);
63395346Sjake			break;
63495346Sjake		case 'l':
63595346Sjake			lflag = 1;
63695346Sjake			goto reswitch;
63795346Sjake		case 'o':
63895346Sjake			if (lflag == 0) {
63995346Sjake				ui = (u_int)va_arg(ap, u_int);
64095346Sjake				s = __uitoa(nbuf, ui, 8);
64195346Sjake			} else {
64295346Sjake				ul = (u_long)va_arg(ap, u_long);
64395346Sjake				s = __ultoa(nbuf, ul, 8);
64495346Sjake			}
64595346Sjake			ret += __puts(s, putc, arg);
64695346Sjake			break;
64795346Sjake		case 'p':
64895346Sjake			ul = (u_long)va_arg(ap, void *);
64995346Sjake			s = __ultoa(nbuf, ul, 16);
65095346Sjake			ret += __puts("0x", putc, arg);
65195346Sjake			ret += __puts(s, putc, arg);
65295346Sjake			break;
65395346Sjake		case 's':
65495346Sjake			s = va_arg(ap, char *);
65595346Sjake			ret += __puts(s, putc, arg);
65695346Sjake			break;
65795346Sjake		case 'u':
65895346Sjake			if (lflag == 0) {
65995346Sjake				ui = va_arg(ap, u_int);
66095346Sjake				s = __uitoa(nbuf, ui, 10);
66195346Sjake			} else {
66295346Sjake				ul = va_arg(ap, u_long);
66395346Sjake				s = __ultoa(nbuf, ul, 10);
66495346Sjake			}
66595346Sjake			ret += __puts(s, putc, arg);
66695346Sjake			break;
66795346Sjake		case 'x':
66895346Sjake			if (lflag == 0) {
66995346Sjake				ui = va_arg(ap, u_int);
67095346Sjake				s = __uitoa(nbuf, ui, 16);
67195346Sjake			} else {
67295346Sjake				ul = va_arg(ap, u_long);
67395346Sjake				s = __ultoa(nbuf, ul, 16);
67495346Sjake			}
67595346Sjake			if (sflag)
67695346Sjake				ret += __puts("0x", putc, arg);
67795346Sjake			ret += __puts(s, putc, arg);
67895346Sjake			break;
67995346Sjake		case '0': case '1': case '2': case '3': case '4':
68095346Sjake		case '5': case '6': case '7': case '8': case '9':
68195346Sjake			pad = pad * 10 + c - '0';
68295346Sjake			goto reswitch;
68395346Sjake		default:
68495346Sjake			break;
68590699Srobert		}
68690699Srobert	}
68795346Sjake	return (ret);
68890699Srobert}
68990699Srobert
69090699Srobertstatic int
69195346Sjake__puts(const char *s, putc_func_t *putc, void *arg)
69290699Srobert{
69395346Sjake	const char *p;
69495346Sjake	int ret;
69595346Sjake
69695346Sjake	ret = 0;
69795346Sjake	for (p = s; *p != '\0'; p++)
69895346Sjake		ret += putc(*p, arg);
69995346Sjake	return (ret);
70090699Srobert}
70195346Sjake
70295346Sjakestatic char *
70395346Sjake__uitoa(char *buf, u_int ui, int base)
70495346Sjake{
70595346Sjake	char *p;
70695346Sjake
70795346Sjake	p = buf;
70895346Sjake	*p = '\0';
70995346Sjake	do
71095346Sjake		*--p = digits[ui % base];
71195346Sjake	while ((ui /= base) != 0);
71295346Sjake	return (p);
71395346Sjake}
71495346Sjake
71595346Sjakestatic char *
71695346Sjake__ultoa(char *buf, u_long ul, int base)
71795346Sjake{
71895346Sjake	char *p;
71995346Sjake
72095346Sjake	p = buf;
72195346Sjake	*p = '\0';
72295346Sjake	do
72395346Sjake		*--p = digits[ul % base];
72495346Sjake	while ((ul /= base) != 0);
72595346Sjake	return (p);
72695346Sjake}
727