#include <sys/param.h>
#include <sys/systm.h>
#include <sys/conf.h>
#include <sys/reboot.h>
#include <sys/msgbuf.h>
#include <sys/proc_internal.h>
#include <sys/ioctl.h>
#include <sys/tty.h>
#include <sys/file_internal.h>
#include <sys/tprintf.h>
#include <sys/syslog.h>
#include <stdarg.h>
#include <sys/malloc.h>
#include <sys/lock.h>
#include <sys/subr_prf.h>
#include <kern/cpu_number.h>
#include <libkern/libkern.h>
#include <os/log_private.h>
extern void bsd_log_lock(void);
extern void bsd_log_unlock(void);
void _printf(int, struct tty *, const char *, ...);
struct snprintf_arg {
char *str;
size_t remain;
};
extern const char *debugger_panic_str;
extern void cnputc(char);
void (*v_putc)(char) = cnputc;
extern struct tty cons;
extern struct tty *constty;
extern int __doprnt(const char *fmt,
va_list argp,
void (*)(int, void *),
void *arg,
int radix,
int is_log);
extern void logwakeup(struct msgbuf *);
extern void halt_cpu(void);
static void
snprintf_func(int ch, void *arg);
struct putchar_args {
int flags;
struct tty *tty;
};
static void putchar(int c, void *arg);
void
uprintf(const char *fmt, ...)
{
struct proc *p = current_proc();
struct putchar_args pca;
va_list ap;
struct session *sessp;
sessp = proc_session(p);
if (p->p_flag & P_CONTROLT && sessp != SESSION_NULL && sessp->s_ttyvp) {
pca.flags = TOTTY;
pca.tty = SESSION_TP(sessp);
if (pca.tty != NULL) {
tty_lock(pca.tty);
}
va_start(ap, fmt);
__doprnt(fmt, ap, putchar, &pca, 10, FALSE);
va_end(ap);
if (pca.tty != NULL) {
tty_unlock(pca.tty);
}
}
if (sessp != SESSION_NULL) {
session_rele(sessp);
}
}
tpr_t
tprintf_open(struct proc *p)
{
struct session * sessp;
sessp = proc_session(p);
if (p->p_flag & P_CONTROLT && sessp->s_ttyvp) {
return (tpr_t)sessp;
}
if (sessp != SESSION_NULL) {
session_rele(sessp);
}
return (tpr_t) NULL;
}
void
tprintf_close(tpr_t sessp)
{
if (sessp) {
session_rele((struct session *) sessp);
}
}
void
tprintf(tpr_t tpr, const char *fmt, ...)
{
struct session *sess = (struct session *)tpr;
struct tty *tp;
va_list ap;
struct putchar_args pca;
if (sess && (tp = SESSION_TP(sess)) != TTY_NULL) {
tty_lock(tp);
if (ttycheckoutq(tp, 0)) {
pca.flags = TOTTY;
pca.tty = tp;
va_start(ap, fmt);
__doprnt(fmt, ap, putchar, &pca, 10, FALSE);
va_end(ap);
}
tty_unlock(tp);
}
pca.flags = TOLOG;
pca.tty = TTY_NULL;
va_start(ap, fmt);
__doprnt(fmt, ap, putchar, &pca, 10, TRUE);
va_end(ap);
logwakeup(msgbufp);
va_start(ap, fmt);
os_log_with_args(OS_LOG_DEFAULT, OS_LOG_TYPE_DEFAULT, fmt, ap, __builtin_return_address(0));
va_end(ap);
}
void
ttyprintf(struct tty *tp, const char *fmt, ...)
{
va_list ap;
if (tp != NULL) {
struct putchar_args pca;
pca.flags = TOTTY;
pca.tty = tp;
va_start(ap, fmt);
__doprnt(fmt, ap, putchar, &pca, 10, TRUE);
va_end(ap);
}
}
void
logtime(time_t secs)
{
printf("Time %ld Message ", secs);
}
static void
putchar_asl(int c, void *arg)
{
struct putchar_args *pca = arg;
if ((pca->flags & TOLOGLOCKED) && c != '\0' && c != '\r' && c != 0177) {
log_putc_locked(aslbufp, c);
}
putchar(c, arg);
}
int
vaddlog(const char *fmt, va_list ap)
{
struct putchar_args pca = {
.flags = TOLOGLOCKED,
.tty = NULL,
};
bsd_log_lock();
__doprnt(fmt, ap, putchar_asl, &pca, 10, TRUE);
bsd_log_unlock();
logwakeup(NULL);
return 0;
}
void
_printf(int flags, struct tty *ttyp, const char *format, ...)
{
va_list ap;
struct putchar_args pca;
pca.flags = flags;
pca.tty = ttyp;
if (ttyp != NULL) {
tty_lock(ttyp);
va_start(ap, format);
__doprnt(format, ap, putchar, &pca, 10, TRUE);
va_end(ap);
tty_unlock(ttyp);
}
}
int
prf(const char *fmt, va_list ap, int flags, struct tty *ttyp)
{
struct putchar_args pca;
pca.flags = flags;
pca.tty = ttyp;
__doprnt(fmt, ap, putchar, &pca, 10, TRUE);
return 0;
}
void
tablefull(const char *tab)
{
log(LOG_ERR, "%s: table is full\n", tab);
}
void
putchar(int c, void *arg)
{
struct putchar_args *pca = arg;
char **sp = (char**) pca->tty;
if (debugger_panic_str) {
constty = 0;
}
if ((pca->flags & TOCONS) && pca->tty == NULL && constty) {
pca->tty = constty;
pca->flags |= TOTTY;
}
if ((pca->flags & TOTTY) && pca->tty && tputchar(c, pca->tty) < 0 &&
(pca->flags & TOCONS) && pca->tty == constty) {
constty = 0;
}
if ((pca->flags & TOLOG) && c != '\0' && c != '\r' && c != 0177) {
log_putc(c);
}
if ((pca->flags & TOLOGLOCKED) && c != '\0' && c != '\r' && c != 0177) {
log_putc_locked(msgbufp, c);
}
if ((pca->flags & TOCONS) && constty == 0 && c != '\0') {
(*v_putc)(c);
}
if (pca->flags & TOSTR) {
**sp = c;
(*sp)++;
}
}
int
vprintf_log_locked(const char *fmt, va_list ap, bool addcr)
{
struct putchar_args pca;
pca.flags = TOLOGLOCKED;
pca.tty = NULL;
__doprnt(fmt, ap, putchar, &pca, 10, TRUE);
if (addcr) {
putchar('\n', &pca);
}
return 0;
}
#if !CONFIG_EMBEDDED
int
vsprintf(char *buf, const char *cfmt, va_list ap)
{
int retval;
struct snprintf_arg info;
info.str = buf;
info.remain = 999999;
retval = __doprnt(cfmt, ap, snprintf_func, &info, 10, FALSE);
if (info.remain >= 1) {
*info.str++ = '\0';
}
return 0;
}
#endif
int
snprintf(char *str, size_t size, const char *format, ...)
{
int retval;
va_list ap;
va_start(ap, format);
retval = vsnprintf(str, size, format, ap);
va_end(ap);
return retval;
}
int
vsnprintf(char *str, size_t size, const char *format, va_list ap)
{
struct snprintf_arg info;
int retval;
info.str = str;
info.remain = size;
retval = __doprnt(format, ap, snprintf_func, &info, 10, FALSE);
if (info.remain >= 1) {
*info.str++ = '\0';
}
return retval;
}
int
vscnprintf(char *buf, size_t size, const char *fmt, va_list args)
{
ssize_t ssize = size;
int i;
i = vsnprintf(buf, size, fmt, args);
return (i >= ssize) ? (ssize - 1) : i;
}
int
scnprintf(char *buf, size_t size, const char *fmt, ...)
{
va_list args;
int i;
va_start(args, fmt);
i = vscnprintf(buf, size, fmt, args);
va_end(args);
return i;
}
static void
snprintf_func(int ch, void *arg)
{
struct snprintf_arg *const info = arg;
if (info->remain >= 2) {
*info->str++ = ch;
info->remain--;
}
}
int
kvprintf(char const *fmt, void (*func)(int, void*), void *arg, int radix, va_list ap)
{
__doprnt(fmt, ap, func, arg, radix, TRUE);
return 0;
}