summaryrefslogtreecommitdiff
path: root/src/bootchart
diff options
context:
space:
mode:
authorDaniel Mack <daniel@zonque.org>2015-04-02 14:15:33 +0200
committerDaniel Mack <daniel@zonque.org>2015-04-03 15:29:18 +0200
commitf91781329c6d8a760e3c1b88b66b0e2137c2e5ab (patch)
tree94a417ee58753ea5a92116d0a74ec0a3a044e825 /src/bootchart
parent34a4071e998f327945993ea6e6cbcaa0292b4093 (diff)
bootchart: clean up sysfd and proc handling
Retrieve the handle to procfs in main(), and pass it functions that need it. Kill the global variables. Also, refactor lots of code in svg_title(). There's no need to access any global variables from there either, and we really should return proper errors from there as well.
Diffstat (limited to 'src/bootchart')
-rw-r--r--src/bootchart/bootchart.c35
-rw-r--r--src/bootchart/bootchart.h1
-rw-r--r--src/bootchart/store.c24
-rw-r--r--src/bootchart/store.h5
-rw-r--r--src/bootchart/svg.c97
-rw-r--r--src/bootchart/svg.h2
6 files changed, 78 insertions, 86 deletions
diff --git a/src/bootchart/bootchart.c b/src/bootchart/bootchart.c
index 1024f78fa6..8cb1ee6921 100644
--- a/src/bootchart/bootchart.c
+++ b/src/bootchart/bootchart.c
@@ -67,7 +67,6 @@ 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
@@ -314,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,
};
@@ -323,7 +324,6 @@ int main(int argc, char *argv[]) {
time_t t = 0;
int r;
struct rlimit rlim;
- bool has_procfs = false;
parse_conf();
@@ -373,8 +373,6 @@ int main(int argc, char *argv[]) {
return EXIT_FAILURE;
}
- has_procfs = access("/proc/vmstat", F_OK) == 0;
-
LIST_HEAD_INIT(head);
/* main program loop */
@@ -404,13 +402,16 @@ int main(int argc, char *argv[]) {
parse_env_file("/usr/lib/os-release", NEWLINE, "PRETTY_NAME", &build, NULL);
}
- if (has_procfs) {
- r = log_sample(samples, &sampledata);
+ if (proc)
+ rewinddir(proc);
+ else
+ 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;
- } else {
- /* wait for /proc to become available, discarding samples */
- has_procfs = access("/proc/vmstat", F_OK) == 0;
}
sample_stop = gettime_ns();
@@ -470,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) {
diff --git a/src/bootchart/bootchart.h b/src/bootchart/bootchart.h
index e4dbdd921d..6e83a99a2b 100644
--- a/src/bootchart/bootchart.h
+++ b/src/bootchart/bootchart.h
@@ -132,4 +132,3 @@ extern char arg_output_path[PATH_MAX];
extern char arg_init_path[PATH_MAX];
extern FILE *of;
-extern int sysfd;
diff --git a/src/bootchart/store.c b/src/bootchart/store.c
index 53b827fe59..6125104084 100644
--- a/src/bootchart/store.c
+++ b/src/bootchart/store.c
@@ -45,8 +45,6 @@
*/
static char smaps_buf[4096];
static int skip = 0;
-DIR *proc;
-int procfd = -1;
double gettime_ns(void) {
struct timespec n;
@@ -86,7 +84,7 @@ static char *bufgetline(char *buf) {
return c;
}
-static int pid_cmdline_strscpy(char *buffer, size_t buf_len, int pid) {
+static int pid_cmdline_strscpy(int procfd, char *buffer, size_t buf_len, int pid) {
char filename[PATH_MAX];
_cleanup_close_ int fd=-1;
ssize_t n;
@@ -107,7 +105,7 @@ static int pid_cmdline_strscpy(char *buffer, size_t buf_len, int pid) {
return 0;
}
-int log_sample(int sample, struct list_sample_data **ptr) {
+int log_sample(DIR *proc, int sample, struct list_sample_data **ptr) {
static int vmstat = -1;
static int schedstat = -1;
char buf[4096];
@@ -126,19 +124,13 @@ int log_sample(int sample, struct list_sample_data **ptr) {
int fd;
struct list_sample_data *sampledata;
struct ps_sched_struct *ps_prev = NULL;
+ int procfd;
sampledata = *ptr;
- /* all the per-process stuff goes here */
- if (!proc) {
- /* find all processes */
- proc = opendir("/proc");
- if (!proc)
- return -errno;
- procfd = dirfd(proc);
- } else {
- rewinddir(proc);
- }
+ procfd = dirfd(proc);
+ if (procfd < 0)
+ return -errno;
if (vmstat < 0) {
/* block stuff */
@@ -301,7 +293,7 @@ schedstat_next:
/* cmdline */
if (arg_show_cmdline)
- pid_cmdline_strscpy(ps->name, sizeof(ps->name), pid);
+ pid_cmdline_strscpy(procfd, ps->name, sizeof(ps->name), pid);
/* discard line 2 */
m = bufgetline(buf);
@@ -520,7 +512,7 @@ catch_rename:
/* cmdline */
if (arg_show_cmdline)
- pid_cmdline_strscpy(ps->name, sizeof(ps->name), pid);
+ pid_cmdline_strscpy(procfd, ps->name, sizeof(ps->name), pid);
}
}
diff --git a/src/bootchart/store.h b/src/bootchart/store.h
index 8cb319275c..bc54f4f631 100644
--- a/src/bootchart/store.h
+++ b/src/bootchart/store.h
@@ -27,9 +27,6 @@
#include <dirent.h>
#include "bootchart.h"
-extern DIR *proc;
-extern int procfd;
-
double gettime_ns(void);
void log_uptime(void);
-int log_sample(int sample, struct list_sample_data **ptr);
+int log_sample(DIR *proc, int sample, struct list_sample_data **ptr);
diff --git a/src/bootchart/svg.c b/src/bootchart/svg.c
index 8c8fab941d..b031090d2f 100644
--- a/src/bootchart/svg.c
+++ b/src/bootchart/svg.c
@@ -31,6 +31,7 @@
#include <fcntl.h>
#include "util.h"
+#include "fileio.h"
#include "macro.h"
#include "store.h"
#include "svg.h"
@@ -149,54 +150,47 @@ static void svg_header(void) {
svg(" ]]>\n </style>\n</defs>\n\n");
}
-static void svg_title(const char *build) {
- char cmdline[256] = "";
- char filename[PATH_MAX];
- char buf[256];
- char rootbdev[16] = "Unknown";
- char model[256] = "Unknown";
+static int svg_title(const char *build) {
+ _cleanup_free_ char *cmdline = NULL;
+ _cleanup_free_ char *model = NULL;
+ _cleanup_free_ char *buf = NULL;
char date[256] = "Unknown";
- char cpu[256] = "Unknown";
+ char *cpu;
char *c;
- FILE *f;
time_t t;
- int fd, r;
+ int r;
struct utsname uts;
- /* grab /proc/cmdline */
- fd = openat(procfd, "cmdline", O_RDONLY);
- f = fdopen(fd, "r");
- if (f) {
- if (!fgets(cmdline, 255, f))
- sprintf(cmdline, "Unknown");
- fclose(f);
- } else {
- if (fd >= 0)
- close(fd);
+ r = read_one_line_file("/proc/cmdline", &cmdline);
+ if (r < 0) {
+ log_error_errno(r, "Unable to read cmdline: %m\n");
+ return r;
}
/* 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);
+ char rootbdev[4];
+ char filename[32];
+
+ strncpy(rootbdev, &c[10], sizeof(rootbdev) - 1);
rootbdev[3] = '\0';
- sprintf(filename, "block/%s/device/model", rootbdev);
- fd = openat(sysfd, filename, O_RDONLY);
- f = fdopen(fd, "r");
- if (f) {
- if (!fgets(model, 255, f))
- log_error("Error reading disk model for %s: %m\n", rootbdev);
- fclose(f);
- } else {
- if (fd >= 0)
- close(fd);
+ snprintf(filename, sizeof(filename), "/sys/block/%s/device/model", rootbdev);
+
+ r = read_one_line_file(filename, &model);
+ if (r < 0) {
+ log_error("Error reading disk model for %s: %m\n", rootbdev);
+ return r;
}
}
/* various utsname parameters */
- if (uname(&uts))
+ r = uname(&uts);
+ if (r < 0) {
log_error("Error getting uname info\n");
+ return -errno;
+ }
/* date */
t = time(NULL);
@@ -204,21 +198,23 @@ static void svg_title(const char *build) {
assert_se(r > 0);
/* CPU type */
- fd = openat(procfd, "cpuinfo", O_RDONLY);
- f = fdopen(fd, "r");
- if (f) {
- while (fgets(buf, 255, f)) {
- if (strstr(buf, "model name")) {
- strncpy(cpu, &buf[13], 255);
- break;
- }
- }
- fclose(f);
- } else {
- if (fd >= 0)
- close(fd);
+ r = read_full_file("/proc/cpuinfo", &buf, NULL);
+ if (r < 0) {
+ log_error_errno(r, "Unable to read cpuinfo: %m\n");
+ return r;
+ }
+
+ cpu = strstr(buf, "model name");
+ if (!cpu) {
+ log_error("Unable to read module name from cpuinfo.\n");
+ return -ENOENT;
}
+ cpu += 13;
+ c = strchr(cpu, '\n');
+ if (c)
+ *c = '\0';
+
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",
@@ -241,6 +237,8 @@ static void svg_title(const char *build) {
svg("</text>\n");
svg("<text class=\"sec\" x=\"20\" y=\"155\">Graph data: %.03f samples/sec, recorded %i total, dropped %i samples, %i processes, %i filtered</text>\n",
arg_hz, arg_samples_len, overrun, pscount, pfiltered);
+
+ return 0;
}
static void svg_graph_box(int height) {
@@ -1273,10 +1271,10 @@ static void svg_top_ten_pss(void) {
top[n]->pid);
}
-void svg_do(const char *build) {
+int svg_do(const char *build) {
struct ps_struct *ps;
double offset = 7;
- int c;
+ int r, c;
memzero(&str, sizeof(str));
@@ -1334,9 +1332,12 @@ void svg_do(const char *build) {
svg("</g>\n\n");
svg("<g transform=\"translate(10, 0)\">\n");
- svg_title(build);
+ r = svg_title(build);
svg("</g>\n\n");
+ if (r < 0)
+ return r;
+
svg("<g transform=\"translate(10,200)\">\n");
svg_top_ten_cpu();
svg("</g>\n\n");
@@ -1359,4 +1360,6 @@ void svg_do(const char *build) {
/* svg footer */
svg("\n</svg>\n");
+
+ return 0;
}
diff --git a/src/bootchart/svg.h b/src/bootchart/svg.h
index df3a7bf8ef..f0fb1a7ce7 100644
--- a/src/bootchart/svg.h
+++ b/src/bootchart/svg.h
@@ -24,4 +24,4 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-void svg_do(const char *build);
+int svg_do(const char *build);