diff --git a/tools/perf/util/Build b/tools/perf/util/Build index fd89d6a8cd65..4d1894e38a81 100644 --- a/tools/perf/util/Build +++ b/tools/perf/util/Build @@ -3,6 +3,7 @@ perf-y += block-range.o perf-y += build-id.o perf-y += cacheline.o perf-y += config.o +perf-y += copyfile.o perf-y += ctype.o perf-y += db-export.o perf-y += env.o diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c index 7928c398a063..c076fc7fe025 100644 --- a/tools/perf/util/build-id.c +++ b/tools/perf/util/build-id.c @@ -7,12 +7,13 @@ * Copyright (C) 2009, 2010 Red Hat Inc. * Copyright (C) 2009, 2010 Arnaldo Carvalho de Melo */ -#include "util.h" // copyfile_ns(), lsdir(), mkdir_p(), rm_rf() +#include "util.h" // lsdir(), mkdir_p(), rm_rf() #include #include #include #include #include +#include "util/copyfile.h" #include "dso.h" #include "build-id.h" #include "event.h" diff --git a/tools/perf/util/copyfile.c b/tools/perf/util/copyfile.c new file mode 100644 index 000000000000..3fa0db136667 --- /dev/null +++ b/tools/perf/util/copyfile.c @@ -0,0 +1,144 @@ +// SPDX-License-Identifier: GPL-2.0 +#include "util/copyfile.h" +#include "util/namespaces.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int slow_copyfile(const char *from, const char *to, struct nsinfo *nsi) +{ + int err = -1; + char *line = NULL; + size_t n; + FILE *from_fp, *to_fp; + struct nscookie nsc; + + nsinfo__mountns_enter(nsi, &nsc); + from_fp = fopen(from, "r"); + nsinfo__mountns_exit(&nsc); + if (from_fp == NULL) + goto out; + + to_fp = fopen(to, "w"); + if (to_fp == NULL) + goto out_fclose_from; + + while (getline(&line, &n, from_fp) > 0) + if (fputs(line, to_fp) == EOF) + goto out_fclose_to; + err = 0; +out_fclose_to: + fclose(to_fp); + free(line); +out_fclose_from: + fclose(from_fp); +out: + return err; +} + +int copyfile_offset(int ifd, loff_t off_in, int ofd, loff_t off_out, u64 size) +{ + void *ptr; + loff_t pgoff; + + pgoff = off_in & ~(page_size - 1); + off_in -= pgoff; + + ptr = mmap(NULL, off_in + size, PROT_READ, MAP_PRIVATE, ifd, pgoff); + if (ptr == MAP_FAILED) + return -1; + + while (size) { + ssize_t ret = pwrite(ofd, ptr + off_in, size, off_out); + if (ret < 0 && errno == EINTR) + continue; + if (ret <= 0) + break; + + size -= ret; + off_in += ret; + off_out += ret; + } + munmap(ptr, off_in + size); + + return size ? -1 : 0; +} + +static int copyfile_mode_ns(const char *from, const char *to, mode_t mode, + struct nsinfo *nsi) +{ + int fromfd, tofd; + struct stat st; + int err; + char *tmp = NULL, *ptr = NULL; + struct nscookie nsc; + + nsinfo__mountns_enter(nsi, &nsc); + err = stat(from, &st); + nsinfo__mountns_exit(&nsc); + if (err) + goto out; + err = -1; + + /* extra 'x' at the end is to reserve space for '.' */ + if (asprintf(&tmp, "%s.XXXXXXx", to) < 0) { + tmp = NULL; + goto out; + } + ptr = strrchr(tmp, '/'); + if (!ptr) + goto out; + ptr = memmove(ptr + 1, ptr, strlen(ptr) - 1); + *ptr = '.'; + + tofd = mkstemp(tmp); + if (tofd < 0) + goto out; + + if (fchmod(tofd, mode)) + goto out_close_to; + + if (st.st_size == 0) { /* /proc? do it slowly... */ + err = slow_copyfile(from, tmp, nsi); + goto out_close_to; + } + + nsinfo__mountns_enter(nsi, &nsc); + fromfd = open(from, O_RDONLY); + nsinfo__mountns_exit(&nsc); + if (fromfd < 0) + goto out_close_to; + + err = copyfile_offset(fromfd, 0, tofd, 0, st.st_size); + + close(fromfd); +out_close_to: + close(tofd); + if (!err) + err = link(tmp, to); + unlink(tmp); +out: + free(tmp); + return err; +} + +int copyfile_ns(const char *from, const char *to, struct nsinfo *nsi) +{ + return copyfile_mode_ns(from, to, 0755, nsi); +} + +int copyfile_mode(const char *from, const char *to, mode_t mode) +{ + return copyfile_mode_ns(from, to, mode, NULL); +} + +int copyfile(const char *from, const char *to) +{ + return copyfile_mode(from, to, 0755); +} diff --git a/tools/perf/util/copyfile.h b/tools/perf/util/copyfile.h new file mode 100644 index 000000000000..e85d2f22f3cc --- /dev/null +++ b/tools/perf/util/copyfile.h @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: GPL-2.0 +#ifndef PERF_COPYFILE_H_ +#define PERF_COPYFILE_H_ + +#include +#include +#include + +struct nsinfo; + +int copyfile(const char *from, const char *to); +int copyfile_mode(const char *from, const char *to, mode_t mode); +int copyfile_ns(const char *from, const char *to, struct nsinfo *nsi); +int copyfile_offset(int ifd, loff_t off_in, int ofd, loff_t off_out, u64 size); + +#endif // PERF_COPYFILE_H_ diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c index 6fbfdf8bf61f..66f4be1df573 100644 --- a/tools/perf/util/symbol-elf.c +++ b/tools/perf/util/symbol-elf.c @@ -17,7 +17,7 @@ #include "machine.h" #include "vdso.h" #include "debug.h" -#include "util.h" +#include "util/copyfile.h" #include #include #include diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c index cb6fa4c98470..5eda6e19c947 100644 --- a/tools/perf/util/util.c +++ b/tools/perf/util/util.c @@ -2,10 +2,7 @@ #include "util.h" #include "debug.h" #include "event.h" -#include "namespaces.h" -#include #include -#include #include #include #include @@ -233,138 +230,6 @@ out: return list; } -static int slow_copyfile(const char *from, const char *to, struct nsinfo *nsi) -{ - int err = -1; - char *line = NULL; - size_t n; - FILE *from_fp, *to_fp; - struct nscookie nsc; - - nsinfo__mountns_enter(nsi, &nsc); - from_fp = fopen(from, "r"); - nsinfo__mountns_exit(&nsc); - if (from_fp == NULL) - goto out; - - to_fp = fopen(to, "w"); - if (to_fp == NULL) - goto out_fclose_from; - - while (getline(&line, &n, from_fp) > 0) - if (fputs(line, to_fp) == EOF) - goto out_fclose_to; - err = 0; -out_fclose_to: - fclose(to_fp); - free(line); -out_fclose_from: - fclose(from_fp); -out: - return err; -} - -int copyfile_offset(int ifd, loff_t off_in, int ofd, loff_t off_out, u64 size) -{ - void *ptr; - loff_t pgoff; - - pgoff = off_in & ~(page_size - 1); - off_in -= pgoff; - - ptr = mmap(NULL, off_in + size, PROT_READ, MAP_PRIVATE, ifd, pgoff); - if (ptr == MAP_FAILED) - return -1; - - while (size) { - ssize_t ret = pwrite(ofd, ptr + off_in, size, off_out); - if (ret < 0 && errno == EINTR) - continue; - if (ret <= 0) - break; - - size -= ret; - off_in += ret; - off_out += ret; - } - munmap(ptr, off_in + size); - - return size ? -1 : 0; -} - -static int copyfile_mode_ns(const char *from, const char *to, mode_t mode, - struct nsinfo *nsi) -{ - int fromfd, tofd; - struct stat st; - int err; - char *tmp = NULL, *ptr = NULL; - struct nscookie nsc; - - nsinfo__mountns_enter(nsi, &nsc); - err = stat(from, &st); - nsinfo__mountns_exit(&nsc); - if (err) - goto out; - err = -1; - - /* extra 'x' at the end is to reserve space for '.' */ - if (asprintf(&tmp, "%s.XXXXXXx", to) < 0) { - tmp = NULL; - goto out; - } - ptr = strrchr(tmp, '/'); - if (!ptr) - goto out; - ptr = memmove(ptr + 1, ptr, strlen(ptr) - 1); - *ptr = '.'; - - tofd = mkstemp(tmp); - if (tofd < 0) - goto out; - - if (fchmod(tofd, mode)) - goto out_close_to; - - if (st.st_size == 0) { /* /proc? do it slowly... */ - err = slow_copyfile(from, tmp, nsi); - goto out_close_to; - } - - nsinfo__mountns_enter(nsi, &nsc); - fromfd = open(from, O_RDONLY); - nsinfo__mountns_exit(&nsc); - if (fromfd < 0) - goto out_close_to; - - err = copyfile_offset(fromfd, 0, tofd, 0, st.st_size); - - close(fromfd); -out_close_to: - close(tofd); - if (!err) - err = link(tmp, to); - unlink(tmp); -out: - free(tmp); - return err; -} - -int copyfile_ns(const char *from, const char *to, struct nsinfo *nsi) -{ - return copyfile_mode_ns(from, to, 0755, nsi); -} - -int copyfile_mode(const char *from, const char *to, mode_t mode) -{ - return copyfile_mode_ns(from, to, mode, NULL); -} - -int copyfile(const char *from, const char *to) -{ - return copyfile_mode(from, to, 0755); -} - size_t hex_width(u64 v) { size_t n = 1; diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h index b78b73e5bb32..9969b8b46f7c 100644 --- a/tools/perf/util/util.h +++ b/tools/perf/util/util.h @@ -17,7 +17,6 @@ void usage(const char *err) __noreturn; void die(const char *err, ...) __noreturn __printf(1, 2); struct dirent; -struct nsinfo; struct strlist; int mkdir_p(char *path, mode_t mode); @@ -25,10 +24,6 @@ int rm_rf(const char *path); int rm_rf_perf_data(const char *path); struct strlist *lsdir(const char *name, bool (*filter)(const char *, struct dirent *)); bool lsdir_no_dot_filter(const char *name, struct dirent *d); -int copyfile(const char *from, const char *to); -int copyfile_mode(const char *from, const char *to, mode_t mode); -int copyfile_ns(const char *from, const char *to, struct nsinfo *nsi); -int copyfile_offset(int ifd, loff_t off_in, int ofd, loff_t off_out, u64 size); size_t hex_width(u64 v);