chiark / gitweb /
bootchart: clean up sysfd and proc handling
[elogind.git] / src / bootchart / bootchart.c
index 64a384bacfa6a3ccce7a173fa1e4d558776d1e0a..8cb1ee69211cf2bd1ce123ba150be8f525682a09 100644 (file)
 
  ***/
 
-#include <sys/time.h>
-#include <sys/types.h>
 #include <sys/resource.h>
-#include <sys/stat.h>
 #include <stdio.h>
 #include <signal.h>
 #include <stdlib.h>
@@ -70,13 +67,12 @@ double interval;
 FILE *of = NULL;
 int overrun = 0;
 static int exiting = 0;
-int sysfd=-1;
 
 #define DEFAULT_SAMPLES_LEN 500
 #define DEFAULT_HZ 25.0
 #define DEFAULT_SCALE_X 100.0 /* 100px = 1sec */
 #define DEFAULT_SCALE_Y 20.0  /* 16px = 1 process bar */
-#define DEFAULT_INIT ROOTLIBDIR "/systemd/systemd"
+#define DEFAULT_INIT ROOTLIBEXECDIR "/systemd"
 #define DEFAULT_OUTPUT "/run/log"
 
 /* graph defaults */
@@ -138,31 +134,30 @@ static void parse_conf(void) {
 }
 
 static void help(void) {
-        fprintf(stdout,
-                "Usage: %s [OPTIONS]\n\n"
-                "Options:\n"
-                "  -r, --rel             Record time relative to recording\n"
-                "  -f, --freq=FREQ       Sample frequency [%g]\n"
-                "  -n, --samples=N       Stop sampling at [%d] samples\n"
-                "  -x, --scale-x=N       Scale the graph horizontally [%g] \n"
-                "  -y, --scale-y=N       Scale the graph vertically [%g] \n"
-                "  -p, --pss             Enable PSS graph (CPU intensive)\n"
-                "  -e, --entropy         Enable the entropy_avail graph\n"
-                "  -o, --output=PATH     Path to output files [%s]\n"
-                "  -i, --init=PATH       Path to init executable [%s]\n"
-                "  -F, --no-filter       Disable filtering of unimportant or ephemeral processes\n"
-                "  -C, --cmdline         Display full command lines with arguments\n"
-                "  -c, --control-group   Display process control group\n"
-                "      --per-cpu         Draw each CPU utilization and wait bar also\n"
-                "  -h, --help            Display this message\n\n"
-                "See bootchart.conf for more information.\n",
-                program_invocation_short_name,
-                DEFAULT_HZ,
-                DEFAULT_SAMPLES_LEN,
-                DEFAULT_SCALE_X,
-                DEFAULT_SCALE_Y,
-                DEFAULT_OUTPUT,
-                DEFAULT_INIT);
+        printf("Usage: %s [OPTIONS]\n\n"
+               "Options:\n"
+               "  -r --rel             Record time relative to recording\n"
+               "  -f --freq=FREQ       Sample frequency [%g]\n"
+               "  -n --samples=N       Stop sampling at [%d] samples\n"
+               "  -x --scale-x=N       Scale the graph horizontally [%g] \n"
+               "  -y --scale-y=N       Scale the graph vertically [%g] \n"
+               "  -p --pss             Enable PSS graph (CPU intensive)\n"
+               "  -e --entropy         Enable the entropy_avail graph\n"
+               "  -o --output=PATH     Path to output files [%s]\n"
+               "  -i --init=PATH       Path to init executable [%s]\n"
+               "  -F --no-filter       Disable filtering of unimportant or ephemeral processes\n"
+               "  -C --cmdline         Display full command lines with arguments\n"
+               "  -c --control-group   Display process control group\n"
+               "     --per-cpu         Draw each CPU utilization and wait bar also\n"
+               "  -h --help            Display this message\n\n"
+               "See bootchart.conf for more information.\n",
+               program_invocation_short_name,
+               DEFAULT_HZ,
+               DEFAULT_SAMPLES_LEN,
+               DEFAULT_SCALE_X,
+               DEFAULT_SCALE_Y,
+               DEFAULT_OUTPUT,
+               DEFAULT_INIT);
 }
 
 static int parse_argv(int argc, char *argv[]) {
@@ -271,10 +266,11 @@ static int parse_argv(int argc, char *argv[]) {
 
 static void do_journal_append(char *file) {
         struct iovec iovec[5];
-        int r, f, j = 0;
+        int r, j = 0;
         ssize_t n;
         _cleanup_free_ char *bootchart_file = NULL, *bootchart_message = NULL,
                 *p = NULL;
+        _cleanup_close_ int fd = -1;
 
         bootchart_file = strappend("BOOTCHART_FILE=", file);
         if (bootchart_file)
@@ -294,18 +290,17 @@ static void do_journal_append(char *file) {
 
         memcpy(p, "BOOTCHART=", 10);
 
-        f = open(file, O_RDONLY|O_CLOEXEC);
-        if (f < 0) {
-                log_error_errno(errno, "Failed to read bootchart data: %m");
+        fd = open(file, O_RDONLY|O_CLOEXEC);
+        if (fd < 0) {
+                log_error_errno(errno, "Failed to open bootchart data \"%s\": %m", file);
                 return;
         }
-        n = loop_read(f, p + 10, BOOTCHART_MAX, false);
+
+        n = loop_read(fd, p + 10, BOOTCHART_MAX, false);
         if (n < 0) {
                 log_error_errno(n, "Failed to read bootchart data: %m");
-                close(f);
                 return;
         }
-        close(f);
 
         iovec[j].iov_base = p;
         iovec[j].iov_len = 10 + n;
@@ -318,6 +313,8 @@ static void do_journal_append(char *file) {
 
 int main(int argc, char *argv[]) {
         _cleanup_free_ char *build = NULL;
+        _cleanup_close_ int sysfd = -1;
+        _cleanup_closedir_ DIR *proc = NULL;
         struct sigaction sig = {
                 .sa_handler = signal_handler,
         };
@@ -327,13 +324,15 @@ int main(int argc, char *argv[]) {
         time_t t = 0;
         int r;
         struct rlimit rlim;
-        bool has_procfs = false;
 
         parse_conf();
 
         r = parse_argv(argc, argv);
-        if (r <= 0)
-                return r == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
+        if (r < 0)
+                return EXIT_FAILURE;
+
+        if (r == 0)
+                return EXIT_SUCCESS;
 
         /*
          * If the kernel executed us through init=/usr/lib/systemd/systemd-bootchart, then
@@ -368,15 +367,12 @@ int main(int argc, char *argv[]) {
         log_uptime();
 
         if (graph_start < 0.0) {
-                fprintf(stderr,
-                        "Failed to setup graph start time.\n\nThe system uptime "
-                        "probably includes time that the system was suspended. "
-                        "Use --rel to bypass this issue.\n");
-                exit (EXIT_FAILURE);
+                log_error("Failed to setup graph start time.\n\n"
+                          "The system uptime probably includes time that the system was suspended. "
+                          "Use --rel to bypass this issue.");
+                return EXIT_FAILURE;
         }
 
-        has_procfs = access("/proc/vmstat", F_OK) == 0;
-
         LIST_HEAD_INIT(head);
 
         /* main program loop */
@@ -398,15 +394,6 @@ int main(int argc, char *argv[]) {
                 sampledata->sampletime = gettime_ns();
                 sampledata->counter = samples;
 
-                if (!of && (access(arg_output_path, R_OK|W_OK|X_OK) == 0)) {
-                        t = time(NULL);
-                        r = strftime(datestr, sizeof(datestr), "%Y%m%d-%H%M", localtime(&t));
-                        assert_se(r > 0);
-
-                        snprintf(output_file, PATH_MAX, "%s/bootchart-%s.svg", arg_output_path, datestr);
-                        of = fopen(output_file, "we");
-                }
-
                 if (sysfd < 0)
                         sysfd = open("/sys", O_RDONLY|O_CLOEXEC);
 
@@ -415,11 +402,17 @@ int main(int argc, char *argv[]) {
                                 parse_env_file("/usr/lib/os-release", NEWLINE, "PRETTY_NAME", &build, NULL);
                 }
 
-                if (has_procfs)
-                        log_sample(samples, &sampledata);
+                if (proc)
+                        rewinddir(proc);
                 else
-                        /* wait for /proc to become available, discarding samples */
-                        has_procfs = access("/proc/vmstat", F_OK) == 0;
+                        proc = opendir("/proc");
+
+                /* wait for /proc to become available, discarding samples */
+                if (proc) {
+                        r = log_sample(proc, samples, &sampledata);
+                        if (r < 0)
+                                return EXIT_FAILURE;
+                }
 
                 sample_stop = gettime_ns();
 
@@ -446,7 +439,7 @@ int main(int argc, char *argv[]) {
                                         break;
                                 }
                                 log_error_errno(errno, "nanosleep() failed: %m");
-                                exit(EXIT_FAILURE);
+                                return EXIT_FAILURE;
                         }
                 } else {
                         overrun++;
@@ -460,9 +453,9 @@ int main(int argc, char *argv[]) {
         ps = ps_first;
         while (ps->next_ps) {
                 ps = ps->next_ps;
-                if (ps->schedstat)
+                if (ps->schedstat >= 0)
                         close(ps->schedstat);
-                if (ps->sched)
+                if (ps->sched >= 0)
                         close(ps->sched);
                 if (ps->smaps)
                         fclose(ps->smaps);
@@ -478,23 +471,23 @@ int main(int argc, char *argv[]) {
         }
 
         if (!of) {
-                fprintf(stderr, "opening output file '%s': %m\n", output_file);
-                exit (EXIT_FAILURE);
+                log_error("Error opening output file '%s': %m\n", output_file);
+                return EXIT_FAILURE;
         }
 
-        svg_do(strna(build));
+        r = svg_do(strna(build));
+        if (r < 0) {
+                log_error_errno(r, "Error generating svg file: %m\n");
+                return EXIT_FAILURE;
+        }
 
-        fprintf(stderr, "systemd-bootchart wrote %s\n", output_file);
+        log_info("systemd-bootchart wrote %s\n", output_file);
 
         do_journal_append(output_file);
 
         if (of)
                 fclose(of);
 
-        closedir(proc);
-        if (sysfd >= 0)
-                close(sysfd);
-
         /* nitpic cleanups */
         ps = ps_first->next_ps;
         while (ps->next_ps) {
@@ -526,7 +519,7 @@ int main(int argc, char *argv[]) {
         free(sampledata);
         /* don't complain when overrun once, happens most commonly on 1st sample */
         if (overrun > 1)
-                fprintf(stderr, "systemd-boochart: Warning: sample time overrun %i times\n", overrun);
+                log_warning("systemd-boochart: sample time overrun %i times\n", overrun);
 
         return 0;
 }