Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 54 additions & 0 deletions src/bootchart.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@
#include <sys/uio.h>
#include <time.h>
#include <unistd.h>
#include <sys/stat.h>
#include <libgen.h>

#ifdef HAVE_LIBSYSTEMD
#include <systemd/sd-journal.h>
Expand Down Expand Up @@ -310,6 +312,38 @@ static int do_journal_append(char *file) {
return 0;
}


static int is_mountpoint(const char *path) {
struct stat s_path, s_parent;
char *path_aux, *parent_path;

// Root is always a mountpoint
if (strcmp(path, "/") == 0) {
return 1;
}

if (stat(path, &s_path) == -1) {
return -1;
}

// Duplicate path as dirname can modify it
path_aux = strdup(path);
if (!path_aux) {
return -1;
}

parent_path = dirname(path_aux);
if (stat(parent_path, &s_parent) == -1) {
free(path_aux);
return -1;
}

free(path_aux);

// mount point if the directory and its parent are on different devices (filesystems)
return (s_path.st_dev != s_parent.st_dev);
}

int main(int argc, char *argv[]) {
static struct list_sample_data *sampledata;
_cleanup_closedir_ DIR *proc = NULL;
Expand All @@ -333,6 +367,7 @@ int main(int argc, char *argv[]) {
.sa_handler = signal_handler,
};
bool has_procfs = false;
bool sysroot_mounted = false;

parse_conf();

Expand Down Expand Up @@ -433,6 +468,25 @@ int main(int argc, char *argv[]) {
if (r < 0)
return EXIT_FAILURE;
}
if (!sysroot_mounted) {
// sysroot is where systemd will switch root when
// switching from initramfs to the root fs. We chroot
// there so we can write later the svg file.
//
// TODO instead of detecting this way, use signal from initramfs service.
sysroot_mounted = is_mountpoint("/sysroot") == 1;
if (sysroot_mounted) {
// chroot does not change the cwd of the process, so we do that first
if (chdir("/sysroot") != 0) {
log_info_errno(errno, "cannot chdir to /sysroot: %m\n");
return EXIT_FAILURE;
}
if (chroot(".") != 0) {
log_info_errno(errno, "cannot chroot: %m\n");
return EXIT_FAILURE;
}
}
}

sample_stop = gettime_ns();

Expand Down
67 changes: 66 additions & 1 deletion src/store.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/

#define _POSIX_C_SOURCE

#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
Expand All @@ -29,6 +31,7 @@
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <sys/stat.h>

#include "alloc-util.h"
#include "bootchart.h"
Expand Down Expand Up @@ -119,6 +122,68 @@ static void garbage_collect_dead_processes(struct ps_struct *ps_first) {
}
}

static int proc_read_full_file(int procfd, const char *fn, char **contents, size_t *size) {
int fd = -1;
size_t n, l;
_cleanup_free_ char *buf = NULL;
struct stat st;

fd = openat(procfd, fn, O_RDONLY|O_CLOEXEC);
if (fd < 0)
return log_error_errno(errno, "Failed to openat /proc/%s: %m", fn);

if (fstat(fd, &st) < 0)
return log_error_errno(errno, "Failed to fstat /proc/%s: %m", fn);

n = LINE_MAX;
if (S_ISREG(st.st_mode)) {

/* Safety check */
if (st.st_size > 4*1024*1024)
return -E2BIG;

/* Start with the right file size, but be prepared for
* files from /proc which generally report a file size
* of 0 */
if (st.st_size > 0)
n = st.st_size;
}

l = 0;
for (;;) {
char *t;
ssize_t k;

t = realloc(buf, n+1);
if (!t)
return -ENOMEM;

buf = t;
k = pread(fd, buf + l, n - l, l);

if (k < 0)
return log_error_errno(errno, "Failed to pread /proc/%s: %m", fn);
if (k == 0)
break;

l += k;
n *= 2;

/* Safety check */
if (n > 4*1024*1024)
return -E2BIG;
}

buf[l] = 0;
*contents = buf;
buf = NULL; /* do not free */

if (size)
*size = l;

safe_close(fd);
return 0;
}

int log_sample(DIR *proc,
int sample,
Expand Down Expand Up @@ -189,7 +254,7 @@ int log_sample(DIR *proc,
}

/* Parse "/proc/schedstat" for overall CPU utilization */
r = read_full_file("/proc/schedstat", &buf_schedstat, NULL);
r = proc_read_full_file(procfd, "schedstat", &buf_schedstat, NULL);
if (r < 0)
return log_error_errno(r, "Unable to read schedstat: %m");

Expand Down