flowtop: Print error cause if errno is set when panic
[netsniff-ng.git] / tprintf.c
blob0ca2375be503d780290a16421628116fd42a3704
1 /*
2 * netsniff-ng - the packet sniffing beast
3 * Copyright 2009, 2010 Daniel Borkmann.
4 * Copyright 2013 Tobias Klauser.
5 * Subject to the GPL, version 2.
6 */
8 #define _BSD_SOURCE
9 #include <ctype.h>
10 #include <stdio.h>
11 #include <stdarg.h>
12 #include <sys/ioctl.h>
14 #include "tprintf.h"
15 #include "die.h"
16 #include "locking.h"
17 #include "built_in.h"
19 #define term_trailing_size 5
20 #define term_starting_size 3
22 #define term_curr_size (get_tty_size() - term_trailing_size)
24 static char buffer[1024];
26 static volatile size_t buffer_use = 0;
28 static struct spinlock buffer_lock;
30 static int get_tty_size(void)
32 #ifdef TIOCGSIZE
33 struct ttysize ts = {0};
35 return (ioctl(0, TIOCGSIZE, &ts) == 0 ? ts.ts_cols : DEFAULT_TTY_SIZE);
36 #elif defined(TIOCGWINSZ)
37 struct winsize ts;
39 return (ioctl(0, TIOCGWINSZ, &ts) == 0 ? ts.ws_col : DEFAULT_TTY_SIZE);
40 #else
41 return DEFAULT_TTY_SIZE;
42 #endif
45 static inline void __tprintf_flush_newline(void)
47 int i;
49 fputc('\n', stdout);
50 for (i = 0; i < term_starting_size; ++i)
51 fputc(' ', stdout);
54 static inline int __tprintf_flush_skip(char *buf, int i)
56 int val = buf[i];
58 if (val == ' ' || val == ',')
59 return 1;
61 return 0;
64 static void __tprintf_flush(void)
66 size_t i;
67 static ssize_t line_count = 0;
68 ssize_t term_len = term_curr_size;
70 for (i = 0; i < buffer_use; ++i) {
71 if (buffer[i] == '\n') {
72 term_len = term_curr_size;
73 line_count = -1;
76 if (line_count == term_len) {
77 __tprintf_flush_newline();
78 line_count = term_starting_size;
80 while (i < buffer_use &&
81 __tprintf_flush_skip(buffer, i))
82 i++;
85 fputc(buffer[i], stdout);
86 line_count++;
89 fflush(stdout);
90 buffer_use = 0;
93 void tprintf_flush(void)
95 spinlock_lock(&buffer_lock);
96 __tprintf_flush();
97 spinlock_unlock(&buffer_lock);
100 void tprintf_init(void)
102 spinlock_init(&buffer_lock);
104 setvbuf(stdout, NULL, _IONBF, 0);
105 setvbuf(stderr, NULL, _IONBF, 0);
108 void tprintf_cleanup(void)
110 tprintf_flush();
111 spinlock_destroy(&buffer_lock);
114 void tprintf(char *msg, ...)
116 ssize_t ret;
117 ssize_t avail;
118 va_list vl;
120 spinlock_lock(&buffer_lock);
122 avail = sizeof(buffer) - buffer_use;
123 bug_on(avail < 0);
125 va_start(vl, msg);
126 ret = vsnprintf(buffer + buffer_use, avail, msg, vl);
127 va_end(vl);
129 if (ret < 0)
130 panic("vsnprintf screwed up in tprintf!\n");
131 if ((size_t) ret > sizeof(buffer))
132 panic("No mem in tprintf left!\n");
133 if (ret >= avail) {
134 __tprintf_flush();
136 avail = sizeof(buffer) - buffer_use;
137 bug_on(avail < 0);
139 va_start(vl, msg);
140 ret = vsnprintf(buffer + buffer_use, avail, msg, vl);
141 va_end(vl);
143 if (ret < 0)
144 panic("vsnprintf screwed up in tprintf!\n");
147 buffer_use += ret;
149 spinlock_unlock(&buffer_lock);
152 void tputchar_safe(int c)
154 unsigned char ch = (unsigned char)(c & 0xff);
156 if (isprint(ch))
157 tprintf("%c", ch);
158 else
159 tprintf("\\0x%02x", ch);
162 void tputs_safe(const char *str, size_t len)
164 while (len--) {
165 tputchar_safe(*str);
166 str++;