1139738Simp/*-
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 */
1791295Srobert
1891295Srobert#include <sys/cdefs.h>
1991295Srobert__FBSDID("$FreeBSD: stable/11/stand/sparc64/boot1/boot1.c 332154 2018-04-06 21:37:25Z kevans $");
2091295Srobert
2190699Srobert#include <sys/param.h>
2290699Srobert#include <sys/dirent.h>
23234898Smarius
2490699Srobert#include <machine/elf.h>
2590699Srobert#include <machine/stdarg.h>
2690699Srobert
27294765Simp#include "paths.h"
28294765Simp
29234898Smarius#define	READ_BUF_SIZE	8192
3090699Srobert
31212729Smariustypedef int putc_func_t(char c, void *arg);
3295351Sjaketypedef int32_t ofwh_t;
3395351Sjake
3495351Sjakestruct sp_data {
3595351Sjake	char	*sp_buf;
3695351Sjake	u_int	sp_len;
3795351Sjake	u_int	sp_size;
3890699Srobert};
3990699Srobert
4095346Sjakestatic const char digits[] = "0123456789abcdef";
4190699Srobert
4295346Sjakestatic char bootpath[128];
4395346Sjakestatic char bootargs[128];
4495346Sjake
4595351Sjakestatic ofwh_t bootdev;
4695346Sjake
4790699Srobertstatic uint32_t fs_off;
4890699Srobert
4995346Sjakeint main(int ac, char **av);
50234898Smariusstatic void exit(int) __dead2;
51234898Smariusstatic void usage(void);
5295346Sjake
53234898Smarius#ifdef ZFSBOOT
54234898Smariusstatic void loadzfs(void);
55234898Smariusstatic int zbread(char *buf, off_t off, size_t bytes);
56234898Smarius#else
5790699Srobertstatic void load(const char *);
58234898Smarius#endif
5990699Srobert
6095340Sjakestatic void bcopy(const void *src, void *dst, size_t len);
6195340Sjakestatic void bzero(void *b, size_t len);
6290699Srobert
63243305Smariusstatic int domount(const char *device);
64332154Skevansstatic int dskread(void *buf, uint64_t lba, int nblk);
6595351Sjake
6695351Sjakestatic void panic(const char *fmt, ...) __dead2;
6795346Sjakestatic int printf(const char *fmt, ...);
68212729Smariusstatic int putchar(char c, void *arg);
6995346Sjakestatic int vprintf(const char *fmt, va_list ap);
7095351Sjakestatic int vsnprintf(char *str, size_t sz, const char *fmt, va_list ap);
7195346Sjake
7295346Sjakestatic int __printf(const char *fmt, putc_func_t *putc, void *arg, va_list ap);
7395346Sjakestatic int __puts(const char *s, putc_func_t *putc, void *arg);
74212729Smariusstatic int __sputc(char c, void *arg);
7595346Sjakestatic char *__uitoa(char *buf, u_int val, int base);
7695346Sjakestatic char *__ultoa(char *buf, u_long val, int base);
7795346Sjake
7890699Srobert/*
7990699Srobert * Open Firmware interface functions
8090699Srobert */
81332154Skevanstypedef uint64_t	ofwcell_t;
82332154Skevanstypedef uint32_t	u_ofwh_t;
8390699Sroberttypedef int (*ofwfp_t)(ofwcell_t []);
84212729Smariusstatic ofwfp_t ofw;			/* the PROM Open Firmware entry */
8590699Srobert
8690699Srobertvoid ofw_init(int, int, int, int, ofwfp_t);
87212729Smariusstatic ofwh_t ofw_finddevice(const char *);
88212729Smariusstatic ofwh_t ofw_open(const char *);
89212729Smariusstatic int ofw_getprop(ofwh_t, const char *, void *, size_t);
90212729Smariusstatic int ofw_read(ofwh_t, void *, size_t);
91212729Smariusstatic int ofw_write(ofwh_t, const void *, size_t);
92332154Skevansstatic int ofw_seek(ofwh_t, uint64_t);
93212729Smariusstatic void ofw_exit(void) __dead2;
9490699Srobert
95212729Smariusstatic ofwh_t stdinh, stdouth;
9690699Srobert
9790699Srobert/*
9890699Srobert * This has to stay here, as the PROM seems to ignore the
9990699Srobert * entry point specified in the a.out header.  (or elftoaout is broken)
10090699Srobert */
10190699Srobert
10290699Srobertvoid
10390699Srobertofw_init(int d, int d1, int d2, int d3, ofwfp_t ofwaddr)
10490699Srobert{
10590699Srobert	ofwh_t chosenh;
10695346Sjake	char *av[16];
10795346Sjake	char *p;
10895346Sjake	int ac;
10990699Srobert
11090699Srobert	ofw = ofwaddr;
11190699Srobert
11290699Srobert	chosenh = ofw_finddevice("/chosen");
11390699Srobert	ofw_getprop(chosenh, "stdin", &stdinh, sizeof(stdinh));
11490699Srobert	ofw_getprop(chosenh, "stdout", &stdouth, sizeof(stdouth));
11595346Sjake	ofw_getprop(chosenh, "bootargs", bootargs, sizeof(bootargs));
11690699Srobert	ofw_getprop(chosenh, "bootpath", bootpath, sizeof(bootpath));
11790699Srobert
11895346Sjake	bootargs[sizeof(bootargs) - 1] = '\0';
11995346Sjake	bootpath[sizeof(bootpath) - 1] = '\0';
12095346Sjake
12195346Sjake	ac = 0;
12295346Sjake	p = bootargs;
12395346Sjake	for (;;) {
12495346Sjake		while (*p == ' ' && *p != '\0')
12595346Sjake			p++;
12695346Sjake		if (*p == '\0' || ac >= 16)
12795346Sjake			break;
12895346Sjake		av[ac++] = p;
12995346Sjake		while (*p != ' ' && *p != '\0')
13095346Sjake			p++;
13195346Sjake		if (*p != '\0')
13295346Sjake			*p++ = '\0';
13395346Sjake	}
13495346Sjake
13595346Sjake	exit(main(ac, av));
13690699Srobert}
13790699Srobert
138212729Smariusstatic ofwh_t
13990699Srobertofw_finddevice(const char *name)
14090699Srobert{
14191295Srobert	ofwcell_t args[] = {
14291295Srobert		(ofwcell_t)"finddevice",
14391295Srobert		1,
14491295Srobert		1,
14591295Srobert		(ofwcell_t)name,
14691295Srobert		0
14791295Srobert	};
14891295Srobert
14991295Srobert	if ((*ofw)(args)) {
15091295Srobert		printf("ofw_finddevice: name=\"%s\"\n", name);
15191295Srobert		return (1);
15291295Srobert	}
15391295Srobert	return (args[4]);
15490699Srobert}
15590699Srobert
156212729Smariusstatic int
15790699Srobertofw_getprop(ofwh_t ofwh, const char *name, void *buf, size_t len)
15890699Srobert{
15991295Srobert	ofwcell_t args[] = {
16091295Srobert		(ofwcell_t)"getprop",
16191295Srobert		4,
16291295Srobert		1,
16391295Srobert		(u_ofwh_t)ofwh,
16491295Srobert		(ofwcell_t)name,
16591295Srobert		(ofwcell_t)buf,
16691295Srobert		len,
16790699Srobert	0
16891295Srobert	};
16991295Srobert
17091295Srobert	if ((*ofw)(args)) {
17191295Srobert		printf("ofw_getprop: ofwh=0x%x buf=%p len=%u\n",
17291295Srobert			ofwh, buf, len);
17391295Srobert		return (1);
17491295Srobert	}
17591295Srobert	return (0);
17690699Srobert}
17790699Srobert
178212729Smariusstatic ofwh_t
17990699Srobertofw_open(const char *path)
18090699Srobert{
18191295Srobert	ofwcell_t args[] = {
18291295Srobert		(ofwcell_t)"open",
18391295Srobert		1,
18491295Srobert		1,
18591295Srobert		(ofwcell_t)path,
18691295Srobert		0
18791295Srobert	};
18891295Srobert
18991295Srobert	if ((*ofw)(args)) {
19091295Srobert		printf("ofw_open: path=\"%s\"\n", path);
19191295Srobert		return (-1);
19291295Srobert	}
19391295Srobert	return (args[4]);
19490699Srobert}
19590699Srobert
196212729Smariusstatic int
19790699Srobertofw_close(ofwh_t devh)
19890699Srobert{
19991295Srobert	ofwcell_t args[] = {
20091295Srobert		(ofwcell_t)"close",
20191295Srobert		1,
20291295Srobert		0,
20391295Srobert		(u_ofwh_t)devh
20491295Srobert	};
20591295Srobert
20691295Srobert	if ((*ofw)(args)) {
20791295Srobert		printf("ofw_close: devh=0x%x\n", devh);
20891295Srobert		return (1);
20991295Srobert	}
21091295Srobert	return (0);
21190699Srobert}
21290699Srobert
213212729Smariusstatic int
21490699Srobertofw_read(ofwh_t devh, void *buf, size_t len)
21590699Srobert{
21691295Srobert	ofwcell_t args[] = {
21791295Srobert		(ofwcell_t)"read",
218212729Smarius		3,
21991295Srobert		1,
22091295Srobert		(u_ofwh_t)devh,
22191295Srobert		(ofwcell_t)buf,
22291295Srobert		len,
22391295Srobert		0
22491295Srobert	};
22591295Srobert
22691295Srobert	if ((*ofw)(args)) {
22791295Srobert		printf("ofw_read: devh=0x%x buf=%p len=%u\n", devh, buf, len);
22891295Srobert		return (1);
22991295Srobert	}
23091295Srobert	return (0);
23190699Srobert}
23290699Srobert
233212729Smariusstatic int
23490699Srobertofw_write(ofwh_t devh, const void *buf, size_t len)
23590699Srobert{
23691295Srobert	ofwcell_t args[] = {
23791295Srobert		(ofwcell_t)"write",
23891295Srobert		3,
23991295Srobert		1,
24091295Srobert		(u_ofwh_t)devh,
24191295Srobert		(ofwcell_t)buf,
24291295Srobert		len,
24391295Srobert		0
24491295Srobert	};
24591295Srobert
24691295Srobert	if ((*ofw)(args)) {
24791295Srobert		printf("ofw_write: devh=0x%x buf=%p len=%u\n", devh, buf, len);
24891295Srobert		return (1);
24991295Srobert	}
25091295Srobert	return (0);
25190699Srobert}
25290699Srobert
253212729Smariusstatic int
254332154Skevansofw_seek(ofwh_t devh, uint64_t off)
25590699Srobert{
25691295Srobert	ofwcell_t args[] = {
25791295Srobert		(ofwcell_t)"seek",
258212729Smarius		3,
25991295Srobert		1,
26091295Srobert		(u_ofwh_t)devh,
26191295Srobert		off >> 32,
26291678Srobert		off,
26391295Srobert		0
26491295Srobert	};
26591295Srobert
26691295Srobert	if ((*ofw)(args)) {
26791295Srobert		printf("ofw_seek: devh=0x%x off=0x%lx\n", devh, off);
26891295Srobert		return (1);
26991295Srobert	}
27091295Srobert	return (0);
27190699Srobert}
27290699Srobert
273212729Smariusstatic void
27495342Sjakeofw_exit(void)
27595342Sjake{
27695342Sjake	ofwcell_t args[3];
27795342Sjake
27895342Sjake	args[0] = (ofwcell_t)"exit";
27995342Sjake	args[1] = 0;
28095342Sjake	args[2] = 0;
28195342Sjake
28295351Sjake	for (;;)
28395351Sjake		(*ofw)(args);
28495342Sjake}
28595342Sjake
28695340Sjakestatic void
28797863Sphkbcopy(const void *src, void *dst, size_t len)
28895340Sjake{
28997863Sphk	const char *s = src;
29097863Sphk	char *d = dst;
29195340Sjake
29295340Sjake	while (len-- != 0)
29397863Sphk		*d++ = *s++;
29495340Sjake}
29595340Sjake
29695340Sjakestatic void
29797864Sphkmemcpy(void *dst, const void *src, size_t len)
29897864Sphk{
299212729Smarius
30097864Sphk	bcopy(src, dst, len);
30197864Sphk}
30297864Sphk
30397864Sphkstatic 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{
315212729Smarius
31691295Srobert	for (; *s1 == *s2 && *s1; s1++, s2++)
31791295Srobert		;
31891295Srobert	return ((u_char)*s1 - (u_char)*s2);
31990699Srobert}
32090699Srobert
32195346Sjakeint
32295346Sjakemain(int ac, char **av)
32390699Srobert{
32495346Sjake	const char *path;
32595346Sjake	int i;
32691295Srobert
327294765Simp	path = PATH_LOADER;
32895346Sjake	for (i = 0; i < ac; i++) {
32995346Sjake		switch (av[i][0]) {
33095346Sjake		case '-':
33195346Sjake			switch (av[i][1]) {
33295346Sjake			default:
33395351Sjake				usage();
33495346Sjake			}
33595346Sjake			break;
33695346Sjake		default:
33795346Sjake			path = av[i];
33895346Sjake			break;
33995346Sjake		}
34095346Sjake	}
34190699Srobert
342234898Smarius#ifdef ZFSBOOT
343244307Smarius	printf(" \n>> FreeBSD/sparc64 ZFS boot block\n   Boot path:   %s\n",
344234898Smarius	    bootpath);
345234898Smarius#else
346244307Smarius	printf(" \n>> FreeBSD/sparc64 boot block\n   Boot path:   %s\n"
347244307Smarius	    "   Boot loader: %s\n", bootpath, path);
348234898Smarius#endif
34995351Sjake
350243305Smarius	if (domount(bootpath) == -1)
351243305Smarius		panic("domount");
35295351Sjake
353234898Smarius#ifdef ZFSBOOT
354234898Smarius	loadzfs();
355234898Smarius#else
35695346Sjake	load(path);
357234898Smarius#endif
35891295Srobert	return (1);
35990699Srobert}
36090699Srobert
36190699Srobertstatic void
36295351Sjakeusage(void)
36395351Sjake{
36495351Sjake
36595351Sjake	printf("usage: boot device [/path/to/loader]\n");
36695351Sjake	exit(1);
36795351Sjake}
36895351Sjake
36995351Sjakestatic void
37095342Sjakeexit(int code)
37195342Sjake{
37295342Sjake
37395342Sjake	ofw_exit();
37495342Sjake}
37595342Sjake
376234898Smarius#ifdef ZFSBOOT
37797864Sphk
378234898Smarius#define	VDEV_BOOT_OFFSET	(2 * 256 * 1024)
379234898Smariusstatic char zbuf[READ_BUF_SIZE];
380234898Smarius
38195351Sjakestatic int
382234898Smariuszbread(char *buf, off_t off, size_t bytes)
38395351Sjake{
384234898Smarius	size_t len;
385234898Smarius	off_t poff;
386234898Smarius	off_t soff;
387234898Smarius	char *p;
388234898Smarius	unsigned int nb;
389234898Smarius	unsigned int lb;
39095351Sjake
391234898Smarius	p = buf;
392234898Smarius	soff = VDEV_BOOT_OFFSET + off;
393298645Spfg	lb = howmany(soff + bytes, DEV_BSIZE);
394234898Smarius	poff = soff;
395234898Smarius	while (poff < soff + bytes) {
396234898Smarius		nb = lb - poff / DEV_BSIZE;
397234898Smarius		if (nb > READ_BUF_SIZE / DEV_BSIZE)
398234898Smarius			nb = READ_BUF_SIZE / DEV_BSIZE;
399234898Smarius		if (dskread(zbuf, poff / DEV_BSIZE, nb))
400234898Smarius			break;
401234898Smarius		if ((poff / DEV_BSIZE + nb) * DEV_BSIZE > soff + bytes)
402234898Smarius			len = soff + bytes - poff;
403234898Smarius		else
404234898Smarius			len = (poff / DEV_BSIZE + nb) * DEV_BSIZE - poff;
405234898Smarius		memcpy(p, zbuf + poff % DEV_BSIZE, len);
406234898Smarius		p += len;
407234898Smarius		poff += len;
40895351Sjake	}
409234898Smarius	return (poff - soff);
410234898Smarius}
411234898Smarius
412234898Smariusstatic void
413234898Smariusloadzfs(void)
414234898Smarius{
415234898Smarius	Elf64_Ehdr eh;
416234898Smarius	Elf64_Phdr ph;
417234898Smarius	caddr_t p;
418234898Smarius	int i;
419234898Smarius
420234898Smarius	if (zbread((char *)&eh, 0, sizeof(eh)) != sizeof(eh)) {
421234898Smarius		printf("Can't read elf header\n");
422234898Smarius		return;
42395351Sjake	}
424234898Smarius	if (!IS_ELF(eh)) {
425234898Smarius		printf("Not an ELF file\n");
426234898Smarius		return;
427234898Smarius	}
428234898Smarius	for (i = 0; i < eh.e_phnum; i++) {
429234898Smarius		fs_off = eh.e_phoff + i * eh.e_phentsize;
430234898Smarius		if (zbread((char *)&ph, fs_off, sizeof(ph)) != sizeof(ph)) {
431234898Smarius			printf("Can't read program header %d\n", i);
432234898Smarius			return;
433234898Smarius		}
434234898Smarius		if (ph.p_type != PT_LOAD)
435234898Smarius			continue;
436234898Smarius		fs_off = ph.p_offset;
437234898Smarius		p = (caddr_t)ph.p_vaddr;
438234898Smarius		if (zbread(p, fs_off, ph.p_filesz) != ph.p_filesz) {
439234898Smarius			printf("Can't read content of section %d\n", i);
440234898Smarius			return;
441234898Smarius		}
442234898Smarius		if (ph.p_filesz != ph.p_memsz)
443234898Smarius			bzero(p + ph.p_filesz, ph.p_memsz - ph.p_filesz);
444234898Smarius	}
445234898Smarius	ofw_close(bootdev);
446234898Smarius	(*(void (*)(int, int, int, int, ofwfp_t))eh.e_entry)(0, 0, 0, 0, ofw);
44795351Sjake}
44895351Sjake
449234898Smarius#else
450234898Smarius
451234898Smarius#include "ufsread.c"
452234898Smarius
453234898Smariusstatic struct dmadat __dmadat;
454234898Smarius
45595342Sjakestatic void
45690699Srobertload(const char *fname)
45790699Srobert{
45891295Srobert	Elf64_Ehdr eh;
45995339Sjake	Elf64_Phdr ph;
46091295Srobert	caddr_t p;
461235988Sgleb	ufs_ino_t ino;
46295339Sjake	int i;
46390699Srobert
46491295Srobert	if ((ino = lookup(fname)) == 0) {
46595337Sjake		printf("File %s not found\n", fname);
46690699Srobert		return;
46790699Srobert	}
46895339Sjake	if (fsread(ino, &eh, sizeof(eh)) != sizeof(eh)) {
46995339Sjake		printf("Can't read elf header\n");
47091295Srobert		return;
47195339Sjake	}
47291295Srobert	if (!IS_ELF(eh)) {
47391295Srobert		printf("Not an ELF file\n");
47491295Srobert		return;
47591295Srobert	}
47695339Sjake	for (i = 0; i < eh.e_phnum; i++) {
47795339Sjake		fs_off = eh.e_phoff + i * eh.e_phentsize;
47895339Sjake		if (fsread(ino, &ph, sizeof(ph)) != sizeof(ph)) {
47995339Sjake			printf("Can't read program header %d\n", i);
48091295Srobert			return;
48191295Srobert		}
48295339Sjake		if (ph.p_type != PT_LOAD)
48395339Sjake			continue;
48495339Sjake		fs_off = ph.p_offset;
48595339Sjake		p = (caddr_t)ph.p_vaddr;
48695339Sjake		if (fsread(ino, p, ph.p_filesz) != ph.p_filesz) {
48795339Sjake			printf("Can't read content of section %d\n", i);
48891295Srobert			return;
48991295Srobert		}
49095339Sjake		if (ph.p_filesz != ph.p_memsz)
49195340Sjake			bzero(p + ph.p_filesz, ph.p_memsz - ph.p_filesz);
49291295Srobert	}
49395351Sjake	ofw_close(bootdev);
49495339Sjake	(*(void (*)(int, int, int, int, ofwfp_t))eh.e_entry)(0, 0, 0, 0, ofw);
49590699Srobert}
49690699Srobert
497234898Smarius#endif /* ZFSBOOT */
498234898Smarius
49990699Srobertstatic int
500243305Smariusdomount(const char *device)
501234898Smarius{
502234898Smarius
503234898Smarius	if ((bootdev = ofw_open(device)) == -1) {
504243305Smarius		printf("domount: can't open device\n");
505234898Smarius		return (-1);
506234898Smarius	}
507234898Smarius#ifndef ZFSBOOT
508234898Smarius	dmadat = &__dmadat;
509234898Smarius	if (fsread(0, NULL, 0)) {
510243305Smarius		printf("domount: can't read superblock\n");
511234898Smarius		return (-1);
512234898Smarius	}
513234898Smarius#endif
514234898Smarius	return (0);
515234898Smarius}
516234898Smarius
517234898Smariusstatic int
518332154Skevansdskread(void *buf, uint64_t lba, int nblk)
51990699Srobert{
520212729Smarius
52191295Srobert	/*
522133862Smarius	 * The Open Firmware should open the correct partition for us.
52391295Srobert	 * That means, if we read from offset zero on an open instance handle,
52491295Srobert	 * we should read from offset zero of that partition.
52591295Srobert	 */
52695351Sjake	ofw_seek(bootdev, lba * DEV_BSIZE);
52795351Sjake	ofw_read(bootdev, buf, nblk * DEV_BSIZE);
52891295Srobert	return (0);
52990699Srobert}
53090699Srobert
53195351Sjakestatic void
53295351Sjakepanic(const char *fmt, ...)
53390699Srobert{
53495351Sjake	char buf[128];
53591295Srobert	va_list ap;
53695346Sjake
53795346Sjake	va_start(ap, fmt);
53895351Sjake	vsnprintf(buf, sizeof buf, fmt, ap);
53995351Sjake	printf("panic: %s\n", buf);
54095346Sjake	va_end(ap);
54195351Sjake
54295351Sjake	exit(1);
54395346Sjake}
54495346Sjake
54595346Sjakestatic int
54695351Sjakeprintf(const char *fmt, ...)
54795346Sjake{
54895351Sjake	va_list ap;
54995346Sjake	int ret;
55095346Sjake
55195351Sjake	va_start(ap, fmt);
55295351Sjake	ret = vprintf(fmt, ap);
55395351Sjake	va_end(ap);
55495346Sjake	return (ret);
55595346Sjake}
55695346Sjake
55795346Sjakestatic int
558212729Smariusputchar(char c, void *arg)
55995346Sjake{
56095346Sjake	char buf;
56195346Sjake
56295346Sjake	if (c == '\n') {
56395346Sjake		buf = '\r';
56495346Sjake		ofw_write(stdouth, &buf, 1);
56595346Sjake	}
56695346Sjake	buf = c;
56795346Sjake	ofw_write(stdouth, &buf, 1);
56895346Sjake	return (1);
56995346Sjake}
57095346Sjake
57195346Sjakestatic int
57295351Sjakevprintf(const char *fmt, va_list ap)
57395351Sjake{
57495351Sjake	int ret;
57595351Sjake
57695351Sjake	ret = __printf(fmt, putchar, 0, ap);
57795351Sjake	return (ret);
57895351Sjake}
57995351Sjake
58095351Sjakestatic int
58195351Sjakevsnprintf(char *str, size_t sz, const char *fmt, va_list ap)
58295351Sjake{
58395351Sjake	struct sp_data sp;
58495351Sjake	int ret;
58595351Sjake
58695351Sjake	sp.sp_buf = str;
58795351Sjake	sp.sp_len = 0;
58895351Sjake	sp.sp_size = sz;
58995351Sjake	ret = __printf(fmt, __sputc, &sp, ap);
59095351Sjake	return (ret);
59195351Sjake}
59295351Sjake
59395351Sjakestatic int
59495346Sjake__printf(const char *fmt, putc_func_t *putc, void *arg, va_list ap)
59595346Sjake{
59695346Sjake	char buf[(sizeof(long) * 8) + 1];
59795346Sjake	char *nbuf;
59895346Sjake	u_long ul;
59995346Sjake	u_int ui;
60095346Sjake	int lflag;
60195346Sjake	int sflag;
60291295Srobert	char *s;
60395346Sjake	int pad;
60495346Sjake	int ret;
60595346Sjake	int c;
60690699Srobert
60795346Sjake	nbuf = &buf[sizeof buf - 1];
60895346Sjake	ret = 0;
60995346Sjake	while ((c = *fmt++) != 0) {
61095346Sjake		if (c != '%') {
61195346Sjake			ret += putc(c, arg);
61295346Sjake			continue;
61395346Sjake		}
61495346Sjake		lflag = 0;
61595346Sjake		sflag = 0;
61695346Sjake		pad = 0;
61795346Sjakereswitch:	c = *fmt++;
61895346Sjake		switch (c) {
61995346Sjake		case '#':
62095346Sjake			sflag = 1;
62195346Sjake			goto reswitch;
62295346Sjake		case '%':
62395346Sjake			ret += putc('%', arg);
62495346Sjake			break;
62595346Sjake		case 'c':
62695346Sjake			c = va_arg(ap, int);
62795346Sjake			ret += putc(c, arg);
62895346Sjake			break;
62995346Sjake		case 'd':
63095346Sjake			if (lflag == 0) {
63195346Sjake				ui = (u_int)va_arg(ap, int);
63295346Sjake				if (ui < (int)ui) {
63395346Sjake					ui = -ui;
63495346Sjake					ret += putc('-', arg);
63591295Srobert				}
63695346Sjake				s = __uitoa(nbuf, ui, 10);
63795346Sjake			} else {
63895346Sjake				ul = (u_long)va_arg(ap, long);
63995346Sjake				if (ul < (long)ul) {
64095346Sjake					ul = -ul;
64195346Sjake					ret += putc('-', arg);
64295346Sjake				}
64395346Sjake				s = __ultoa(nbuf, ul, 10);
64491295Srobert			}
64595346Sjake			ret += __puts(s, putc, arg);
64695346Sjake			break;
64795346Sjake		case 'l':
64895346Sjake			lflag = 1;
64995346Sjake			goto reswitch;
65095346Sjake		case 'o':
65195346Sjake			if (lflag == 0) {
65295346Sjake				ui = (u_int)va_arg(ap, u_int);
65395346Sjake				s = __uitoa(nbuf, ui, 8);
65495346Sjake			} else {
65595346Sjake				ul = (u_long)va_arg(ap, u_long);
65695346Sjake				s = __ultoa(nbuf, ul, 8);
65795346Sjake			}
65895346Sjake			ret += __puts(s, putc, arg);
65995346Sjake			break;
66095346Sjake		case 'p':
66195346Sjake			ul = (u_long)va_arg(ap, void *);
66295346Sjake			s = __ultoa(nbuf, ul, 16);
66395346Sjake			ret += __puts("0x", putc, arg);
66495346Sjake			ret += __puts(s, putc, arg);
66595346Sjake			break;
66695346Sjake		case 's':
66795346Sjake			s = va_arg(ap, char *);
66895346Sjake			ret += __puts(s, putc, arg);
66995346Sjake			break;
67095346Sjake		case 'u':
67195346Sjake			if (lflag == 0) {
67295346Sjake				ui = va_arg(ap, u_int);
67395346Sjake				s = __uitoa(nbuf, ui, 10);
67495346Sjake			} else {
67595346Sjake				ul = va_arg(ap, u_long);
67695346Sjake				s = __ultoa(nbuf, ul, 10);
67795346Sjake			}
67895346Sjake			ret += __puts(s, putc, arg);
67995346Sjake			break;
68095346Sjake		case 'x':
68195346Sjake			if (lflag == 0) {
68295346Sjake				ui = va_arg(ap, u_int);
68395346Sjake				s = __uitoa(nbuf, ui, 16);
68495346Sjake			} else {
68595346Sjake				ul = va_arg(ap, u_long);
68695346Sjake				s = __ultoa(nbuf, ul, 16);
68795346Sjake			}
68895346Sjake			if (sflag)
68995346Sjake				ret += __puts("0x", putc, arg);
69095346Sjake			ret += __puts(s, putc, arg);
69195346Sjake			break;
69295346Sjake		case '0': case '1': case '2': case '3': case '4':
69395346Sjake		case '5': case '6': case '7': case '8': case '9':
69495346Sjake			pad = pad * 10 + c - '0';
69595346Sjake			goto reswitch;
69695346Sjake		default:
69795346Sjake			break;
69890699Srobert		}
69990699Srobert	}
70095346Sjake	return (ret);
70190699Srobert}
70290699Srobert
70390699Srobertstatic int
704212729Smarius__sputc(char c, void *arg)
70595351Sjake{
70695351Sjake	struct sp_data *sp;
70795351Sjake
70895351Sjake	sp = arg;
70995351Sjake	if (sp->sp_len < sp->sp_size)
71095351Sjake		sp->sp_buf[sp->sp_len++] = c;
71195351Sjake	sp->sp_buf[sp->sp_len] = '\0';
71295351Sjake	return (1);
71395351Sjake}
71495351Sjake
71595351Sjakestatic int
71695346Sjake__puts(const char *s, putc_func_t *putc, void *arg)
71790699Srobert{
71895346Sjake	const char *p;
71995346Sjake	int ret;
72095346Sjake
72195346Sjake	ret = 0;
72295346Sjake	for (p = s; *p != '\0'; p++)
72395346Sjake		ret += putc(*p, arg);
72495346Sjake	return (ret);
72590699Srobert}
72695346Sjake
72795346Sjakestatic char *
72895346Sjake__uitoa(char *buf, u_int ui, int base)
72995346Sjake{
73095346Sjake	char *p;
73195346Sjake
73295346Sjake	p = buf;
73395346Sjake	*p = '\0';
73495346Sjake	do
73595346Sjake		*--p = digits[ui % base];
73695346Sjake	while ((ui /= base) != 0);
73795346Sjake	return (p);
73895346Sjake}
73995346Sjake
74095346Sjakestatic char *
74195346Sjake__ultoa(char *buf, u_long ul, int base)
74295346Sjake{
74395346Sjake	char *p;
74495346Sjake
74595346Sjake	p = buf;
74695346Sjake	*p = '\0';
74795346Sjake	do
74895346Sjake		*--p = digits[ul % base];
74995346Sjake	while ((ul /= base) != 0);
75095346Sjake	return (p);
75195346Sjake}
752