1df8bae1dSRodney W. Grimes /*- 2df8bae1dSRodney W. Grimes * Copyright (c) 1986, 1988, 1991, 1993 3df8bae1dSRodney W. Grimes * The Regents of the University of California. All rights reserved. 4df8bae1dSRodney W. Grimes * (c) UNIX System Laboratories, Inc. 5df8bae1dSRodney W. Grimes * All or some portions of this file are derived from material licensed 6df8bae1dSRodney W. Grimes * to the University of California by American Telephone and Telegraph 7df8bae1dSRodney W. Grimes * Co. or Unix System Laboratories, Inc. and are reproduced herein with 8df8bae1dSRodney W. Grimes * the permission of UNIX System Laboratories, Inc. 9df8bae1dSRodney W. Grimes * 10df8bae1dSRodney W. Grimes * Redistribution and use in source and binary forms, with or without 11df8bae1dSRodney W. Grimes * modification, are permitted provided that the following conditions 12df8bae1dSRodney W. Grimes * are met: 13df8bae1dSRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 14df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer. 15df8bae1dSRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 16df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 17df8bae1dSRodney W. Grimes * documentation and/or other materials provided with the distribution. 18df8bae1dSRodney W. Grimes * 3. All advertising materials mentioning features or use of this software 19df8bae1dSRodney W. Grimes * must display the following acknowledgement: 20df8bae1dSRodney W. Grimes * This product includes software developed by the University of 21df8bae1dSRodney W. Grimes * California, Berkeley and its contributors. 22df8bae1dSRodney W. Grimes * 4. Neither the name of the University nor the names of its contributors 23df8bae1dSRodney W. Grimes * may be used to endorse or promote products derived from this software 24df8bae1dSRodney W. Grimes * without specific prior written permission. 25df8bae1dSRodney W. Grimes * 26df8bae1dSRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 27df8bae1dSRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28df8bae1dSRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29df8bae1dSRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 30df8bae1dSRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31df8bae1dSRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32df8bae1dSRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33df8bae1dSRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34df8bae1dSRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35df8bae1dSRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36df8bae1dSRodney W. Grimes * SUCH DAMAGE. 37df8bae1dSRodney W. Grimes * 38df8bae1dSRodney W. Grimes * @(#)subr_prf.c 8.3 (Berkeley) 1/21/94 3912d17f65SPoul-Henning Kamp * $Id: subr_prf.c,v 1.5 1994/08/27 16:14:27 davidg Exp $ 40df8bae1dSRodney W. Grimes */ 41df8bae1dSRodney W. Grimes 42df8bae1dSRodney W. Grimes #include <sys/param.h> 43df8bae1dSRodney W. Grimes #include <sys/systm.h> 44df8bae1dSRodney W. Grimes #include <sys/buf.h> 45df8bae1dSRodney W. Grimes #include <sys/conf.h> 46df8bae1dSRodney W. Grimes #include <sys/reboot.h> 47df8bae1dSRodney W. Grimes #include <sys/msgbuf.h> 48df8bae1dSRodney W. Grimes #include <sys/proc.h> 49df8bae1dSRodney W. Grimes #include <sys/ioctl.h> 50df8bae1dSRodney W. Grimes #include <sys/vnode.h> 51df8bae1dSRodney W. Grimes #include <sys/file.h> 52df8bae1dSRodney W. Grimes #include <sys/tty.h> 53df8bae1dSRodney W. Grimes #include <sys/tprintf.h> 54df8bae1dSRodney W. Grimes #include <sys/syslog.h> 55df8bae1dSRodney W. Grimes #include <sys/malloc.h> 56df8bae1dSRodney W. Grimes 57df8bae1dSRodney W. Grimes /* 58df8bae1dSRodney W. Grimes * Note that stdarg.h and the ANSI style va_start macro is used for both 59df8bae1dSRodney W. Grimes * ANSI and traditional C compilers. 60df8bae1dSRodney W. Grimes */ 61df8bae1dSRodney W. Grimes #include <machine/stdarg.h> 62df8bae1dSRodney W. Grimes 63df8bae1dSRodney W. Grimes #ifdef KADB 64df8bae1dSRodney W. Grimes #include <machine/kdbparam.h> 65df8bae1dSRodney W. Grimes #endif 66df8bae1dSRodney W. Grimes 67df8bae1dSRodney W. Grimes #define TOCONS 0x01 68df8bae1dSRodney W. Grimes #define TOTTY 0x02 69df8bae1dSRodney W. Grimes #define TOLOG 0x04 70df8bae1dSRodney W. Grimes 71df8bae1dSRodney W. Grimes struct tty *constty; /* pointer to console "window" tty */ 72df8bae1dSRodney W. Grimes 73df8bae1dSRodney W. Grimes extern cnputc(); /* standard console putc */ 74df8bae1dSRodney W. Grimes int (*v_putc)() = cnputc; /* routine to putc on virtual console */ 75df8bae1dSRodney W. Grimes 76df8bae1dSRodney W. Grimes void logpri __P((int level)); 77df8bae1dSRodney W. Grimes static void putchar __P((int ch, int flags, struct tty *tp)); 78df8bae1dSRodney W. Grimes static char *ksprintn __P((u_long num, int base, int *len)); 79df8bae1dSRodney W. Grimes void kprintf __P((const char *fmt, int flags, struct tty *tp, va_list ap)); 80df8bae1dSRodney W. Grimes 81df8bae1dSRodney W. Grimes int consintr = 1; /* Ok to handle console interrupts? */ 82df8bae1dSRodney W. Grimes 83df8bae1dSRodney W. Grimes /* 84df8bae1dSRodney W. Grimes * Variable panicstr contains argument to first call to panic; used as flag 85df8bae1dSRodney W. Grimes * to indicate that the kernel has already called panic. 86df8bae1dSRodney W. Grimes */ 87df8bae1dSRodney W. Grimes const char *panicstr; 88df8bae1dSRodney W. Grimes 89df8bae1dSRodney W. Grimes /* 90df8bae1dSRodney W. Grimes * Panic is called on unresolvable fatal errors. It prints "panic: mesg", 91df8bae1dSRodney W. Grimes * and then reboots. If we are called twice, then we avoid trying to sync 92df8bae1dSRodney W. Grimes * the disks as this often leads to recursive panics. 93df8bae1dSRodney W. Grimes */ 94df8bae1dSRodney W. Grimes #ifdef __GNUC__ 950e427608SDavid Greenman __dead /* panic() does not return */ 96df8bae1dSRodney W. Grimes #endif 97df8bae1dSRodney W. Grimes void 98df8bae1dSRodney W. Grimes #ifdef __STDC__ 99df8bae1dSRodney W. Grimes panic(const char *fmt, ...) 100df8bae1dSRodney W. Grimes #else 101df8bae1dSRodney W. Grimes panic(fmt, va_alist) 102df8bae1dSRodney W. Grimes char *fmt; 103df8bae1dSRodney W. Grimes #endif 104df8bae1dSRodney W. Grimes { 105df8bae1dSRodney W. Grimes int bootopt; 106df8bae1dSRodney W. Grimes va_list ap; 107df8bae1dSRodney W. Grimes 108df8bae1dSRodney W. Grimes bootopt = RB_AUTOBOOT | RB_DUMP; 109df8bae1dSRodney W. Grimes if (panicstr) 110df8bae1dSRodney W. Grimes bootopt |= RB_NOSYNC; 111df8bae1dSRodney W. Grimes else 112df8bae1dSRodney W. Grimes panicstr = fmt; 113df8bae1dSRodney W. Grimes 114df8bae1dSRodney W. Grimes va_start(ap, fmt); 115df8bae1dSRodney W. Grimes printf("panic: %r\n", fmt, ap); 116df8bae1dSRodney W. Grimes va_end(ap); 117df8bae1dSRodney W. Grimes 118df8bae1dSRodney W. Grimes #ifdef KGDB 119df8bae1dSRodney W. Grimes kgdb_panic(); 120df8bae1dSRodney W. Grimes #endif 121df8bae1dSRodney W. Grimes #ifdef KADB 122df8bae1dSRodney W. Grimes if (boothowto & RB_KDB) 123df8bae1dSRodney W. Grimes kdbpanic(); 124df8bae1dSRodney W. Grimes #endif 1258a129caeSDavid Greenman #ifdef DDB 12626f9a767SRodney W. Grimes Debugger ("panic"); 12726f9a767SRodney W. Grimes #endif 128df8bae1dSRodney W. Grimes boot(bootopt); 129df8bae1dSRodney W. Grimes } 130df8bae1dSRodney W. Grimes 131df8bae1dSRodney W. Grimes /* 132df8bae1dSRodney W. Grimes * Warn that a system table is full. 133df8bae1dSRodney W. Grimes */ 134df8bae1dSRodney W. Grimes void 135df8bae1dSRodney W. Grimes tablefull(tab) 136df8bae1dSRodney W. Grimes const char *tab; 137df8bae1dSRodney W. Grimes { 138df8bae1dSRodney W. Grimes 139df8bae1dSRodney W. Grimes log(LOG_ERR, "%s: table is full\n", tab); 140df8bae1dSRodney W. Grimes } 141df8bae1dSRodney W. Grimes 142df8bae1dSRodney W. Grimes /* 143df8bae1dSRodney W. Grimes * Uprintf prints to the controlling terminal for the current process. 144df8bae1dSRodney W. Grimes * It may block if the tty queue is overfull. No message is printed if 145df8bae1dSRodney W. Grimes * the queue does not clear in a reasonable time. 146df8bae1dSRodney W. Grimes */ 147df8bae1dSRodney W. Grimes void 148df8bae1dSRodney W. Grimes #ifdef __STDC__ 149df8bae1dSRodney W. Grimes uprintf(const char *fmt, ...) 150df8bae1dSRodney W. Grimes #else 151df8bae1dSRodney W. Grimes uprintf(fmt, va_alist) 152df8bae1dSRodney W. Grimes char *fmt; 153df8bae1dSRodney W. Grimes #endif 154df8bae1dSRodney W. Grimes { 155df8bae1dSRodney W. Grimes register struct proc *p = curproc; 156df8bae1dSRodney W. Grimes va_list ap; 157df8bae1dSRodney W. Grimes 158df8bae1dSRodney W. Grimes if (p->p_flag & P_CONTROLT && p->p_session->s_ttyvp) { 159df8bae1dSRodney W. Grimes va_start(ap, fmt); 160df8bae1dSRodney W. Grimes kprintf(fmt, TOTTY, p->p_session->s_ttyp, ap); 161df8bae1dSRodney W. Grimes va_end(ap); 162df8bae1dSRodney W. Grimes } 163df8bae1dSRodney W. Grimes } 164df8bae1dSRodney W. Grimes 165df8bae1dSRodney W. Grimes tpr_t 166df8bae1dSRodney W. Grimes tprintf_open(p) 167df8bae1dSRodney W. Grimes register struct proc *p; 168df8bae1dSRodney W. Grimes { 169df8bae1dSRodney W. Grimes 170df8bae1dSRodney W. Grimes if (p->p_flag & P_CONTROLT && p->p_session->s_ttyvp) { 171df8bae1dSRodney W. Grimes SESSHOLD(p->p_session); 172df8bae1dSRodney W. Grimes return ((tpr_t) p->p_session); 173df8bae1dSRodney W. Grimes } 174df8bae1dSRodney W. Grimes return ((tpr_t) NULL); 175df8bae1dSRodney W. Grimes } 176df8bae1dSRodney W. Grimes 177df8bae1dSRodney W. Grimes void 178df8bae1dSRodney W. Grimes tprintf_close(sess) 179df8bae1dSRodney W. Grimes tpr_t sess; 180df8bae1dSRodney W. Grimes { 181df8bae1dSRodney W. Grimes 182df8bae1dSRodney W. Grimes if (sess) 183df8bae1dSRodney W. Grimes SESSRELE((struct session *) sess); 184df8bae1dSRodney W. Grimes } 185df8bae1dSRodney W. Grimes 186df8bae1dSRodney W. Grimes /* 187df8bae1dSRodney W. Grimes * tprintf prints on the controlling terminal associated 188df8bae1dSRodney W. Grimes * with the given session. 189df8bae1dSRodney W. Grimes */ 190df8bae1dSRodney W. Grimes void 191df8bae1dSRodney W. Grimes #ifdef __STDC__ 192df8bae1dSRodney W. Grimes tprintf(tpr_t tpr, const char *fmt, ...) 193df8bae1dSRodney W. Grimes #else 194df8bae1dSRodney W. Grimes tprintf(tpr, fmt, va_alist) 195df8bae1dSRodney W. Grimes tpr_t tpr; 196df8bae1dSRodney W. Grimes char *fmt; 197df8bae1dSRodney W. Grimes #endif 198df8bae1dSRodney W. Grimes { 199df8bae1dSRodney W. Grimes register struct session *sess = (struct session *)tpr; 200df8bae1dSRodney W. Grimes struct tty *tp = NULL; 201df8bae1dSRodney W. Grimes int flags = TOLOG; 202df8bae1dSRodney W. Grimes va_list ap; 203df8bae1dSRodney W. Grimes 204df8bae1dSRodney W. Grimes logpri(LOG_INFO); 205df8bae1dSRodney W. Grimes if (sess && sess->s_ttyvp && ttycheckoutq(sess->s_ttyp, 0)) { 206df8bae1dSRodney W. Grimes flags |= TOTTY; 207df8bae1dSRodney W. Grimes tp = sess->s_ttyp; 208df8bae1dSRodney W. Grimes } 209df8bae1dSRodney W. Grimes va_start(ap, fmt); 210df8bae1dSRodney W. Grimes kprintf(fmt, flags, tp, ap); 211df8bae1dSRodney W. Grimes va_end(ap); 212df8bae1dSRodney W. Grimes logwakeup(); 213df8bae1dSRodney W. Grimes } 214df8bae1dSRodney W. Grimes 215df8bae1dSRodney W. Grimes /* 216df8bae1dSRodney W. Grimes * Ttyprintf displays a message on a tty; it should be used only by 217df8bae1dSRodney W. Grimes * the tty driver, or anything that knows the underlying tty will not 218df8bae1dSRodney W. Grimes * be revoke(2)'d away. Other callers should use tprintf. 219df8bae1dSRodney W. Grimes */ 220df8bae1dSRodney W. Grimes void 221df8bae1dSRodney W. Grimes #ifdef __STDC__ 222df8bae1dSRodney W. Grimes ttyprintf(struct tty *tp, const char *fmt, ...) 223df8bae1dSRodney W. Grimes #else 224df8bae1dSRodney W. Grimes ttyprintf(tp, fmt, va_alist) 225df8bae1dSRodney W. Grimes struct tty *tp; 226df8bae1dSRodney W. Grimes char *fmt; 227df8bae1dSRodney W. Grimes #endif 228df8bae1dSRodney W. Grimes { 229df8bae1dSRodney W. Grimes va_list ap; 230df8bae1dSRodney W. Grimes 231df8bae1dSRodney W. Grimes va_start(ap, fmt); 232df8bae1dSRodney W. Grimes kprintf(fmt, TOTTY, tp, ap); 233df8bae1dSRodney W. Grimes va_end(ap); 234df8bae1dSRodney W. Grimes } 235df8bae1dSRodney W. Grimes 236df8bae1dSRodney W. Grimes extern int log_open; 237df8bae1dSRodney W. Grimes 238df8bae1dSRodney W. Grimes /* 239df8bae1dSRodney W. Grimes * Log writes to the log buffer, and guarantees not to sleep (so can be 240df8bae1dSRodney W. Grimes * called by interrupt routines). If there is no process reading the 241df8bae1dSRodney W. Grimes * log yet, it writes to the console also. 242df8bae1dSRodney W. Grimes */ 243df8bae1dSRodney W. Grimes void 244df8bae1dSRodney W. Grimes #ifdef __STDC__ 245df8bae1dSRodney W. Grimes log(int level, const char *fmt, ...) 246df8bae1dSRodney W. Grimes #else 247df8bae1dSRodney W. Grimes log(level, fmt, va_alist) 248df8bae1dSRodney W. Grimes int level; 249df8bae1dSRodney W. Grimes char *fmt; 250df8bae1dSRodney W. Grimes #endif 251df8bae1dSRodney W. Grimes { 252df8bae1dSRodney W. Grimes register int s; 253df8bae1dSRodney W. Grimes va_list ap; 254df8bae1dSRodney W. Grimes 255df8bae1dSRodney W. Grimes s = splhigh(); 256df8bae1dSRodney W. Grimes logpri(level); 257df8bae1dSRodney W. Grimes va_start(ap, fmt); 258df8bae1dSRodney W. Grimes kprintf(fmt, TOLOG, NULL, ap); 259df8bae1dSRodney W. Grimes splx(s); 260df8bae1dSRodney W. Grimes va_end(ap); 261df8bae1dSRodney W. Grimes if (!log_open) { 262df8bae1dSRodney W. Grimes va_start(ap, fmt); 263df8bae1dSRodney W. Grimes kprintf(fmt, TOCONS, NULL, ap); 264df8bae1dSRodney W. Grimes va_end(ap); 265df8bae1dSRodney W. Grimes } 266df8bae1dSRodney W. Grimes logwakeup(); 267df8bae1dSRodney W. Grimes } 268df8bae1dSRodney W. Grimes 269df8bae1dSRodney W. Grimes void 270df8bae1dSRodney W. Grimes logpri(level) 271df8bae1dSRodney W. Grimes int level; 272df8bae1dSRodney W. Grimes { 273df8bae1dSRodney W. Grimes register int ch; 274df8bae1dSRodney W. Grimes register char *p; 275df8bae1dSRodney W. Grimes 276df8bae1dSRodney W. Grimes putchar('<', TOLOG, NULL); 277df8bae1dSRodney W. Grimes for (p = ksprintn((u_long)level, 10, NULL); ch = *p--;) 278df8bae1dSRodney W. Grimes putchar(ch, TOLOG, NULL); 279df8bae1dSRodney W. Grimes putchar('>', TOLOG, NULL); 280df8bae1dSRodney W. Grimes } 281df8bae1dSRodney W. Grimes 282df8bae1dSRodney W. Grimes void 283df8bae1dSRodney W. Grimes #ifdef __STDC__ 284df8bae1dSRodney W. Grimes addlog(const char *fmt, ...) 285df8bae1dSRodney W. Grimes #else 286df8bae1dSRodney W. Grimes addlog(fmt, va_alist) 287df8bae1dSRodney W. Grimes char *fmt; 288df8bae1dSRodney W. Grimes #endif 289df8bae1dSRodney W. Grimes { 290df8bae1dSRodney W. Grimes register int s; 291df8bae1dSRodney W. Grimes va_list ap; 292df8bae1dSRodney W. Grimes 293df8bae1dSRodney W. Grimes s = splhigh(); 294df8bae1dSRodney W. Grimes va_start(ap, fmt); 295df8bae1dSRodney W. Grimes kprintf(fmt, TOLOG, NULL, ap); 296df8bae1dSRodney W. Grimes splx(s); 297df8bae1dSRodney W. Grimes va_end(ap); 298df8bae1dSRodney W. Grimes if (!log_open) { 299df8bae1dSRodney W. Grimes va_start(ap, fmt); 300df8bae1dSRodney W. Grimes kprintf(fmt, TOCONS, NULL, ap); 301df8bae1dSRodney W. Grimes va_end(ap); 302df8bae1dSRodney W. Grimes } 303df8bae1dSRodney W. Grimes logwakeup(); 304df8bae1dSRodney W. Grimes } 305df8bae1dSRodney W. Grimes 306df8bae1dSRodney W. Grimes void 307df8bae1dSRodney W. Grimes #ifdef __STDC__ 308df8bae1dSRodney W. Grimes printf(const char *fmt, ...) 309df8bae1dSRodney W. Grimes #else 310df8bae1dSRodney W. Grimes printf(fmt, va_alist) 311df8bae1dSRodney W. Grimes char *fmt; 312df8bae1dSRodney W. Grimes #endif 313df8bae1dSRodney W. Grimes { 314df8bae1dSRodney W. Grimes va_list ap; 315df8bae1dSRodney W. Grimes register int savintr; 316df8bae1dSRodney W. Grimes 317df8bae1dSRodney W. Grimes savintr = consintr; /* disable interrupts */ 318df8bae1dSRodney W. Grimes consintr = 0; 319df8bae1dSRodney W. Grimes va_start(ap, fmt); 320df8bae1dSRodney W. Grimes kprintf(fmt, TOCONS | TOLOG, NULL, ap); 321df8bae1dSRodney W. Grimes va_end(ap); 322df8bae1dSRodney W. Grimes if (!panicstr) 323df8bae1dSRodney W. Grimes logwakeup(); 324df8bae1dSRodney W. Grimes consintr = savintr; /* reenable interrupts */ 325df8bae1dSRodney W. Grimes } 326df8bae1dSRodney W. Grimes 327df8bae1dSRodney W. Grimes /* 328df8bae1dSRodney W. Grimes * Scaled down version of printf(3). 329df8bae1dSRodney W. Grimes * 330df8bae1dSRodney W. Grimes * Two additional formats: 331df8bae1dSRodney W. Grimes * 332df8bae1dSRodney W. Grimes * The format %b is supported to decode error registers. 333df8bae1dSRodney W. Grimes * Its usage is: 334df8bae1dSRodney W. Grimes * 335df8bae1dSRodney W. Grimes * printf("reg=%b\n", regval, "<base><arg>*"); 336df8bae1dSRodney W. Grimes * 337df8bae1dSRodney W. Grimes * where <base> is the output base expressed as a control character, e.g. 338df8bae1dSRodney W. Grimes * \10 gives octal; \20 gives hex. Each arg is a sequence of characters, 339df8bae1dSRodney W. Grimes * the first of which gives the bit number to be inspected (origin 1), and 340df8bae1dSRodney W. Grimes * the next characters (up to a control character, i.e. a character <= 32), 341df8bae1dSRodney W. Grimes * give the name of the register. Thus: 342df8bae1dSRodney W. Grimes * 343df8bae1dSRodney W. Grimes * kprintf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n"); 344df8bae1dSRodney W. Grimes * 345df8bae1dSRodney W. Grimes * would produce output: 346df8bae1dSRodney W. Grimes * 347df8bae1dSRodney W. Grimes * reg=3<BITTWO,BITONE> 348df8bae1dSRodney W. Grimes * 349df8bae1dSRodney W. Grimes * The format %r passes an additional format string and argument list 350df8bae1dSRodney W. Grimes * recursively. Its usage is: 351df8bae1dSRodney W. Grimes * 352df8bae1dSRodney W. Grimes * fn(char *fmt, ...) 353df8bae1dSRodney W. Grimes * { 354df8bae1dSRodney W. Grimes * va_list ap; 355df8bae1dSRodney W. Grimes * va_start(ap, fmt); 356df8bae1dSRodney W. Grimes * printf("prefix: %r: suffix\n", fmt, ap); 357df8bae1dSRodney W. Grimes * va_end(ap); 358df8bae1dSRodney W. Grimes * } 359df8bae1dSRodney W. Grimes * 360df8bae1dSRodney W. Grimes * Space or zero padding and a field width are supported for the numeric 361df8bae1dSRodney W. Grimes * formats only. 362df8bae1dSRodney W. Grimes */ 363df8bae1dSRodney W. Grimes void 364df8bae1dSRodney W. Grimes kprintf(fmt, flags, tp, ap) 365df8bae1dSRodney W. Grimes register const char *fmt; 366df8bae1dSRodney W. Grimes int flags; 367df8bae1dSRodney W. Grimes struct tty *tp; 368df8bae1dSRodney W. Grimes va_list ap; 369df8bae1dSRodney W. Grimes { 370df8bae1dSRodney W. Grimes register char *p, *q; 371df8bae1dSRodney W. Grimes register int ch, n; 372df8bae1dSRodney W. Grimes u_long ul; 373df8bae1dSRodney W. Grimes int base, lflag, tmp, width; 374df8bae1dSRodney W. Grimes char padc; 375df8bae1dSRodney W. Grimes 376df8bae1dSRodney W. Grimes for (;;) { 377df8bae1dSRodney W. Grimes padc = ' '; 378df8bae1dSRodney W. Grimes width = 0; 379df8bae1dSRodney W. Grimes while ((ch = *(u_char *)fmt++) != '%') { 380df8bae1dSRodney W. Grimes if (ch == '\0') 381df8bae1dSRodney W. Grimes return; 382df8bae1dSRodney W. Grimes putchar(ch, flags, tp); 383df8bae1dSRodney W. Grimes } 384df8bae1dSRodney W. Grimes lflag = 0; 385df8bae1dSRodney W. Grimes reswitch: switch (ch = *(u_char *)fmt++) { 386df8bae1dSRodney W. Grimes case '0': 387df8bae1dSRodney W. Grimes padc = '0'; 388df8bae1dSRodney W. Grimes goto reswitch; 389df8bae1dSRodney W. Grimes case '1': case '2': case '3': case '4': 390df8bae1dSRodney W. Grimes case '5': case '6': case '7': case '8': case '9': 391df8bae1dSRodney W. Grimes for (width = 0;; ++fmt) { 392df8bae1dSRodney W. Grimes width = width * 10 + ch - '0'; 393df8bae1dSRodney W. Grimes ch = *fmt; 394df8bae1dSRodney W. Grimes if (ch < '0' || ch > '9') 395df8bae1dSRodney W. Grimes break; 396df8bae1dSRodney W. Grimes } 397df8bae1dSRodney W. Grimes goto reswitch; 398df8bae1dSRodney W. Grimes case 'l': 399df8bae1dSRodney W. Grimes lflag = 1; 400df8bae1dSRodney W. Grimes goto reswitch; 401df8bae1dSRodney W. Grimes case 'b': 402df8bae1dSRodney W. Grimes ul = va_arg(ap, int); 403df8bae1dSRodney W. Grimes p = va_arg(ap, char *); 404df8bae1dSRodney W. Grimes for (q = ksprintn(ul, *p++, NULL); ch = *q--;) 405df8bae1dSRodney W. Grimes putchar(ch, flags, tp); 406df8bae1dSRodney W. Grimes 407df8bae1dSRodney W. Grimes if (!ul) 408df8bae1dSRodney W. Grimes break; 409df8bae1dSRodney W. Grimes 410df8bae1dSRodney W. Grimes for (tmp = 0; n = *p++;) { 411df8bae1dSRodney W. Grimes if (ul & (1 << (n - 1))) { 412df8bae1dSRodney W. Grimes putchar(tmp ? ',' : '<', flags, tp); 413df8bae1dSRodney W. Grimes for (; (n = *p) > ' '; ++p) 414df8bae1dSRodney W. Grimes putchar(n, flags, tp); 415df8bae1dSRodney W. Grimes tmp = 1; 416df8bae1dSRodney W. Grimes } else 417df8bae1dSRodney W. Grimes for (; *p > ' '; ++p) 418df8bae1dSRodney W. Grimes continue; 419df8bae1dSRodney W. Grimes } 420df8bae1dSRodney W. Grimes if (tmp) 421df8bae1dSRodney W. Grimes putchar('>', flags, tp); 422df8bae1dSRodney W. Grimes break; 423df8bae1dSRodney W. Grimes case 'c': 424df8bae1dSRodney W. Grimes putchar(va_arg(ap, int), flags, tp); 425df8bae1dSRodney W. Grimes break; 426df8bae1dSRodney W. Grimes case 'r': 427df8bae1dSRodney W. Grimes p = va_arg(ap, char *); 428df8bae1dSRodney W. Grimes kprintf(p, flags, tp, va_arg(ap, va_list)); 429df8bae1dSRodney W. Grimes break; 430df8bae1dSRodney W. Grimes case 's': 431df8bae1dSRodney W. Grimes p = va_arg(ap, char *); 432df8bae1dSRodney W. Grimes while (ch = *p++) 433df8bae1dSRodney W. Grimes putchar(ch, flags, tp); 434df8bae1dSRodney W. Grimes break; 435df8bae1dSRodney W. Grimes case 'd': 436df8bae1dSRodney W. Grimes ul = lflag ? va_arg(ap, long) : va_arg(ap, int); 437df8bae1dSRodney W. Grimes if ((long)ul < 0) { 438df8bae1dSRodney W. Grimes putchar('-', flags, tp); 439df8bae1dSRodney W. Grimes ul = -(long)ul; 440df8bae1dSRodney W. Grimes } 441df8bae1dSRodney W. Grimes base = 10; 442df8bae1dSRodney W. Grimes goto number; 443df8bae1dSRodney W. Grimes case 'o': 444df8bae1dSRodney W. Grimes ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); 445df8bae1dSRodney W. Grimes base = 8; 446df8bae1dSRodney W. Grimes goto number; 447df8bae1dSRodney W. Grimes case 'u': 448df8bae1dSRodney W. Grimes ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); 449df8bae1dSRodney W. Grimes base = 10; 450df8bae1dSRodney W. Grimes goto number; 45112d17f65SPoul-Henning Kamp case 'p': 45212d17f65SPoul-Henning Kamp ul = (u_long) va_arg(ap, void *); 45312d17f65SPoul-Henning Kamp width=8; 45412d17f65SPoul-Henning Kamp base=16; 45512d17f65SPoul-Henning Kamp putchar('0',flags,tp); 45612d17f65SPoul-Henning Kamp putchar('x',flags,tp); 45712d17f65SPoul-Henning Kamp goto number; 458df8bae1dSRodney W. Grimes case 'x': 459df8bae1dSRodney W. Grimes ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); 460df8bae1dSRodney W. Grimes base = 16; 461df8bae1dSRodney W. Grimes number: p = ksprintn(ul, base, &tmp); 462df8bae1dSRodney W. Grimes if (width && (width -= tmp) > 0) 463df8bae1dSRodney W. Grimes while (width--) 464df8bae1dSRodney W. Grimes putchar(padc, flags, tp); 465df8bae1dSRodney W. Grimes while (ch = *p--) 466df8bae1dSRodney W. Grimes putchar(ch, flags, tp); 467df8bae1dSRodney W. Grimes break; 468df8bae1dSRodney W. Grimes default: 469df8bae1dSRodney W. Grimes putchar('%', flags, tp); 470df8bae1dSRodney W. Grimes if (lflag) 471df8bae1dSRodney W. Grimes putchar('l', flags, tp); 472df8bae1dSRodney W. Grimes /* FALLTHROUGH */ 473df8bae1dSRodney W. Grimes case '%': 474df8bae1dSRodney W. Grimes putchar(ch, flags, tp); 475df8bae1dSRodney W. Grimes } 476df8bae1dSRodney W. Grimes } 477df8bae1dSRodney W. Grimes } 478df8bae1dSRodney W. Grimes 479df8bae1dSRodney W. Grimes /* 480df8bae1dSRodney W. Grimes * Print a character on console or users terminal. If destination is 481df8bae1dSRodney W. Grimes * the console then the last MSGBUFS characters are saved in msgbuf for 482df8bae1dSRodney W. Grimes * inspection later. 483df8bae1dSRodney W. Grimes */ 484df8bae1dSRodney W. Grimes static void 485df8bae1dSRodney W. Grimes putchar(c, flags, tp) 486df8bae1dSRodney W. Grimes register int c; 487df8bae1dSRodney W. Grimes int flags; 488df8bae1dSRodney W. Grimes struct tty *tp; 489df8bae1dSRodney W. Grimes { 490df8bae1dSRodney W. Grimes extern int msgbufmapped; 491df8bae1dSRodney W. Grimes register struct msgbuf *mbp; 492df8bae1dSRodney W. Grimes 493df8bae1dSRodney W. Grimes if (panicstr) 494df8bae1dSRodney W. Grimes constty = NULL; 495df8bae1dSRodney W. Grimes if ((flags & TOCONS) && tp == NULL && constty) { 496df8bae1dSRodney W. Grimes tp = constty; 497df8bae1dSRodney W. Grimes flags |= TOTTY; 498df8bae1dSRodney W. Grimes } 499df8bae1dSRodney W. Grimes if ((flags & TOTTY) && tp && tputchar(c, tp) < 0 && 500df8bae1dSRodney W. Grimes (flags & TOCONS) && tp == constty) 501df8bae1dSRodney W. Grimes constty = NULL; 502df8bae1dSRodney W. Grimes if ((flags & TOLOG) && 503df8bae1dSRodney W. Grimes c != '\0' && c != '\r' && c != 0177 && msgbufmapped) { 504df8bae1dSRodney W. Grimes mbp = msgbufp; 505df8bae1dSRodney W. Grimes if (mbp->msg_magic != MSG_MAGIC) { 506df8bae1dSRodney W. Grimes bzero((caddr_t)mbp, sizeof(*mbp)); 507df8bae1dSRodney W. Grimes mbp->msg_magic = MSG_MAGIC; 508df8bae1dSRodney W. Grimes } 509df8bae1dSRodney W. Grimes mbp->msg_bufc[mbp->msg_bufx++] = c; 510df8bae1dSRodney W. Grimes if (mbp->msg_bufx < 0 || mbp->msg_bufx >= MSG_BSIZE) 511df8bae1dSRodney W. Grimes mbp->msg_bufx = 0; 512df8bae1dSRodney W. Grimes } 513df8bae1dSRodney W. Grimes if ((flags & TOCONS) && constty == NULL && c != '\0') 514df8bae1dSRodney W. Grimes (*v_putc)(c); 515df8bae1dSRodney W. Grimes } 516df8bae1dSRodney W. Grimes 517df8bae1dSRodney W. Grimes /* 518df8bae1dSRodney W. Grimes * Scaled down version of sprintf(3). 519df8bae1dSRodney W. Grimes */ 520df8bae1dSRodney W. Grimes #ifdef __STDC__ 52126f9a767SRodney W. Grimes int 522df8bae1dSRodney W. Grimes sprintf(char *buf, const char *cfmt, ...) 523df8bae1dSRodney W. Grimes #else 52426f9a767SRodney W. Grimes int 525df8bae1dSRodney W. Grimes sprintf(buf, cfmt, va_alist) 526df8bae1dSRodney W. Grimes char *buf, *cfmt; 527df8bae1dSRodney W. Grimes #endif 528df8bae1dSRodney W. Grimes { 529df8bae1dSRodney W. Grimes register const char *fmt = cfmt; 530df8bae1dSRodney W. Grimes register char *p, *bp; 531df8bae1dSRodney W. Grimes register int ch, base; 532df8bae1dSRodney W. Grimes u_long ul; 533df8bae1dSRodney W. Grimes int lflag; 534df8bae1dSRodney W. Grimes va_list ap; 535df8bae1dSRodney W. Grimes 536df8bae1dSRodney W. Grimes va_start(ap, cfmt); 537df8bae1dSRodney W. Grimes for (bp = buf; ; ) { 538df8bae1dSRodney W. Grimes while ((ch = *(u_char *)fmt++) != '%') 539df8bae1dSRodney W. Grimes if ((*bp++ = ch) == '\0') 540df8bae1dSRodney W. Grimes return ((bp - buf) - 1); 541df8bae1dSRodney W. Grimes 542df8bae1dSRodney W. Grimes lflag = 0; 543df8bae1dSRodney W. Grimes reswitch: switch (ch = *(u_char *)fmt++) { 544df8bae1dSRodney W. Grimes case 'l': 545df8bae1dSRodney W. Grimes lflag = 1; 546df8bae1dSRodney W. Grimes goto reswitch; 547df8bae1dSRodney W. Grimes case 'c': 548df8bae1dSRodney W. Grimes *bp++ = va_arg(ap, int); 549df8bae1dSRodney W. Grimes break; 550df8bae1dSRodney W. Grimes case 's': 551df8bae1dSRodney W. Grimes p = va_arg(ap, char *); 552df8bae1dSRodney W. Grimes while (*bp++ = *p++) 553df8bae1dSRodney W. Grimes continue; 554df8bae1dSRodney W. Grimes --bp; 555df8bae1dSRodney W. Grimes break; 556df8bae1dSRodney W. Grimes case 'd': 557df8bae1dSRodney W. Grimes ul = lflag ? va_arg(ap, long) : va_arg(ap, int); 558df8bae1dSRodney W. Grimes if ((long)ul < 0) { 559df8bae1dSRodney W. Grimes *bp++ = '-'; 560df8bae1dSRodney W. Grimes ul = -(long)ul; 561df8bae1dSRodney W. Grimes } 562df8bae1dSRodney W. Grimes base = 10; 563df8bae1dSRodney W. Grimes goto number; 564df8bae1dSRodney W. Grimes break; 565df8bae1dSRodney W. Grimes case 'o': 566df8bae1dSRodney W. Grimes ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); 567df8bae1dSRodney W. Grimes base = 8; 568df8bae1dSRodney W. Grimes goto number; 569df8bae1dSRodney W. Grimes break; 570df8bae1dSRodney W. Grimes case 'u': 571df8bae1dSRodney W. Grimes ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); 572df8bae1dSRodney W. Grimes base = 10; 573df8bae1dSRodney W. Grimes goto number; 574df8bae1dSRodney W. Grimes break; 575df8bae1dSRodney W. Grimes case 'x': 576df8bae1dSRodney W. Grimes ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); 577df8bae1dSRodney W. Grimes base = 16; 578df8bae1dSRodney W. Grimes number: for (p = ksprintn(ul, base, NULL); ch = *p--;) 579df8bae1dSRodney W. Grimes *bp++ = ch; 580df8bae1dSRodney W. Grimes break; 581df8bae1dSRodney W. Grimes default: 582df8bae1dSRodney W. Grimes *bp++ = '%'; 583df8bae1dSRodney W. Grimes if (lflag) 584df8bae1dSRodney W. Grimes *bp++ = 'l'; 585df8bae1dSRodney W. Grimes /* FALLTHROUGH */ 586df8bae1dSRodney W. Grimes case '%': 587df8bae1dSRodney W. Grimes *bp++ = ch; 588df8bae1dSRodney W. Grimes } 589df8bae1dSRodney W. Grimes } 590df8bae1dSRodney W. Grimes va_end(ap); 591df8bae1dSRodney W. Grimes } 592df8bae1dSRodney W. Grimes 593df8bae1dSRodney W. Grimes /* 594df8bae1dSRodney W. Grimes * Put a number (base <= 16) in a buffer in reverse order; return an 595df8bae1dSRodney W. Grimes * optional length and a pointer to the NULL terminated (preceded?) 596df8bae1dSRodney W. Grimes * buffer. 597df8bae1dSRodney W. Grimes */ 598df8bae1dSRodney W. Grimes static char * 599df8bae1dSRodney W. Grimes ksprintn(ul, base, lenp) 600df8bae1dSRodney W. Grimes register u_long ul; 601df8bae1dSRodney W. Grimes register int base, *lenp; 602df8bae1dSRodney W. Grimes { /* A long in base 8, plus NULL. */ 603df8bae1dSRodney W. Grimes static char buf[sizeof(long) * NBBY / 3 + 2]; 604df8bae1dSRodney W. Grimes register char *p; 605df8bae1dSRodney W. Grimes 606df8bae1dSRodney W. Grimes p = buf; 607df8bae1dSRodney W. Grimes do { 608df8bae1dSRodney W. Grimes *++p = "0123456789abcdef"[ul % base]; 609df8bae1dSRodney W. Grimes } while (ul /= base); 610df8bae1dSRodney W. Grimes if (lenp) 611df8bae1dSRodney W. Grimes *lenp = p - buf; 612df8bae1dSRodney W. Grimes return (p); 613df8bae1dSRodney W. Grimes } 614