boot1.c revision 95351
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 95351 2002-04-24 05:54:10Z 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 3895351Sjaketypedef int putc_func_t(int c, void *arg); 3995351Sjaketypedef int32_t ofwh_t; 4095351Sjake 4195351Sjakestruct sp_data { 4295351Sjake char *sp_buf; 4395351Sjake u_int sp_len; 4495351Sjake u_int sp_size; 4590699Srobert}; 4690699Srobert 4795346Sjakestatic const char digits[] = "0123456789abcdef"; 4890699Srobert 4995346Sjakestatic char bootpath[128]; 5095346Sjakestatic char bootargs[128]; 5195346Sjake 5295351Sjakestatic ofwh_t bootdev; 5395346Sjake 5495351Sjakestatic struct fs fs; 5595351Sjakestatic ino_t inomap; 5695351Sjakestatic char blkbuf[BSIZEMAX]; 5795351Sjakestatic unsigned int fsblks; 5895351Sjake 5990699Srobertstatic uint32_t fs_off; 6090699Srobert 6195346Sjakeint main(int ac, char **av); 6295346Sjake 6395351Sjakestatic void exit(int) __dead2; 6490699Srobertstatic void load(const char *); 6590699Srobertstatic ino_t lookup(const char *); 6690699Srobertstatic ssize_t fsread(ino_t, void *, size_t); 6790699Srobertstatic int dskread(void *, u_int64_t, int); 6890699Srobert 6995351Sjakestatic void usage(void); 7095351Sjake 7195340Sjakestatic void bcopy(const void *src, void *dst, size_t len); 7295340Sjakestatic void bzero(void *b, size_t len); 7390699Srobert 7495351Sjakestatic int mount(const char *device); 7595351Sjake 7695351Sjakestatic void panic(const char *fmt, ...) __dead2; 7795346Sjakestatic int printf(const char *fmt, ...); 7895351Sjakestatic int putchar(int c, void *arg); 7995346Sjakestatic int vprintf(const char *fmt, va_list ap); 8095351Sjakestatic int vsnprintf(char *str, size_t sz, const char *fmt, va_list ap); 8195346Sjake 8295346Sjakestatic int __printf(const char *fmt, putc_func_t *putc, void *arg, va_list ap); 8395346Sjakestatic int __putc(int c, void *arg); 8495346Sjakestatic int __puts(const char *s, putc_func_t *putc, void *arg); 8595351Sjakestatic int __sputc(int c, void *arg); 8695346Sjakestatic char *__uitoa(char *buf, u_int val, int base); 8795346Sjakestatic char *__ultoa(char *buf, u_long val, int base); 8895346Sjake 8990699Srobert/* 9090699Srobert * Open Firmware interface functions 9190699Srobert */ 9290699Sroberttypedef u_int64_t ofwcell_t; 9390699Sroberttypedef u_int32_t u_ofwh_t; 9490699Sroberttypedef int (*ofwfp_t)(ofwcell_t []); 9590699Srobertofwfp_t ofw; /* the prom Open Firmware entry */ 9690699Srobert 9790699Srobertvoid ofw_init(int, int, int, int, ofwfp_t); 9890699Srobertofwh_t ofw_finddevice(const char *); 9990699Srobertofwh_t ofw_open(const char *); 10090699Srobertint ofw_getprop(ofwh_t, const char *, void *, size_t); 10190699Srobertint ofw_read(ofwh_t, void *, size_t); 10290699Srobertint ofw_write(ofwh_t, const void *, size_t); 10390699Srobertint ofw_seek(ofwh_t, u_int64_t); 10495351Sjakevoid ofw_exit(void) __dead2; 10590699Srobert 10690699Srobertofwh_t bootdevh; 10790699Srobertofwh_t stdinh, stdouth; 10890699Srobert 10990699Srobert/* 11090699Srobert * This has to stay here, as the PROM seems to ignore the 11190699Srobert * entry point specified in the a.out header. (or elftoaout is broken) 11290699Srobert */ 11390699Srobert 11490699Srobertvoid 11590699Srobertofw_init(int d, int d1, int d2, int d3, ofwfp_t ofwaddr) 11690699Srobert{ 11790699Srobert ofwh_t chosenh; 11895346Sjake char *av[16]; 11995346Sjake char *p; 12095346Sjake int ac; 12190699Srobert 12290699Srobert ofw = ofwaddr; 12390699Srobert 12490699Srobert chosenh = ofw_finddevice("/chosen"); 12590699Srobert ofw_getprop(chosenh, "stdin", &stdinh, sizeof(stdinh)); 12690699Srobert ofw_getprop(chosenh, "stdout", &stdouth, sizeof(stdouth)); 12795346Sjake ofw_getprop(chosenh, "bootargs", bootargs, sizeof(bootargs)); 12890699Srobert ofw_getprop(chosenh, "bootpath", bootpath, sizeof(bootpath)); 12990699Srobert 13095346Sjake bootargs[sizeof(bootargs) - 1] = '\0'; 13195346Sjake bootpath[sizeof(bootpath) - 1] = '\0'; 13295346Sjake 13395346Sjake ac = 0; 13495346Sjake p = bootargs; 13595346Sjake for (;;) { 13695346Sjake while (*p == ' ' && *p != '\0') 13795346Sjake p++; 13895346Sjake if (*p == '\0' || ac >= 16) 13995346Sjake break; 14095346Sjake av[ac++] = p; 14195346Sjake while (*p != ' ' && *p != '\0') 14295346Sjake p++; 14395346Sjake if (*p != '\0') 14495346Sjake *p++ = '\0'; 14595346Sjake } 14695346Sjake 14795346Sjake exit(main(ac, av)); 14890699Srobert} 14990699Srobert 15090699Srobertofwh_t 15190699Srobertofw_finddevice(const char *name) 15290699Srobert{ 15391295Srobert ofwcell_t args[] = { 15491295Srobert (ofwcell_t)"finddevice", 15591295Srobert 1, 15691295Srobert 1, 15791295Srobert (ofwcell_t)name, 15891295Srobert 0 15991295Srobert }; 16091295Srobert 16191295Srobert if ((*ofw)(args)) { 16291295Srobert printf("ofw_finddevice: name=\"%s\"\n", name); 16391295Srobert return (1); 16491295Srobert } 16591295Srobert return (args[4]); 16690699Srobert} 16790699Srobert 16890699Srobertint 16990699Srobertofw_getprop(ofwh_t ofwh, const char *name, void *buf, size_t len) 17090699Srobert{ 17191295Srobert ofwcell_t args[] = { 17291295Srobert (ofwcell_t)"getprop", 17391295Srobert 4, 17491295Srobert 1, 17591295Srobert (u_ofwh_t)ofwh, 17691295Srobert (ofwcell_t)name, 17791295Srobert (ofwcell_t)buf, 17891295Srobert len, 17990699Srobert 0 18091295Srobert }; 18191295Srobert 18291295Srobert if ((*ofw)(args)) { 18391295Srobert printf("ofw_getprop: ofwh=0x%x buf=%p len=%u\n", 18491295Srobert ofwh, buf, len); 18591295Srobert return (1); 18691295Srobert } 18791295Srobert return (0); 18890699Srobert} 18990699Srobert 19090699Srobertofwh_t 19190699Srobertofw_open(const char *path) 19290699Srobert{ 19391295Srobert ofwcell_t args[] = { 19491295Srobert (ofwcell_t)"open", 19591295Srobert 1, 19691295Srobert 1, 19791295Srobert (ofwcell_t)path, 19891295Srobert 0 19991295Srobert }; 20091295Srobert 20191295Srobert if ((*ofw)(args)) { 20291295Srobert printf("ofw_open: path=\"%s\"\n", path); 20391295Srobert return (-1); 20491295Srobert } 20591295Srobert return (args[4]); 20690699Srobert} 20790699Srobert 20890699Srobertint 20990699Srobertofw_close(ofwh_t devh) 21090699Srobert{ 21191295Srobert ofwcell_t args[] = { 21291295Srobert (ofwcell_t)"close", 21391295Srobert 1, 21491295Srobert 0, 21591295Srobert (u_ofwh_t)devh 21691295Srobert }; 21791295Srobert 21891295Srobert if ((*ofw)(args)) { 21991295Srobert printf("ofw_close: devh=0x%x\n", devh); 22091295Srobert return (1); 22191295Srobert } 22291295Srobert return (0); 22390699Srobert} 22490699Srobert 22590699Srobertint 22690699Srobertofw_read(ofwh_t devh, void *buf, size_t len) 22790699Srobert{ 22891295Srobert ofwcell_t args[] = { 22991295Srobert (ofwcell_t)"read", 23091295Srobert 4, 23191295Srobert 1, 23291295Srobert (u_ofwh_t)devh, 23391295Srobert (ofwcell_t)buf, 23491295Srobert len, 23591295Srobert 0 23691295Srobert }; 23791295Srobert 23891295Srobert if ((*ofw)(args)) { 23991295Srobert printf("ofw_read: devh=0x%x buf=%p len=%u\n", devh, buf, len); 24091295Srobert return (1); 24191295Srobert } 24291295Srobert return (0); 24390699Srobert} 24490699Srobert 24590699Srobertint 24690699Srobertofw_write(ofwh_t devh, const void *buf, size_t len) 24790699Srobert{ 24891295Srobert ofwcell_t args[] = { 24991295Srobert (ofwcell_t)"write", 25091295Srobert 3, 25191295Srobert 1, 25291295Srobert (u_ofwh_t)devh, 25391295Srobert (ofwcell_t)buf, 25491295Srobert len, 25591295Srobert 0 25691295Srobert }; 25791295Srobert 25891295Srobert if ((*ofw)(args)) { 25991295Srobert printf("ofw_write: devh=0x%x buf=%p len=%u\n", devh, buf, len); 26091295Srobert return (1); 26191295Srobert } 26291295Srobert return (0); 26390699Srobert} 26490699Srobert 26590699Srobertint 26690699Srobertofw_seek(ofwh_t devh, u_int64_t off) 26790699Srobert{ 26891295Srobert ofwcell_t args[] = { 26991295Srobert (ofwcell_t)"seek", 27091295Srobert 4, 27191295Srobert 1, 27291295Srobert (u_ofwh_t)devh, 27391295Srobert off >> 32, 27491678Srobert off, 27591295Srobert 0 27691295Srobert }; 27791295Srobert 27891295Srobert if ((*ofw)(args)) { 27991295Srobert printf("ofw_seek: devh=0x%x off=0x%lx\n", devh, off); 28091295Srobert return (1); 28191295Srobert } 28291295Srobert return (0); 28390699Srobert} 28490699Srobert 28595342Sjakevoid 28695342Sjakeofw_exit(void) 28795342Sjake{ 28895342Sjake ofwcell_t args[3]; 28995342Sjake 29095342Sjake args[0] = (ofwcell_t)"exit"; 29195342Sjake args[1] = 0; 29295342Sjake args[2] = 0; 29395342Sjake 29495351Sjake for (;;) 29595351Sjake (*ofw)(args); 29695342Sjake} 29795342Sjake 29895340Sjakestatic void 29995340Sjakebcopy(const void *dst, void *src, size_t len) 30095340Sjake{ 30195340Sjake const char *d = dst; 30295340Sjake char *s = src; 30395340Sjake 30495340Sjake while (len-- != 0) 30595340Sjake *s++ = *d++; 30695340Sjake} 30795340Sjake 30895340Sjakestatic void 30995340Sjakebzero(void *b, size_t len) 31095340Sjake{ 31195340Sjake char *p = b; 31295340Sjake 31395340Sjake while (len-- != 0) 31495340Sjake *p++ = 0; 31595340Sjake} 31695340Sjake 31790699Srobertstatic int 31890699Srobertstrcmp(const char *s1, const char *s2) 31990699Srobert{ 32091295Srobert for (; *s1 == *s2 && *s1; s1++, s2++) 32191295Srobert ; 32291295Srobert return ((u_char)*s1 - (u_char)*s2); 32390699Srobert} 32490699Srobert 32590699Srobertstatic int 32690699Srobertfsfind(const char *name, ino_t * ino) 32790699Srobert{ 32891295Srobert char buf[DEV_BSIZE]; 32991295Srobert struct dirent *d; 33091295Srobert char *s; 33191295Srobert ssize_t n; 33290699Srobert 33391295Srobert fs_off = 0; 33491295Srobert while ((n = fsread(*ino, buf, DEV_BSIZE)) > 0) { 33591295Srobert for (s = buf; s < buf + DEV_BSIZE;) { 33691295Srobert d = (void *)s; 33795337Sjake if (!strcmp(name, d->d_name)) { 33891295Srobert *ino = d->d_fileno; 33991295Srobert return (d->d_type); 34091295Srobert } 34191295Srobert s += d->d_reclen; 34291295Srobert } 34390699Srobert } 34491295Srobert return (0); 34590699Srobert} 34690699Srobert 34795346Sjakeint 34895346Sjakemain(int ac, char **av) 34990699Srobert{ 35095346Sjake const char *path; 35195346Sjake int i; 35291295Srobert 35395346Sjake path = _PATH_LOADER; 35495346Sjake for (i = 0; i < ac; i++) { 35595346Sjake switch (av[i][0]) { 35695346Sjake case '-': 35795346Sjake switch (av[i][1]) { 35895346Sjake default: 35995351Sjake usage(); 36095346Sjake } 36195346Sjake break; 36295346Sjake default: 36395346Sjake path = av[i]; 36495346Sjake break; 36595346Sjake } 36695346Sjake } 36790699Srobert 36891295Srobert printf(" \n>> FreeBSD/sparc64 boot block\n" 36990699Srobert " Boot path: %s\n" 37095346Sjake " Boot loader: %s\n", bootpath, path); 37195351Sjake 37295351Sjake if (mount(bootpath) == -1) 37395351Sjake panic("mount"); 37495351Sjake 37595346Sjake load(path); 37691295Srobert return (1); 37790699Srobert} 37890699Srobert 37990699Srobertstatic void 38095351Sjakeusage(void) 38195351Sjake{ 38295351Sjake 38395351Sjake printf("usage: boot device [/path/to/loader]\n"); 38495351Sjake exit(1); 38595351Sjake} 38695351Sjake 38795351Sjakestatic void 38895342Sjakeexit(int code) 38995342Sjake{ 39095342Sjake 39195342Sjake ofw_exit(); 39295342Sjake} 39395342Sjake 39495351Sjakestatic int 39595351Sjakemount(const char *device) 39695351Sjake{ 39795351Sjake 39895351Sjake if ((bootdev = ofw_open(device)) == -1) { 39995351Sjake printf("mount: can't open device\n"); 40095351Sjake return (-1); 40195351Sjake } 40295351Sjake if (dskread(blkbuf, SBOFF / DEV_BSIZE, SBSIZE / DEV_BSIZE)) { 40395351Sjake printf("mount: can't read superblock\n"); 40495351Sjake return (-1); 40595351Sjake } 40695351Sjake inomap = 0; 40795351Sjake bcopy(blkbuf, &fs, sizeof(fs)); 40895351Sjake if (fs.fs_magic != FS_MAGIC) { 40995351Sjake printf("mount: not ufs\n"); 41095351Sjake return (-1); 41195351Sjake } 41295351Sjake fsblks = fs.fs_bsize >> DEV_BSHIFT; 41395351Sjake return (0); 41495351Sjake} 41595351Sjake 41695342Sjakestatic void 41790699Srobertload(const char *fname) 41890699Srobert{ 41991295Srobert Elf64_Ehdr eh; 42095339Sjake Elf64_Phdr ph; 42191295Srobert caddr_t p; 42291295Srobert ino_t ino; 42395339Sjake int i; 42490699Srobert 42591295Srobert if ((ino = lookup(fname)) == 0) { 42695337Sjake printf("File %s not found\n", fname); 42790699Srobert return; 42890699Srobert } 42995339Sjake if (fsread(ino, &eh, sizeof(eh)) != sizeof(eh)) { 43095339Sjake printf("Can't read elf header\n"); 43191295Srobert return; 43295339Sjake } 43391295Srobert if (!IS_ELF(eh)) { 43491295Srobert printf("Not an ELF file\n"); 43591295Srobert return; 43691295Srobert } 43795339Sjake for (i = 0; i < eh.e_phnum; i++) { 43895339Sjake fs_off = eh.e_phoff + i * eh.e_phentsize; 43995339Sjake if (fsread(ino, &ph, sizeof(ph)) != sizeof(ph)) { 44095339Sjake printf("Can't read program header %d\n", i); 44191295Srobert return; 44291295Srobert } 44395339Sjake if (ph.p_type != PT_LOAD) 44495339Sjake continue; 44595339Sjake fs_off = ph.p_offset; 44695339Sjake p = (caddr_t)ph.p_vaddr; 44795339Sjake if (fsread(ino, p, ph.p_filesz) != ph.p_filesz) { 44895339Sjake printf("Can't read content of section %d\n", i); 44991295Srobert return; 45091295Srobert } 45195339Sjake if (ph.p_filesz != ph.p_memsz) 45295340Sjake bzero(p + ph.p_filesz, ph.p_memsz - ph.p_filesz); 45391295Srobert } 45495351Sjake ofw_close(bootdev); 45595339Sjake (*(void (*)(int, int, int, int, ofwfp_t))eh.e_entry)(0, 0, 0, 0, ofw); 45690699Srobert} 45790699Srobert 45890699Srobertstatic ino_t 45990699Srobertlookup(const char *path) 46090699Srobert{ 46191295Srobert char name[MAXNAMLEN + 1]; 46291295Srobert const char *s; 46391295Srobert ino_t ino; 46491295Srobert ssize_t n; 46591295Srobert int dt; 46690699Srobert 46791295Srobert ino = ROOTINO; 46891295Srobert dt = DT_DIR; 46991678Srobert name[0] = '/'; 47091678Srobert name[1] = '\0'; 47191295Srobert for (;;) { 47291295Srobert if (*path == '/') 47391295Srobert path++; 47491295Srobert if (!*path) 47591295Srobert break; 47691295Srobert for (s = path; *s && *s != '/'; s++) 47791295Srobert ; 47891295Srobert if ((n = s - path) > MAXNAMLEN) 47991295Srobert return (0); 48095340Sjake bcopy(path, name, n); 48191295Srobert name[n] = 0; 48291678Srobert if (dt != DT_DIR) { 48391678Srobert printf("%s: not a directory.\n", name); 48491678Srobert return (0); 48591678Srobert } 48691295Srobert if ((dt = fsfind(name, &ino)) <= 0) 48791295Srobert break; 48891295Srobert path = s; 48991295Srobert } 49091295Srobert return (dt == DT_REG ? ino : 0); 49190699Srobert} 49290699Srobert 49390699Srobertstatic ssize_t 49490699Srobertfsread(ino_t inode, void *buf, size_t nbyte) 49590699Srobert{ 49691295Srobert static struct dinode din; 49795337Sjake static ufs_daddr_t indbuf[BSIZEMAX / sizeof(ufs_daddr_t)]; 49891295Srobert static ufs_daddr_t blkmap, indmap; 49991295Srobert char *s; 50091295Srobert ufs_daddr_t lbn, addr; 50191295Srobert size_t n, nb, off; 50290699Srobert 50391295Srobert if (!inode) 50491295Srobert return (0); 50591295Srobert if (inomap != inode) { 50691295Srobert if (dskread(blkbuf, fsbtodb(&fs, ino_to_fsba(&fs, inode)), 50790699Srobert fsblks)) 50891295Srobert return (-1); 50995340Sjake bcopy(blkbuf + ((inode % INOPB(&fs)) * sizeof(din)), &din, 51095340Sjake sizeof(din)); 51191295Srobert inomap = inode; 51291295Srobert fs_off = 0; 51391295Srobert blkmap = indmap = 0; 51490699Srobert } 51591295Srobert s = buf; 51691295Srobert if (nbyte > (n = din.di_size - fs_off)) 51791295Srobert nbyte = n; 51891295Srobert nb = nbyte; 51991295Srobert while (nb) { 52091295Srobert lbn = lblkno(&fs, fs_off); 52191295Srobert if (lbn < NDADDR) 52291295Srobert addr = din.di_db[lbn]; 52391295Srobert else { 52491295Srobert if (indmap != din.di_ib[0]) { 52591295Srobert if (dskread(indbuf, fsbtodb(&fs, din.di_ib[0]), 52691295Srobert fsblks)) 52791295Srobert return (-1); 52891295Srobert indmap = din.di_ib[0]; 52991295Srobert } 53091295Srobert addr = indbuf[(lbn - NDADDR) % NINDIR(&fs)]; 53191295Srobert } 53291295Srobert n = dblksize(&fs, &din, lbn); 53391295Srobert if (blkmap != addr) { 53491295Srobert if (dskread(blkbuf, fsbtodb(&fs, addr), 53591295Srobert n >> DEV_BSHIFT)) { 53691295Srobert return (-1); 53791295Srobert } 53891295Srobert blkmap = addr; 53991295Srobert } 54091295Srobert off = blkoff(&fs, fs_off); 54191295Srobert n -= off; 54291295Srobert if (n > nb) 54391295Srobert n = nb; 54495340Sjake bcopy(blkbuf + off, s, n); 54591295Srobert s += n; 54691295Srobert fs_off += n; 54791295Srobert nb -= n; 54890699Srobert } 54991295Srobert return (nbyte); 55090699Srobert} 55190699Srobert 55290699Srobertstatic int 55390699Srobertdskread(void *buf, u_int64_t lba, int nblk) 55490699Srobert{ 55591295Srobert /* 55691295Srobert * The OpenFirmware should open the correct partition for us. 55791295Srobert * That means, if we read from offset zero on an open instance handle, 55891295Srobert * we should read from offset zero of that partition. 55991295Srobert */ 56095351Sjake ofw_seek(bootdev, lba * DEV_BSIZE); 56195351Sjake ofw_read(bootdev, buf, nblk * DEV_BSIZE); 56291295Srobert return (0); 56390699Srobert} 56490699Srobert 56595351Sjakestatic void 56695351Sjakepanic(const char *fmt, ...) 56790699Srobert{ 56895351Sjake char buf[128]; 56991295Srobert va_list ap; 57095346Sjake 57195346Sjake va_start(ap, fmt); 57295351Sjake vsnprintf(buf, sizeof buf, fmt, ap); 57395351Sjake printf("panic: %s\n", buf); 57495346Sjake va_end(ap); 57595351Sjake 57695351Sjake exit(1); 57795346Sjake} 57895346Sjake 57995346Sjakestatic int 58095351Sjakeprintf(const char *fmt, ...) 58195346Sjake{ 58295351Sjake va_list ap; 58395346Sjake int ret; 58495346Sjake 58595351Sjake va_start(ap, fmt); 58695351Sjake ret = vprintf(fmt, ap); 58795351Sjake va_end(ap); 58895346Sjake return (ret); 58995346Sjake} 59095346Sjake 59195346Sjakestatic int 59295346Sjakeputchar(int c, void *arg) 59395346Sjake{ 59495346Sjake char buf; 59595346Sjake 59695346Sjake if (c == '\n') { 59795346Sjake buf = '\r'; 59895346Sjake ofw_write(stdouth, &buf, 1); 59995346Sjake } 60095346Sjake buf = c; 60195346Sjake ofw_write(stdouth, &buf, 1); 60295346Sjake return (1); 60395346Sjake} 60495346Sjake 60595346Sjakestatic int 60695351Sjakevprintf(const char *fmt, va_list ap) 60795351Sjake{ 60895351Sjake int ret; 60995351Sjake 61095351Sjake ret = __printf(fmt, putchar, 0, ap); 61195351Sjake return (ret); 61295351Sjake} 61395351Sjake 61495351Sjakestatic int 61595351Sjakevsnprintf(char *str, size_t sz, const char *fmt, va_list ap) 61695351Sjake{ 61795351Sjake struct sp_data sp; 61895351Sjake int ret; 61995351Sjake 62095351Sjake sp.sp_buf = str; 62195351Sjake sp.sp_len = 0; 62295351Sjake sp.sp_size = sz; 62395351Sjake ret = __printf(fmt, __sputc, &sp, ap); 62495351Sjake return (ret); 62595351Sjake} 62695351Sjake 62795351Sjakestatic int 62895346Sjake__printf(const char *fmt, putc_func_t *putc, void *arg, va_list ap) 62995346Sjake{ 63095346Sjake char buf[(sizeof(long) * 8) + 1]; 63195346Sjake char *nbuf; 63295346Sjake u_long ul; 63395346Sjake u_int ui; 63495346Sjake int lflag; 63595346Sjake int sflag; 63691295Srobert char *s; 63795346Sjake int pad; 63895346Sjake int ret; 63995346Sjake int c; 64090699Srobert 64195346Sjake nbuf = &buf[sizeof buf - 1]; 64295346Sjake ret = 0; 64395346Sjake while ((c = *fmt++) != 0) { 64495346Sjake if (c != '%') { 64595346Sjake ret += putc(c, arg); 64695346Sjake continue; 64795346Sjake } 64895346Sjake lflag = 0; 64995346Sjake sflag = 0; 65095346Sjake pad = 0; 65195346Sjakereswitch: c = *fmt++; 65295346Sjake switch (c) { 65395346Sjake case '#': 65495346Sjake sflag = 1; 65595346Sjake goto reswitch; 65695346Sjake case '%': 65795346Sjake ret += putc('%', arg); 65895346Sjake break; 65995346Sjake case 'c': 66095346Sjake c = va_arg(ap, int); 66195346Sjake ret += putc(c, arg); 66295346Sjake break; 66395346Sjake case 'd': 66495346Sjake if (lflag == 0) { 66595346Sjake ui = (u_int)va_arg(ap, int); 66695346Sjake if (ui < (int)ui) { 66795346Sjake ui = -ui; 66895346Sjake ret += putc('-', arg); 66991295Srobert } 67095346Sjake s = __uitoa(nbuf, ui, 10); 67195346Sjake } else { 67295346Sjake ul = (u_long)va_arg(ap, long); 67395346Sjake if (ul < (long)ul) { 67495346Sjake ul = -ul; 67595346Sjake ret += putc('-', arg); 67695346Sjake } 67795346Sjake s = __ultoa(nbuf, ul, 10); 67891295Srobert } 67995346Sjake ret += __puts(s, putc, arg); 68095346Sjake break; 68195346Sjake case 'l': 68295346Sjake lflag = 1; 68395346Sjake goto reswitch; 68495346Sjake case 'o': 68595346Sjake if (lflag == 0) { 68695346Sjake ui = (u_int)va_arg(ap, u_int); 68795346Sjake s = __uitoa(nbuf, ui, 8); 68895346Sjake } else { 68995346Sjake ul = (u_long)va_arg(ap, u_long); 69095346Sjake s = __ultoa(nbuf, ul, 8); 69195346Sjake } 69295346Sjake ret += __puts(s, putc, arg); 69395346Sjake break; 69495346Sjake case 'p': 69595346Sjake ul = (u_long)va_arg(ap, void *); 69695346Sjake s = __ultoa(nbuf, ul, 16); 69795346Sjake ret += __puts("0x", putc, arg); 69895346Sjake ret += __puts(s, putc, arg); 69995346Sjake break; 70095346Sjake case 's': 70195346Sjake s = va_arg(ap, char *); 70295346Sjake ret += __puts(s, putc, arg); 70395346Sjake break; 70495346Sjake case 'u': 70595346Sjake if (lflag == 0) { 70695346Sjake ui = va_arg(ap, u_int); 70795346Sjake s = __uitoa(nbuf, ui, 10); 70895346Sjake } else { 70995346Sjake ul = va_arg(ap, u_long); 71095346Sjake s = __ultoa(nbuf, ul, 10); 71195346Sjake } 71295346Sjake ret += __puts(s, putc, arg); 71395346Sjake break; 71495346Sjake case 'x': 71595346Sjake if (lflag == 0) { 71695346Sjake ui = va_arg(ap, u_int); 71795346Sjake s = __uitoa(nbuf, ui, 16); 71895346Sjake } else { 71995346Sjake ul = va_arg(ap, u_long); 72095346Sjake s = __ultoa(nbuf, ul, 16); 72195346Sjake } 72295346Sjake if (sflag) 72395346Sjake ret += __puts("0x", putc, arg); 72495346Sjake ret += __puts(s, putc, arg); 72595346Sjake break; 72695346Sjake case '0': case '1': case '2': case '3': case '4': 72795346Sjake case '5': case '6': case '7': case '8': case '9': 72895346Sjake pad = pad * 10 + c - '0'; 72995346Sjake goto reswitch; 73095346Sjake default: 73195346Sjake break; 73290699Srobert } 73390699Srobert } 73495346Sjake return (ret); 73590699Srobert} 73690699Srobert 73790699Srobertstatic int 73895351Sjake__sputc(int c, void *arg) 73995351Sjake{ 74095351Sjake struct sp_data *sp; 74195351Sjake 74295351Sjake sp = arg; 74395351Sjake if (sp->sp_len < sp->sp_size) 74495351Sjake sp->sp_buf[sp->sp_len++] = c; 74595351Sjake sp->sp_buf[sp->sp_len] = '\0'; 74695351Sjake return (1); 74795351Sjake} 74895351Sjake 74995351Sjakestatic int 75095346Sjake__puts(const char *s, putc_func_t *putc, void *arg) 75190699Srobert{ 75295346Sjake const char *p; 75395346Sjake int ret; 75495346Sjake 75595346Sjake ret = 0; 75695346Sjake for (p = s; *p != '\0'; p++) 75795346Sjake ret += putc(*p, arg); 75895346Sjake return (ret); 75990699Srobert} 76095346Sjake 76195346Sjakestatic char * 76295346Sjake__uitoa(char *buf, u_int ui, int base) 76395346Sjake{ 76495346Sjake char *p; 76595346Sjake 76695346Sjake p = buf; 76795346Sjake *p = '\0'; 76895346Sjake do 76995346Sjake *--p = digits[ui % base]; 77095346Sjake while ((ui /= base) != 0); 77195346Sjake return (p); 77295346Sjake} 77395346Sjake 77495346Sjakestatic char * 77595346Sjake__ultoa(char *buf, u_long ul, int base) 77695346Sjake{ 77795346Sjake char *p; 77895346Sjake 77995346Sjake p = buf; 78095346Sjake *p = '\0'; 78195346Sjake do 78295346Sjake *--p = digits[ul % base]; 78395346Sjake while ((ul /= base) != 0); 78495346Sjake return (p); 78595346Sjake} 786