chiark / gitweb /
bootchart: add parameter "-C" to expand process names to the full cmdline
[elogind.git] / src / bootchart / svg.c
index 8da32efca5c5e3a66057ec600d412947c9198ca8..4c78abda63af2e3d80d2c7fb342e3188b67a6d1f 100644 (file)
@@ -28,6 +28,8 @@
 #include <limits.h>
 #include <unistd.h>
 #include <sys/utsname.h>
+#include <sys/stat.h>
+#include <fcntl.h>
 
 #include "bootchart.h"
 #include "util.h"
@@ -95,10 +97,10 @@ static void svg_header(void)
 
         /* write some basic info as a comment, including some help */
         svg("<!-- This file is a bootchart SVG file. It is best rendered in a browser -->\n");
-        svg("<!-- such as Chrome/Chromium, firefox. Other applications that render    -->\n");
-        svg("<!-- these files properly but much more slow are ImageMagick, gimp,      -->\n");
-        svg("<!-- inkscape, etc.. To display the files on your system, just point     -->\n");
-        svg("<!-- your browser to file:///var/log/ and click. This bootchart was      -->\n\n");
+        svg("<!-- such as Chrome, Chromium, or Firefox. Other applications that       -->\n");
+        svg("<!-- render these files properly but more slowly are ImageMagick, gimp,  -->\n");
+        svg("<!-- inkscape, etc. To display the files on your system, just point      -->\n");
+        svg("<!-- your browser to file:///run/log/ and click. This bootchart was      -->\n\n");
 
         svg("<!-- generated by bootchart version %s, running with options:  -->\n", VERSION);
         svg("<!-- hz=\"%f\" n=\"%d\" -->\n", hz, len);
@@ -138,7 +140,7 @@ static void svg_header(void)
 }
 
 
-static void svg_title(void)
+static void svg_title(const char *build)
 {
         char cmdline[256] = "";
         char filename[PATH_MAX];
@@ -147,14 +149,15 @@ static void svg_title(void)
         char model[256] = "Unknown";
         char date[256] = "Unknown";
         char cpu[256] = "Unknown";
-        char build[256] = "Unknown";
         char *c;
         FILE *f;
         time_t t;
+        int fd;
         struct utsname uts;
 
         /* grab /proc/cmdline */
-        f = fopen("/proc/cmdline", "r");
+        fd = openat(procfd, "cmdline", O_RDONLY);
+        f = fdopen(fd, "r");
         if (f) {
                 if (!fgets(cmdline, 255, f))
                         sprintf(cmdline, "Unknown");
@@ -162,17 +165,19 @@ static void svg_title(void)
         }
 
         /* extract root fs so we can find disk model name in sysfs */
+        /* FIXME: this works only in the simple case */
         c = strstr(cmdline, "root=/dev/");
         if (c) {
                 strncpy(rootbdev, &c[10], 3);
                 rootbdev[3] = '\0';
-        }
-        sprintf(filename, "/sys/block/%s/device/model", rootbdev);
-        f = fopen(filename, "r");
-        if (f) {
-                if (!fgets(model, 255, f))
-                        fprintf(stderr, "Error reading disk model for %s\n", rootbdev);
-                fclose(f);
+                sprintf(filename, "block/%s/device/model", rootbdev);
+                fd = openat(sysfd, filename, O_RDONLY);
+                f = fdopen(fd, "r");
+                if (f) {
+                        if (!fgets(model, 255, f))
+                                fprintf(stderr, "Error reading disk model for %s\n", rootbdev);
+                        fclose(f);
+                }
         }
 
         /* various utsname parameters */
@@ -184,7 +189,8 @@ static void svg_title(void)
         strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", localtime(&t));
 
         /* CPU type */
-        f = fopen("/proc/cpuinfo", "r");
+        fd = openat(procfd, "cpuinfo", O_RDONLY);
+        f = fdopen(fd, "r");
         if (f) {
                 while (fgets(buf, 255, f)) {
                         if (strstr(buf, "model name")) {
@@ -195,14 +201,6 @@ static void svg_title(void)
                 fclose(f);
         }
 
-        /* Build - 1st line from /etc/system-release */
-        f = fopen("/etc/system-release", "r");
-        if (f) {
-                if (fgets(buf, 255, f))
-                        strncpy(build, buf, 255);
-                fclose(f);
-        }
-
         svg("<text class=\"t1\" x=\"0\" y=\"30\">Bootchart for %s - %s</text>\n",
             uts.nodename, date);
         svg("<text class=\"t2\" x=\"20\" y=\"50\">System: %s %s %s %s</text>\n",
@@ -269,6 +267,20 @@ static void svg_graph_box(int height)
         }
 }
 
+/* xml comments must not contain "--" */
+static char* xml_comment_encode(const char* name) {
+        char *enc_name, *p;
+
+        enc_name = strdup(name);
+        if (!enc_name)
+                return NULL;
+
+        for (p = enc_name; *p; p++)
+                if (p[0] == '-' && p[1] == '-')
+                        p[1] = '_';
+
+        return enc_name;
+}
 
 static void svg_pss_graph(void)
 {
@@ -371,7 +383,7 @@ static void svg_pss_graph(void)
                                 top = bottom + ps->sample[i].pss;
                                 /* draw a label with the process / PID */
                                 if ((i == 1) || (ps->sample[i - 1].pss <= (100 * scale_y)))
-                                        svg("  <text x=\"%.03f\" y=\"%.03f\">%s [%i]</text>\n",
+                                        svg("  <text x=\"%.03f\" y=\"%.03f\"><![CDATA[%s]]> [%i]</text>\n",
                                             time_to_graph(sampletime[i] - graph_start),
                                             kb_to_graph(1000000.0 - bottom - ((top -  bottom) / 2)),
                                             ps->name,
@@ -385,10 +397,17 @@ static void svg_pss_graph(void)
         svg("\n\n<!-- PSS map - csv format -->\n");
         ps = ps_first;
         while (ps->next_ps) {
+                char _cleanup_free_*enc_name;
                 ps = ps->next_ps;
                 if (!ps)
                         continue;
-                svg("<!-- %s [%d] pss=", ps->name, ps->pid);
+
+                enc_name = xml_comment_encode(ps->name);
+                if(!enc_name)
+                        continue;
+
+                svg("<!-- %s [%d] pss=", enc_name, ps->pid);
+
                 for (i = 0; i < samples ; i++) {
                         svg("%d," , ps->sample[i].pss);
                 }
@@ -818,14 +837,20 @@ static void svg_ps_bars(void)
         /* pass 2 - ps boxes */
         ps = ps_first;
         while ((ps = get_next_ps(ps))) {
+                char _cleanup_free_*enc_name;
+
                 double starttime;
                 int t;
 
                 if (!ps)
                         continue;
 
+                enc_name = xml_comment_encode(ps->name);
+                if(!enc_name)
+                        continue;
+
                 /* leave some trace of what we actually filtered etc. */
-                svg("<!-- %s [%i] ppid=%i runtime=%.03fs -->\n", ps->name, ps->pid,
+                svg("<!-- %s [%i] ppid=%i runtime=%.03fs -->\n", enc_name, ps->pid,
                     ps->ppid, ps->total);
 
                 /* it would be nice if we could use exec_start from /proc/pid/sched,
@@ -900,7 +925,7 @@ static void svg_ps_bars(void)
                         w = ps->first;
 
                 /* text label of process name */
-                svg("  <text x=\"%.03f\" y=\"%.03f\">%s [%i] <tspan class=\"run\">%.03fs</tspan></text>\n",
+                svg("  <text x=\"%.03f\" y=\"%.03f\"><![CDATA[%s]]> [%i]<tspan class=\"run\">%.03fs</tspan></text>\n",
                     time_to_graph(sampletime[w] - graph_start) + 5.0,
                     ps_to_graph(j) + 14.0,
                     ps->name,
@@ -1004,7 +1029,7 @@ static void svg_top_ten_cpu(void)
 
         svg("<text class=\"t2\" x=\"20\" y=\"0\">Top CPU consumers:</text>\n");
         for (n = 0; n < 10; n++)
-                svg("<text class=\"t3\" x=\"20\" y=\"%d\">%3.03fs - %s[%d]</text>\n",
+                svg("<text class=\"t3\" x=\"20\" y=\"%d\">%3.03fs - <![CDATA[%s]]> [%d]</text>\n",
                     20 + (n * 13),
                     top[n]->total,
                     top[n]->name,
@@ -1039,7 +1064,7 @@ static void svg_top_ten_pss(void)
 
         svg("<text class=\"t2\" x=\"20\" y=\"0\">Top PSS consumers:</text>\n");
         for (n = 0; n < 10; n++)
-                svg("<text class=\"t3\" x=\"20\" y=\"%d\">%dK - %s[%d]</text>\n",
+                svg("<text class=\"t3\" x=\"20\" y=\"%d\">%dK - <![CDATA[%s]]> [%d]</text>\n",
                     20 + (n * 13),
                     top[n]->pss_max,
                     top[n]->name,
@@ -1047,7 +1072,7 @@ static void svg_top_ten_pss(void)
 }
 
 
-void svg_do(void)
+void svg_do(const char *build)
 {
         struct ps_struct *ps;
 
@@ -1100,7 +1125,7 @@ void svg_do(void)
         svg("</g>\n\n");
 
         svg("<g transform=\"translate(10,  0)\">\n");
-        svg_title();
+        svg_title(build);
         svg("</g>\n\n");
 
         svg("<g transform=\"translate(10,200)\">\n");