build and link static libraries without libtool
[vuplus_dvbapp] / main / bsod.cpp
1 #include <string.h>
2 #include <signal.h>
3 #include <asm/ptrace.h>
4
5 #include <lib/base/eenv.h>
6 #include <lib/base/eerror.h>
7 #include <lib/base/smartptr.h>
8 #include <lib/base/nconfig.h>
9 #include <lib/gdi/grc.h>
10 #include <lib/gdi/gfbdc.h>
11 #ifdef WITH_SDL
12 #include <lib/gdi/sdl.h>
13 #endif
14
15 #include "version.h"
16
17 /************************************************/
18
19 #define CRASH_EMAILADDR "crashlog@dream-multimedia-tv.de"
20 #define STDBUFFER_SIZE 512
21 #define RINGBUFFER_SIZE 16384
22 static char ringbuffer[RINGBUFFER_SIZE];
23 static int ringbuffer_head;
24
25 static void addToLogbuffer(const char *data, int len)
26 {
27         while (len)
28         {
29                 int remaining = RINGBUFFER_SIZE - ringbuffer_head;
30         
31                 if (remaining > len)
32                         remaining = len;
33         
34                 memcpy(ringbuffer + ringbuffer_head, data, remaining);
35                 len -= remaining;
36                 data += remaining;
37                 ringbuffer_head += remaining;
38                 if (ringbuffer_head >= RINGBUFFER_SIZE)
39                         ringbuffer_head = 0;
40         }
41 }
42
43 static std::string getLogBuffer()
44 {
45         int begin = ringbuffer_head;
46         while (ringbuffer[begin] == 0)
47         {
48                 ++begin;
49                 if (begin == RINGBUFFER_SIZE)
50                         begin = 0;
51                 if (begin == ringbuffer_head)
52                         return "";
53         }
54         if (begin < ringbuffer_head)
55                 return std::string(ringbuffer + begin, ringbuffer_head - begin);
56         else
57         {
58                 return std::string(ringbuffer + begin, RINGBUFFER_SIZE - begin) + std::string(ringbuffer, ringbuffer_head);
59         }
60 }
61
62 static void addToLogbuffer(int level, const std::string &log)
63 {
64         addToLogbuffer(log.c_str(), log.size());
65 }
66
67 static std::string getConfigFileValue(const char *entry)
68 {
69         std::string configfile = eEnv::resolve("${sysconfdir}/enigma2/settings");
70         std::string configvalue;
71         if (entry)
72         {
73                 ePythonConfigQuery::getConfigValue(entry, configvalue);
74                 if (configvalue != "") //we get at least the default value if python is still alive
75                 {
76                         return configvalue;
77                 }
78                 else // get value from enigma2 settings file
79                 {
80                         FILE *f = fopen(configfile.c_str(), "r");
81                         if (!f)
82                         {
83                                 return "Error";
84                         }
85                         while (1)
86                         {
87                                 char line[1024];
88                                 if (!fgets(line, 1024, f))
89                                         break;
90                                 if (!strncmp(line, entry, strlen(entry) ))
91                                 {
92                                         if (strlen(line) && line[strlen(line)-1] == '\r')
93                                                 line[strlen(line)-1] = 0;
94                                         if (strlen(line) && line[strlen(line)-1] == '\n')
95                                                 line[strlen(line)-1] = 0;
96                                         std::string tmp = line;
97                                         int posEqual = tmp.find("=", 0);
98                                         configvalue = tmp.substr(posEqual+1);
99                                 }
100                         }
101                         fclose(f);
102                         return configvalue;
103                 }
104         }
105 }
106
107 static std::string getFileContent(const char *file)
108 {
109         std::string filecontent;
110
111         if (file)
112         {
113                 FILE *f = fopen(file, "r");
114                 if (!f)
115                 {
116                         return "Error";
117                 }
118                 while (1)
119                 {
120                         char line[1024];
121                         if (!fgets(line, 1024, f))
122                                 break;
123                         std::string tmp = line;
124                         std::string password;
125                         int pwdpos = tmp.find(".password=", 0);
126                         if( pwdpos != std::string::npos)
127                         {
128                                 filecontent += tmp.substr(0,pwdpos +10);
129                                 for ( int pos = pwdpos +10; pos < tmp.length()-1; ++pos )
130                                 {
131                                         filecontent += "X";
132                                 }
133                                 filecontent += "\n";
134                         }
135                         else {
136                                 filecontent += line;
137                         }
138                 }
139                 fclose(f);
140         }
141         return filecontent;
142 }
143
144 static std::string execCommand(std::string cmd) {
145         FILE* pipe = popen(cmd.c_str(), "r");
146         if (!pipe)
147                 return "Error";
148         char buffer[STDBUFFER_SIZE];
149         std::string result = "";
150         while(!feof(pipe))
151         {
152                 if(!fgets(buffer,STDBUFFER_SIZE, pipe))
153                         break;
154                 result += buffer;
155         }
156         pclose(pipe);
157         return result;
158 }
159
160 #define INFOFILE "/maintainer.info"
161
162 void bsodFatal(const char *component)
163 {
164         char logfile[128];
165         sprintf(logfile, "/media/hdd/enigma2_crash_%u.log", (unsigned int)time(0));
166         FILE *f = fopen(logfile, "wb");
167         
168         std::string lines = getLogBuffer();
169         
170                 /* find python-tracebacks, and extract "  File "-strings */
171         size_t start = 0;
172         
173         char crash_emailaddr[256] = CRASH_EMAILADDR;
174         char crash_component[256] = "enigma2";
175
176         if (component)
177                 snprintf(crash_component, 256, component);
178         else
179         {
180                 while ((start = lines.find("\n  File \"", start)) != std::string::npos)
181                 {
182                         start += 9;
183                         size_t end = lines.find("\"", start);
184                         if (end == std::string::npos)
185                                 break;
186                         end = lines.rfind("/", end);
187                                 /* skip a potential prefix to the path */
188                         unsigned int path_prefix = lines.find("/usr/", start);
189                         if (path_prefix != std::string::npos && path_prefix < end)
190                                 start = path_prefix;
191
192                         if (end == std::string::npos)
193                                 break;
194                         if (end - start >= (256 - strlen(INFOFILE)))
195                                 continue;
196                         char filename[256];
197                         snprintf(filename, 256, "%s%s", lines.substr(start, end - start).c_str(), INFOFILE);
198                         FILE *cf = fopen(filename, "r");
199                         if (cf)
200                         {
201                                 fgets(crash_emailaddr, sizeof crash_emailaddr, cf);
202                                 if (*crash_emailaddr && crash_emailaddr[strlen(crash_emailaddr)-1] == '\n')
203                                         crash_emailaddr[strlen(crash_emailaddr)-1] = 0;
204
205                                 fgets(crash_component, sizeof crash_component, cf);
206                                 if (*crash_component && crash_component[strlen(crash_component)-1] == '\n')
207                                         crash_component[strlen(crash_component)-1] = 0;
208                                 fclose(cf);
209                         }
210                 }
211         }
212
213         if (f)
214         {
215                 time_t t = time(0);
216                 char crashtime[STDBUFFER_SIZE];
217                 sprintf(crashtime, "%s",ctime(&t));
218                 if (strlen(crashtime) && crashtime[strlen(crashtime)-1] == '\n')
219                                 crashtime[strlen(crashtime)-1] = 0;
220                 fprintf(f, "<?xml version=\"1.0\" encoding=\"iso-8859-1\" ?>\n<opendreambox>\n");
221                 fprintf(f, "\t<enigma2>\n");
222                 fprintf(f, "\t\t<crashdate>%s</crashdate>\n", crashtime);
223 #ifdef ENIGMA2_CHECKOUT_TAG
224                 fprintf(f, "\t\t<checkouttag>" ENIGMA2_CHECKOUT_TAG "</checkouttag>\n");
225 #else
226                 fprintf(f, "\t\t<compiledate>" __DATE__ "</compiledate>\n");
227 #endif
228 #ifdef ENIGMA2_CHECKOUT_ROOT
229                 fprintf(f, "\t\t<checkoutroot>" ENIGMA2_CHECKOUT_ROOT "</checkoutroot>\n");
230 #endif
231                 fprintf(f, "\t\t<contactemail>%s</contactemail>\n", crash_emailaddr);
232                 fprintf(f, "\t\t<!-- Please email this crashlog to above address -->\n");
233                 std::string activeSkin = getConfigFileValue("config.skin.primary_skin");
234                 if (activeSkin != "Error")
235                 {
236                         if (activeSkin == "")
237                                 activeSkin = "Default Skin";
238                         fprintf(f, "\t\t<skin>%s</skin>\n", activeSkin.c_str());
239                 }
240                 fprintf(f, "\t</enigma2>\n");
241
242                 fprintf(f, "\t<image>\n");
243                 std::string model = getFileContent("/proc/stb/info/model");
244                 if (model != "Error")
245                 {
246                         char modelname[STDBUFFER_SIZE];
247                         sprintf(modelname, "%s",model.c_str());
248                         if (strlen(modelname) && modelname[strlen(modelname)-1] == '\n')
249                                 modelname[strlen(modelname)-1] = 0;
250                         fprintf(f, "\t\t<dreamboxmodel>%s</dreamboxmodel>\n", modelname);
251                 }
252                 std::string kernel = getFileContent("/proc/cmdline");
253                 if (kernel != "Error")
254                 {
255                         char kernelcmd[STDBUFFER_SIZE];
256                         sprintf(kernelcmd, "%s",kernel.c_str());
257                         if (strlen(kernelcmd) && kernelcmd[strlen(kernelcmd)-1] == '\n')
258                                 kernelcmd[strlen(kernelcmd)-1] = 0;
259                         fprintf(f, "\t\t<kernelcmdline>%s</kernelcmdline>\n", kernelcmd);
260                 }
261                 std::string sendAnonCrashlog = getConfigFileValue("config.plugins.crashlogautosubmit.sendAnonCrashlog");
262                 if (sendAnonCrashlog == "False" || sendAnonCrashlog == "false") // defaults to true... default anonymized crashlogs
263                 {
264                         std::string ca = getFileContent("/proc/stb/info/ca");
265                         if (ca != "Error")
266                         {
267                                 char dreamboxca[STDBUFFER_SIZE];
268                                 sprintf(dreamboxca, "%s",ca.c_str());
269                                 if (strlen(dreamboxca) && dreamboxca[strlen(dreamboxca)-1] == '\n')
270                                         dreamboxca[strlen(dreamboxca)-1] = 0;
271                                 fprintf(f, "\t\t<dreamboxca>\n\t\t<![CDATA[\n%s\n\t\t]]>\n\t\t</dreamboxca>\n", dreamboxca);
272                         }
273                         std::string settings = getFileContent(eEnv::resolve("${sysconfdir}/enigma2/settings").c_str());
274                         if (settings != "Error")
275                         {
276                                 fprintf(f, "\t\t<enigma2settings>\n\t\t<![CDATA[\n%s\t\t]]>\n\t\t</enigma2settings>\n", settings.c_str());
277                         }
278                 }
279                 std::string addNetwork = getConfigFileValue("config.plugins.crashlogautosubmit.addNetwork");
280                 if (addNetwork == "True" || addNetwork == "true")
281                 {
282                         std::string nwinterfaces = getFileContent("/etc/network/interfaces");
283                         if (nwinterfaces != "Error")
284                         {
285                                 fprintf(f, "\t\t<networkinterfaces>\n\t\t<![CDATA[\n%s\t\t]]>\n\t\t</networkinterfaces>\n", nwinterfaces.c_str());
286                         }
287                         std::string dns = getFileContent("/etc/resolv.conf");
288                         if (dns != "Error")
289                         {
290                                 fprintf(f, "\t\t<dns>\n\t\t<![CDATA[\n%s\t\t]]>\n\t\t</dns>\n", dns.c_str());
291                         }
292                         std::string defaultgw = getFileContent("/etc/default_gw");
293                         if (defaultgw != "Error")
294                         {
295                                 char gateway[STDBUFFER_SIZE];
296                                 sprintf(gateway, "%s",defaultgw.c_str());
297                                 if (strlen(gateway) && gateway[strlen(gateway)-1] == '\n')
298                                         gateway[strlen(gateway)-1] = 0;
299                                 fprintf(f, "\t\t<defaultgateway>\n\t\t<![CDATA[\n%s\t\t]]>\n\t\t</defaultgateway>\n", gateway);
300                         }
301                 }
302                 std::string addWlan = getConfigFileValue("config.plugins.crashlogautosubmit.addWlan");
303                 if (addWlan == "True" || addWlan == "true")
304                 {
305                         std::string wpasupplicant = getFileContent("/etc/wpa_supplicant.conf");
306                         if (wpasupplicant != "Error")
307                         {
308                                 fprintf(f, "\t\t<wpasupplicant>\n\t\t<![CDATA[\n%s\t\t]]>\n\t\t</wpasupplicant>\n", wpasupplicant.c_str());
309                         }
310                 }
311                 std::string imageversion = getFileContent("/etc/image-version");
312                 if (imageversion != "Error")
313                 {
314                         fprintf(f, "\t\t<imageversion>\n\t\t<![CDATA[\n%s\t\t]]>\n\t\t</imageversion>\n", imageversion.c_str());
315                 }
316                 std::string imageissue = getFileContent("/etc/issue.net");
317                 if (imageissue != "Error")
318                 {
319                         fprintf(f, "\t\t<imageissue>\n\t\t<![CDATA[\n%s\t\t]]>\n\t\t</imageissue>\n", imageissue.c_str());
320                 }
321                 fprintf(f, "\t</image>\n");
322
323                 fprintf(f, "\t<software>\n");
324                 std::string installedplugins = execCommand("ipkg list_installed | grep enigma2");
325                 fprintf(f, "\t\t<enigma2software>\n\t\t<![CDATA[\n%s\t\t]]>\n\t\t</enigma2software>\n", installedplugins.c_str());
326                 std::string dreambox = execCommand("ipkg list_installed | grep dream");
327                 fprintf(f, "\t\t<dreamboxsoftware>\n\t\t<![CDATA[\n%s\t\t]]>\n\t\t</dreamboxsoftware>\n", dreambox.c_str());
328                 std::string gstreamer = execCommand("ipkg list_installed | grep gst");
329                 fprintf(f, "\t\t<gstreamersoftware>\n\t\t<![CDATA[\n%s\t\t]]>\n\t\t</gstreamersoftware>\n", gstreamer.c_str());
330                 fprintf(f, "\t</software>\n");
331
332                 fprintf(f, "\t<crashlogs>\n");
333                 std::string buffer = getLogBuffer();
334                 fprintf(f, "\t\t<enigma2crashlog>\n\t\t<![CDATA[\n%s\t\t]]>\n\t\t</enigma2crashlog>\n", buffer.c_str());
335                 std::string pythonmd5 = execCommand("find " + eEnv::resolve("${libdir}/enigma2/python/") + " -name \"*.py\" | xargs md5sum");
336                 fprintf(f, "\t\t<pythonMD5sum>\n\t\t<![CDATA[\n%s\t\t]]>\n\t\t</pythonMD5sum>\n", pythonmd5.c_str());
337                 fprintf(f, "\t</crashlogs>\n");
338
339                 fprintf(f, "\n</opendreambox>\n");
340                 fclose(f);
341                 
342         }
343         
344 #ifdef WITH_SDL
345         ePtr<gSDLDC> my_dc;
346         gSDLDC::getInstance(my_dc);
347 #else
348         ePtr<gFBDC> my_dc;
349         gFBDC::getInstance(my_dc);
350 #endif
351         
352         {
353                 gPainter p(my_dc);
354                 p.resetOffset();
355                 p.resetClip(eRect(ePoint(0, 0), my_dc->size()));
356 #ifdef ENIGMA2_CHECKOUT_TAG
357                 if (ENIGMA2_CHECKOUT_TAG[0] == 'T') /* tagged checkout (release) */
358                         p.setBackgroundColor(gRGB(0x0000C0));
359                 else if (ENIGMA2_CHECKOUT_TAG[0] == 'D') /* dated checkout (daily experimental build) */
360                 {
361                         srand(time(0));
362                         int r = rand();
363                         unsigned int col = 0;
364                         if (r & 1)
365                                 col |= 0x800000;
366                         if (r & 2)
367                                 col |= 0x008000;
368                         if (r & 4)
369                                 col |= 0x0000c0;
370                         p.setBackgroundColor(gRGB(col));
371                 }
372 #else
373                         p.setBackgroundColor(gRGB(0x008000));
374 #endif
375
376                 p.setForegroundColor(gRGB(0xFFFFFF));
377         
378                 ePtr<gFont> font = new gFont("Regular", 20);
379                 p.setFont(font);
380                 p.clear();
381         
382                 eRect usable_area = eRect(100, 70, my_dc->size().width() - 150, 100);
383                 
384                 char text[512];
385                 snprintf(text, 512, "We are really sorry. Your Dreambox encountered "
386                         "a software problem, and needs to be restarted. "
387                         "Please send the logfile created in /hdd/ to %s.\n"
388                         "Your Dreambox restarts in 10 seconds!\n"
389                         "Component: %s",
390                         crash_emailaddr, crash_component);
391         
392                 p.renderText(usable_area, text, gPainter::RT_WRAP|gPainter::RT_HALIGN_LEFT);
393         
394                 usable_area = eRect(100, 170, my_dc->size().width() - 180, my_dc->size().height() - 20);
395         
396                 int i;
397         
398                 size_t start = std::string::npos + 1;
399                 for (i=0; i<20; ++i)
400                 {
401                         start = lines.rfind('\n', start - 1);
402                         if (start == std::string::npos)
403                         {
404                                 start = 0;
405                                 break;
406                         }
407                 }
408         
409                 font = new gFont("Regular", 14);
410                 p.setFont(font);
411         
412                 p.renderText(usable_area, 
413                         lines.substr(start), gPainter::RT_HALIGN_LEFT);
414                 sleep(10);
415         }
416
417         raise(SIGKILL);
418 }
419
420 #if defined(__MIPSEL__)
421 void oops(const mcontext_t &context, int dumpcode)
422 {
423         eDebug("PC: %08lx", (unsigned long)context.pc);
424         int i;
425         for (i=0; i<32; ++i)
426         {
427                 eDebugNoNewLine(" %08x", (int)context.gregs[i]);
428                 if ((i&3) == 3)
429                         eDebug("");
430         }
431                 /* this is temporary debug stuff. */
432         if (dumpcode && ((unsigned long)context.pc) > 0x10000) /* not a zero pointer */
433         {
434                 eDebug("As a final action, i will try to dump a bit of code.");
435                 eDebug("I just hope that this won't crash.");
436                 int i;
437                 eDebugNoNewLine("%08lx:", (unsigned long)context.pc);
438                 for (i=0; i<0x20; ++i)
439                         eDebugNoNewLine(" %02x", ((unsigned char*)context.pc)[i]);
440                 eDebug(" (end)");
441         }
442 }
443 #else
444 #warning "no oops support!"
445 #define NO_OOPS_SUPPORT
446 #endif
447
448 void handleFatalSignal(int signum, siginfo_t *si, void *ctx)
449 {
450         ucontext_t *uc = (ucontext_t*)ctx;
451
452 #ifndef NO_OOPS_SUPPORT
453         oops(uc->uc_mcontext, signum == SIGSEGV || signum == SIGABRT);
454 #endif
455         eDebug("-------");
456         bsodFatal("enigma2, signal");
457 }
458
459 void bsodCatchSignals()
460 {
461         struct sigaction act;
462         act.sa_handler = SIG_DFL;
463         act.sa_sigaction = handleFatalSignal;
464         act.sa_flags = SA_RESTART | SA_SIGINFO;
465         if (sigemptyset(&act.sa_mask) == -1)
466                 perror("sigemptyset");
467         
468                 /* start handling segfaults etc. */
469         sigaction(SIGSEGV, &act, 0);
470         sigaction(SIGILL, &act, 0);
471         sigaction(SIGBUS, &act, 0);
472         sigaction(SIGABRT, &act, 0);
473 }
474
475 void bsodLogInit()
476 {
477         logOutput.connect(addToLogbuffer);
478 }