1/* 2 * Copyright (c) 2000-2006 Apple Computer, Inc. All rights reserved. 3 * 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. The rights granted to you under the License 10 * may not be used to create, or enable the creation or redistribution of, 11 * unlawful or unlicensed copies of an Apple operating system, or to 12 * circumvent, violate, or enable the circumvention or violation of, any 13 * terms of an Apple operating system software license agreement. 14 * 15 * Please obtain a copy of the License at 16 * http://www.opensource.apple.com/apsl/ and read it before using this file. 17 * 18 * The Original Code and all software distributed under the License are 19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 23 * Please see the License for the specific language governing rights and 24 * limitations under the License. 25 * 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27 */ 28/* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */ 29/*- 30 * Copyright (c) 1986, 1988, 1991, 1993 31 * The Regents of the University of California. All rights reserved. 32 * (c) UNIX System Laboratories, Inc. 33 * All or some portions of this file are derived from material licensed 34 * to the University of California by American Telephone and Telegraph 35 * Co. or Unix System Laboratories, Inc. and are reproduced herein with 36 * the permission of UNIX System Laboratories, Inc. 37 * 38 * Redistribution and use in source and binary forms, with or without 39 * modification, are permitted provided that the following conditions 40 * are met: 41 * 1. Redistributions of source code must retain the above copyright 42 * notice, this list of conditions and the following disclaimer. 43 * 2. Redistributions in binary form must reproduce the above copyright 44 * notice, this list of conditions and the following disclaimer in the 45 * documentation and/or other materials provided with the distribution. 46 * 3. All advertising materials mentioning features or use of this software 47 * must display the following acknowledgement: 48 * This product includes software developed by the University of 49 * California, Berkeley and its contributors. 50 * 4. Neither the name of the University nor the names of its contributors 51 * may be used to endorse or promote products derived from this software 52 * without specific prior written permission. 53 * 54 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 55 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 56 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 57 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 58 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 59 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 60 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 61 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 62 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 63 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 64 * SUCH DAMAGE. 65 * 66 * @(#)subr_prf.c 8.4 (Berkeley) 5/4/95 67 */ 68/* HISTORY 69 * 22-Sep-1997 Umesh Vaishampayan (umeshv@apple.com) 70 * Cleaned up m68k crud. Fixed vlog() to do logpri() for ppc, too. 71 * 72 * 17-July-97 Umesh Vaishampayan (umeshv@apple.com) 73 * Eliminated multiple definition of constty which is defined 74 * in bsd/dev/XXX/cons.c 75 * 76 * 26-MAR-1997 Umesh Vaishampayan (umeshv@NeXT.com 77 * Fixed tharshing format in many functions. Cleanup. 78 * 79 * 17-Jun-1995 Mac Gillon (mgillon) at NeXT 80 * Purged old history 81 * New version based on 4.4 and NS3.3 82 */ 83 84#include <sys/param.h> 85#include <sys/systm.h> 86#include <sys/conf.h> 87#include <sys/reboot.h> 88#include <sys/msgbuf.h> 89#include <sys/proc_internal.h> 90#include <sys/ioctl.h> 91#include <sys/tty.h> 92#include <sys/file_internal.h> 93#include <sys/tprintf.h> 94#include <sys/syslog.h> 95#include <stdarg.h> 96#include <sys/malloc.h> 97#include <sys/lock.h> 98#include <sys/subr_prf.h> 99 100#include <kern/cpu_number.h> /* for cpu_number() */ 101#include <machine/spl.h> 102#include <libkern/libkern.h> 103 104/* for vaddlog(): the following are implemented in osfmk/kern/printf.c */ 105extern void bsd_log_lock(void); 106extern void bsd_log_unlock(void); 107 108/* Keep this around only because it's exported */ 109void _printf(int, struct tty *, const char *, ...); 110 111struct snprintf_arg { 112 char *str; 113 size_t remain; 114}; 115 116 117/* 118 * In case console is off, 119 * panicstr contains argument to last 120 * call to panic. 121 */ 122extern const char *panicstr; 123 124extern void cnputc(char); /* standard console putc */ 125void (*v_putc)(char) = cnputc; /* routine to putc on virtual console */ 126 127extern struct tty cons; /* standard console tty */ 128extern struct tty *constty; /* pointer to console "window" tty */ 129extern int __doprnt(const char *fmt, 130 va_list argp, 131 void (*)(int, void *), 132 void *arg, 133 int radix); 134 135/* 136 * Record cpu that panic'd and lock around panic data 137 */ 138static void printn(uint32_t n, int b, int flags, struct tty *ttyp, int zf, int fld_size); 139 140extern void logwakeup(void); 141extern void halt_cpu(void); 142 143static void 144snprintf_func(int ch, void *arg); 145 146struct putchar_args { 147 int flags; 148 struct tty *tty; 149}; 150static void putchar(int c, void *arg); 151 152 153/* 154 * Uprintf prints to the controlling terminal for the current process. 155 * It may block if the tty queue is overfull. No message is printed if 156 * the queue does not clear in a reasonable time. 157 */ 158void 159uprintf(const char *fmt, ...) 160{ 161 struct proc *p = current_proc(); 162 struct putchar_args pca; 163 va_list ap; 164 struct session *sessp; 165 166 sessp = proc_session(p); 167 168 if (p->p_flag & P_CONTROLT && sessp != SESSION_NULL && sessp->s_ttyvp) { 169 pca.flags = TOTTY; 170 pca.tty = SESSION_TP(sessp); 171 if (pca.tty != NULL) 172 tty_lock(pca.tty); 173 va_start(ap, fmt); 174 __doprnt(fmt, ap, putchar, &pca, 10); 175 va_end(ap); 176 if (pca.tty != NULL) 177 tty_unlock(pca.tty); 178 } 179 if (sessp != SESSION_NULL) 180 session_rele(sessp); 181} 182 183tpr_t 184tprintf_open(struct proc *p) 185{ 186 struct session * sessp; 187 188 sessp = proc_session(p); 189 190 if (p->p_flag & P_CONTROLT && sessp->s_ttyvp) { 191 return ((tpr_t)sessp); 192 } 193 if (sessp != SESSION_NULL) 194 session_rele(sessp); 195 196 return ((tpr_t) NULL); 197} 198 199void 200tprintf_close(tpr_t sessp) 201{ 202 if (sessp) 203 session_rele((struct session *) sessp); 204} 205 206/* 207 * tprintf prints on the controlling terminal associated 208 * with the given session. 209 * 210 * NOTE: No one else should call this function!!! 211 */ 212void 213tprintf(tpr_t tpr, const char *fmt, ...) 214{ 215 struct session *sess = (struct session *)tpr; 216 struct tty *tp = TTY_NULL; 217 int flags = TOLOG; 218 va_list ap; 219 struct putchar_args pca; 220 221 logpri(LOG_INFO); 222 223 if (sess && (tp = SESSION_TP(sess)) != TTY_NULL) { 224 /* ttycheckoutq(), tputchar() require a locked tp */ 225 tty_lock(tp); 226 if(ttycheckoutq(tp, 0)) { 227 flags |= TOTTY; 228 /* going to the tty; leave locked */ 229 } else { 230 /* not going to the tty... */ 231 tty_unlock(tp); 232 tp = TTY_NULL; 233 } 234 } 235 236 pca.flags = flags; 237 pca.tty = tp; 238 va_start(ap, fmt); 239 __doprnt(fmt, ap, putchar, &pca, 10); 240 va_end(ap); 241 242 if (tp != NULL) 243 tty_unlock(tp); /* lock/unlock is guarded by tp, above */ 244 245 logwakeup(); 246} 247 248/* 249 * Ttyprintf displays a message on a tty; it should be used only by 250 * the tty driver, or anything that knows the underlying tty will not 251 * be revoke(2)'d away. Other callers should use tprintf. 252 * 253 * Locks: It is assumed that the tty_lock() is held over the call 254 * to this function. Ensuring this is the responsibility 255 * of the caller. 256 */ 257void 258ttyprintf(struct tty *tp, const char *fmt, ...) 259{ 260 va_list ap; 261 262 if (tp != NULL) { 263 struct putchar_args pca; 264 pca.flags = TOTTY; 265 pca.tty = tp; 266 267 va_start(ap, fmt); 268 __doprnt(fmt, ap, putchar, &pca, 10); 269 va_end(ap); 270 } 271} 272 273 274extern int log_open; 275 276 277void 278logpri(int level) 279{ 280 struct putchar_args pca; 281 pca.flags = TOLOG; 282 pca.tty = NULL; 283 284 putchar('<', &pca); 285 printn((uint32_t)level, 10, TOLOG, (struct tty *)0, 0, 0); 286 putchar('>', &pca); 287} 288 289static void 290_logtime(const char *fmt, ...) 291{ 292 va_list ap; 293 va_start(ap, fmt); 294 vaddlog(fmt, ap); 295 va_end(ap); 296} 297 298void 299logtime(time_t secs) 300{ 301 _logtime(" 0 [Time %ld] [Message ", secs); 302} 303 304int 305vaddlog(const char *fmt, va_list ap) 306{ 307 struct putchar_args pca; 308 309 pca.flags = TOLOGLOCKED; 310 pca.tty = NULL; 311 312 if (!log_open) { 313 pca.flags |= TOCONS; 314 } 315 316 bsd_log_lock(); 317 __doprnt(fmt, ap, putchar, &pca, 10); 318 bsd_log_unlock(); 319 320 logwakeup(); 321 return 0; 322} 323 324void 325_printf(int flags, struct tty *ttyp, const char *format, ...) 326{ 327 va_list ap; 328 struct putchar_args pca; 329 330 pca.flags = flags; 331 pca.tty = ttyp; 332 333 if (ttyp != NULL) { 334 tty_lock(ttyp); 335 336 va_start(ap, format); 337 __doprnt(format, ap, putchar, &pca, 10); 338 va_end(ap); 339 340 tty_unlock(ttyp); 341 } 342} 343 344int 345prf(const char *fmt, va_list ap, int flags, struct tty *ttyp) 346{ 347 struct putchar_args pca; 348 349 pca.flags = flags; 350 pca.tty = ttyp; 351 352 __doprnt(fmt, ap, putchar, &pca, 10); 353 354 return 0; 355} 356 357/* 358 * Printn prints a number n in base b. 359 * We don't use recursion to avoid deep kernel stacks. 360 */ 361static void 362printn(uint32_t n, int b, int flags, struct tty *ttyp, int zf, int fld_size) 363{ 364 char prbuf[11]; 365 char *cp; 366 struct putchar_args pca; 367 368 pca.flags = flags; 369 pca.tty = ttyp; 370 371 if (b == 10 && (int)n < 0) { 372 putchar('-', &pca); 373 n = (unsigned)(-(int)n); 374 } 375 cp = prbuf; 376 do { 377 *cp++ = "0123456789abcdef"[n%b]; 378 n /= b; 379 } while (n); 380 if (fld_size) { 381 for (fld_size -= cp - prbuf; fld_size > 0; fld_size--) 382 if (zf) 383 putchar('0', &pca); 384 else 385 putchar(' ', &pca); 386 } 387 do 388 putchar(*--cp, &pca); 389 while (cp > prbuf); 390} 391 392 393 394/* 395 * Warn that a system table is full. 396 */ 397void tablefull(const char *tab) 398{ 399 log(LOG_ERR, "%s: table is full\n", tab); 400} 401 402/* 403 * Print a character on console or users terminal. 404 * If destination is console then the last MSGBUFS characters 405 * are saved in msgbuf for inspection later. 406 * 407 * Locks: If TOTTY is set, we assume that the tty lock is held 408 * over the call to this function. 409 */ 410/*ARGSUSED*/ 411void 412putchar(int c, void *arg) 413{ 414 struct putchar_args *pca = arg; 415 char **sp = (char**) pca->tty; 416 417 if (panicstr) 418 constty = 0; 419 if ((pca->flags & TOCONS) && pca->tty == NULL && constty) { 420 pca->tty = constty; 421 pca->flags |= TOTTY; 422 } 423 if ((pca->flags & TOTTY) && pca->tty && tputchar(c, pca->tty) < 0 && 424 (pca->flags & TOCONS) && pca->tty == constty) 425 constty = 0; 426 if ((pca->flags & TOLOG) && c != '\0' && c != '\r' && c != 0177) 427 log_putc(c); 428 if ((pca->flags & TOLOGLOCKED) && c != '\0' && c != '\r' && c != 0177) 429 log_putc_locked(c); 430 if ((pca->flags & TOCONS) && constty == 0 && c != '\0') 431 (*v_putc)(c); 432 if (pca->flags & TOSTR) { 433 **sp = c; 434 (*sp)++; 435 } 436} 437 438int 439vprintf(const char *fmt, va_list ap) 440{ 441 struct putchar_args pca; 442 443 pca.flags = TOLOG | TOCONS; 444 pca.tty = NULL; 445 __doprnt(fmt, ap, putchar, &pca, 10); 446 return 0; 447} 448 449 450/* 451 * Scaled down version of vsprintf(3). 452 * 453 * Deprecation Warning: 454 * vsprintf() is being deprecated. Please use vsnprintf() instead. 455 */ 456int 457vsprintf(char *buf, const char *cfmt, va_list ap) 458{ 459 int retval; 460 struct snprintf_arg info; 461 462 info.str = buf; 463 info.remain = 999999; 464 465 retval = __doprnt(cfmt, ap, snprintf_func, &info, 10); 466 if (info.remain >= 1) { 467 *info.str++ = '\0'; 468 } 469 return 0; 470} 471 472/* 473 * Scaled down version of snprintf(3). 474 */ 475int 476snprintf(char *str, size_t size, const char *format, ...) 477{ 478 int retval; 479 va_list ap; 480 481 va_start(ap, format); 482 retval = vsnprintf(str, size, format, ap); 483 va_end(ap); 484 return(retval); 485} 486 487/* 488 * Scaled down version of vsnprintf(3). 489 */ 490int 491vsnprintf(char *str, size_t size, const char *format, va_list ap) 492{ 493 struct snprintf_arg info; 494 int retval; 495 496 info.str = str; 497 info.remain = size; 498 retval = __doprnt(format, ap, snprintf_func, &info, 10); 499 if (info.remain >= 1) 500 *info.str++ = '\0'; 501 return retval; 502} 503 504static void 505snprintf_func(int ch, void *arg) 506{ 507 struct snprintf_arg *const info = arg; 508 509 if (info->remain >= 2) { 510 *info->str++ = ch; 511 info->remain--; 512 } 513} 514 515int 516kvprintf(char const *fmt, void (*func)(int, void*), void *arg, int radix, va_list ap) 517{ 518 __doprnt(fmt, ap, func, arg, radix); 519 return 0; 520} 521 522