1 /*
2  * (c) 2008-2009 Adam Lackorzynski <adam@os.inf.tu-dresden.de>,
3  *               Alexander Warg <warg@os.inf.tu-dresden.de>
4  *     economic rights: Technische Universität Dresden (Germany)
5  *
6  * This file is part of TUD:OS and distributed under the terms of the
7  * GNU General Public License 2.
8  * Please see the COPYING-GPL-2 file for details.
9  */
10 #include <l4/re/log>
11 #include <l4/re/log-sys.h>
12 #include <l4/sys/kdebug.h>
13 #include <l4/cxx/minmax>
14 
15 #include "globals.h"
16 #include "log.h"
17 
18 #include <unistd.h>
19 #include <cstdio>
20 #include <stdarg.h>
21 
22 static Moe::Log *last_log = 0;
23 
24 class Pbuf
25 {
26 public:
Pbuf()27   Pbuf() : _p(0) {}
size() const28   unsigned long size() const { return sizeof(_b); }
29   void flush();
30   void printf(char const *fmt, ...)
31     __attribute__((format(printf, 2, 3)));
32   void outnstring(char const *str, unsigned long len);
33 
34 private:
35   void checknflush(int n);
36   char _b[1024];
37   unsigned long _p;
38 
fits(unsigned l) const39   bool fits(unsigned l) const { return (_p + l) < sizeof(_b); }
40 };
41 
my_outnstring(char const * s,unsigned long len)42 static void my_outnstring(char const *s, unsigned long len)
43 {
44   write(1, s, len);
45 }
46 
47 
48 
flush()49 void Pbuf::flush()
50 {
51   my_outnstring(_b, _p);
52   _p = 0;
53 }
54 
checknflush(int n)55 void Pbuf::checknflush(int n)
56 {
57   char *x = 0;
58   x = (char*)memchr(_b, '\n', _p + n);
59 
60   if (x)
61     {
62       int rem = n - (x - _b + 1 - _p);
63       _p = x - _b + 1;
64       flush();
65       if (rem)
66         memmove(_b, x + 1, rem);
67       _p = rem;
68     }
69   else
70     _p += n;
71 }
72 
printf(char const * fmt,...)73 void Pbuf::printf(char const *fmt, ...)
74 {
75   if (!fits(strlen(fmt) + 50))
76     flush();
77   int n;
78   va_list arg;
79   va_start(arg, fmt);
80   n = vsnprintf(_b + _p, size() - _p, fmt, arg);
81   va_end(arg);
82   checknflush(n);
83 }
84 
outnstring(char const * str,unsigned long len)85 void Pbuf::outnstring(char const *str, unsigned long len)
86 {
87   if (!fits(len))
88     flush();
89   memcpy(_b + _p, str, len);
90   checknflush(len);
91 }
92 
93 l4_msgtag_t
op_dispatch(l4_utcb_t * utcb,l4_msgtag_t tag,L4::Vcon::Rights)94 Moe::Log::op_dispatch(l4_utcb_t *utcb, l4_msgtag_t tag, L4::Vcon::Rights)
95 {
96   enum { Max_tag = 8 };
97   if (tag.words() < 2)
98     return l4_msgtag(-L4_EINVAL, 0, 0, 0);
99 
100   l4_msg_regs_t *m = l4_utcb_mr_u(utcb);
101   L4::Opcode op = m->mr[0];
102 
103   // we only have one opcode
104   if (op != L4Re::Log_::Print)
105     return l4_msgtag(-L4_ENOSYS, 0, 0, 0);
106 
107   char *msg = log_buffer;
108   unsigned long len_msg = sizeof(log_buffer);
109 
110   if (len_msg > (tag.words() - 2) * sizeof(l4_umword_t))
111     len_msg = (tag.words() - 2) * sizeof(l4_umword_t);
112 
113   if (len_msg > m->mr[1])
114     len_msg = m->mr[1];
115 
116   memcpy(msg, &m->mr[2], len_msg);
117 
118   static Pbuf ob;
119 
120   while (len_msg > 0 && msg[0])
121     {
122       if (color())
123         ob.printf("\033[%s3%dm", (color() & 8) ? "01;" : "", (color() & 7));
124       else
125         ob.printf("\033[0m");
126 
127       if (last_log != this)
128         {
129           if (last_log != 0)
130             ob.printf("\n");
131 
132           ob.outnstring(_tag, cxx::min<unsigned long>(_l, Max_tag));
133           if (_l < Max_tag)
134             ob.outnstring("             ", Max_tag-_l);
135 
136           if (_in_line)
137             ob.printf(": ");
138           else
139             ob.printf("| ");
140         }
141 
142       long i;
143       for (i = 0; i < (long)len_msg; ++i)
144         if (msg[i] == '\n' || msg[i] == 0)
145           break;
146 
147       ob.outnstring(msg, i);
148 
149       if (i < (long)len_msg && msg[i] == '\n')
150         {
151           if (color())
152             ob.printf("\033[0m\n");
153           else
154             ob.printf("\n");
155           _in_line = false;
156           last_log = 0;
157           ++i;
158         }
159       else
160         {
161           last_log = this;
162           _in_line = true;
163         }
164 
165       msg += i;
166       len_msg -= i;
167     }
168 
169   if (_in_line && color())
170     ob.printf("\033[0m");
171 
172   // and finally done
173   return l4_msgtag(-L4_ENOREPLY, 0, 0, 0);
174 }
175 
176 
177 int
color_value(cxx::String const & col)178 Moe::Log::color_value(cxx::String const &col)
179 {
180   int c = 0, bright = 0;
181 
182   if (col.empty())
183     return 0;
184 
185   switch (col[0])
186     {
187     case 'N': bright = 1; /* FALLTHRU */ case 'n': c = 0; break;
188     case 'R': bright = 1; /* FALLTHRU */ case 'r': c = 1; break;
189     case 'G': bright = 1; /* FALLTHRU */ case 'g': c = 2; break;
190     case 'Y': bright = 1; /* FALLTHRU */ case 'y': c = 3; break;
191     case 'B': bright = 1; /* FALLTHRU */ case 'b': c = 4; break;
192     case 'M': bright = 1; /* FALLTHRU */ case 'm': c = 5; break;
193     case 'C': bright = 1; /* FALLTHRU */ case 'c': c = 6; break;
194     case 'W': bright = 1; /* FALLTHRU */ case 'w': c = 7; break;
195     default: c = 0;
196     }
197 
198   return (bright << 3) | c;
199 }
200 
201 
202