162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci#include <linux/compiler.h> 362306a36Sopenharmony_ci#include <linux/kernel.h> 462306a36Sopenharmony_ci#include <linux/string.h> 562306a36Sopenharmony_ci#include <linux/zalloc.h> 662306a36Sopenharmony_ci#include <linux/err.h> 762306a36Sopenharmony_ci#include <sys/types.h> 862306a36Sopenharmony_ci#include <sys/stat.h> 962306a36Sopenharmony_ci#include <errno.h> 1062306a36Sopenharmony_ci#include <fcntl.h> 1162306a36Sopenharmony_ci#include <unistd.h> 1262306a36Sopenharmony_ci#include <string.h> 1362306a36Sopenharmony_ci#include <asm/bug.h> 1462306a36Sopenharmony_ci#include <dirent.h> 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#include "data.h" 1762306a36Sopenharmony_ci#include "util.h" // rm_rf_perf_data() 1862306a36Sopenharmony_ci#include "debug.h" 1962306a36Sopenharmony_ci#include "header.h" 2062306a36Sopenharmony_ci#include <internal/lib.h> 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_cistatic void close_dir(struct perf_data_file *files, int nr) 2362306a36Sopenharmony_ci{ 2462306a36Sopenharmony_ci while (--nr >= 0) { 2562306a36Sopenharmony_ci close(files[nr].fd); 2662306a36Sopenharmony_ci zfree(&files[nr].path); 2762306a36Sopenharmony_ci } 2862306a36Sopenharmony_ci free(files); 2962306a36Sopenharmony_ci} 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_civoid perf_data__close_dir(struct perf_data *data) 3262306a36Sopenharmony_ci{ 3362306a36Sopenharmony_ci close_dir(data->dir.files, data->dir.nr); 3462306a36Sopenharmony_ci} 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ciint perf_data__create_dir(struct perf_data *data, int nr) 3762306a36Sopenharmony_ci{ 3862306a36Sopenharmony_ci struct perf_data_file *files = NULL; 3962306a36Sopenharmony_ci int i, ret; 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci if (WARN_ON(!data->is_dir)) 4262306a36Sopenharmony_ci return -EINVAL; 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci files = zalloc(nr * sizeof(*files)); 4562306a36Sopenharmony_ci if (!files) 4662306a36Sopenharmony_ci return -ENOMEM; 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci for (i = 0; i < nr; i++) { 4962306a36Sopenharmony_ci struct perf_data_file *file = &files[i]; 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci ret = asprintf(&file->path, "%s/data.%d", data->path, i); 5262306a36Sopenharmony_ci if (ret < 0) { 5362306a36Sopenharmony_ci ret = -ENOMEM; 5462306a36Sopenharmony_ci goto out_err; 5562306a36Sopenharmony_ci } 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci ret = open(file->path, O_RDWR|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR); 5862306a36Sopenharmony_ci if (ret < 0) { 5962306a36Sopenharmony_ci ret = -errno; 6062306a36Sopenharmony_ci goto out_err; 6162306a36Sopenharmony_ci } 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci file->fd = ret; 6462306a36Sopenharmony_ci } 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci data->dir.version = PERF_DIR_VERSION; 6762306a36Sopenharmony_ci data->dir.files = files; 6862306a36Sopenharmony_ci data->dir.nr = nr; 6962306a36Sopenharmony_ci return 0; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ciout_err: 7262306a36Sopenharmony_ci close_dir(files, i); 7362306a36Sopenharmony_ci return ret; 7462306a36Sopenharmony_ci} 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ciint perf_data__open_dir(struct perf_data *data) 7762306a36Sopenharmony_ci{ 7862306a36Sopenharmony_ci struct perf_data_file *files = NULL; 7962306a36Sopenharmony_ci struct dirent *dent; 8062306a36Sopenharmony_ci int ret = -1; 8162306a36Sopenharmony_ci DIR *dir; 8262306a36Sopenharmony_ci int nr = 0; 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci /* 8562306a36Sopenharmony_ci * Directory containing a single regular perf data file which is already 8662306a36Sopenharmony_ci * open, means there is nothing more to do here. 8762306a36Sopenharmony_ci */ 8862306a36Sopenharmony_ci if (perf_data__is_single_file(data)) 8962306a36Sopenharmony_ci return 0; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci if (WARN_ON(!data->is_dir)) 9262306a36Sopenharmony_ci return -EINVAL; 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci /* The version is provided by DIR_FORMAT feature. */ 9562306a36Sopenharmony_ci if (WARN_ON(data->dir.version != PERF_DIR_VERSION)) 9662306a36Sopenharmony_ci return -1; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci dir = opendir(data->path); 9962306a36Sopenharmony_ci if (!dir) 10062306a36Sopenharmony_ci return -EINVAL; 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci while ((dent = readdir(dir)) != NULL) { 10362306a36Sopenharmony_ci struct perf_data_file *file; 10462306a36Sopenharmony_ci char path[PATH_MAX]; 10562306a36Sopenharmony_ci struct stat st; 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci snprintf(path, sizeof(path), "%s/%s", data->path, dent->d_name); 10862306a36Sopenharmony_ci if (stat(path, &st)) 10962306a36Sopenharmony_ci continue; 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci if (!S_ISREG(st.st_mode) || strncmp(dent->d_name, "data.", 5)) 11262306a36Sopenharmony_ci continue; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci ret = -ENOMEM; 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci file = realloc(files, (nr + 1) * sizeof(*files)); 11762306a36Sopenharmony_ci if (!file) 11862306a36Sopenharmony_ci goto out_err; 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci files = file; 12162306a36Sopenharmony_ci file = &files[nr++]; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci file->path = strdup(path); 12462306a36Sopenharmony_ci if (!file->path) 12562306a36Sopenharmony_ci goto out_err; 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci ret = open(file->path, O_RDONLY); 12862306a36Sopenharmony_ci if (ret < 0) 12962306a36Sopenharmony_ci goto out_err; 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci file->fd = ret; 13262306a36Sopenharmony_ci file->size = st.st_size; 13362306a36Sopenharmony_ci } 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci closedir(dir); 13662306a36Sopenharmony_ci if (!files) 13762306a36Sopenharmony_ci return -EINVAL; 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci data->dir.files = files; 14062306a36Sopenharmony_ci data->dir.nr = nr; 14162306a36Sopenharmony_ci return 0; 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ciout_err: 14462306a36Sopenharmony_ci closedir(dir); 14562306a36Sopenharmony_ci close_dir(files, nr); 14662306a36Sopenharmony_ci return ret; 14762306a36Sopenharmony_ci} 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ciint perf_data__update_dir(struct perf_data *data) 15062306a36Sopenharmony_ci{ 15162306a36Sopenharmony_ci int i; 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci if (WARN_ON(!data->is_dir)) 15462306a36Sopenharmony_ci return -EINVAL; 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci for (i = 0; i < data->dir.nr; i++) { 15762306a36Sopenharmony_ci struct perf_data_file *file = &data->dir.files[i]; 15862306a36Sopenharmony_ci struct stat st; 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci if (fstat(file->fd, &st)) 16162306a36Sopenharmony_ci return -1; 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci file->size = st.st_size; 16462306a36Sopenharmony_ci } 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci return 0; 16762306a36Sopenharmony_ci} 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_cistatic bool check_pipe(struct perf_data *data) 17062306a36Sopenharmony_ci{ 17162306a36Sopenharmony_ci struct stat st; 17262306a36Sopenharmony_ci bool is_pipe = false; 17362306a36Sopenharmony_ci int fd = perf_data__is_read(data) ? 17462306a36Sopenharmony_ci STDIN_FILENO : STDOUT_FILENO; 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci if (!data->path) { 17762306a36Sopenharmony_ci if (!fstat(fd, &st) && S_ISFIFO(st.st_mode)) 17862306a36Sopenharmony_ci is_pipe = true; 17962306a36Sopenharmony_ci } else { 18062306a36Sopenharmony_ci if (!strcmp(data->path, "-")) 18162306a36Sopenharmony_ci is_pipe = true; 18262306a36Sopenharmony_ci } 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci if (is_pipe) { 18562306a36Sopenharmony_ci if (data->use_stdio) { 18662306a36Sopenharmony_ci const char *mode; 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci mode = perf_data__is_read(data) ? "r" : "w"; 18962306a36Sopenharmony_ci data->file.fptr = fdopen(fd, mode); 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci if (data->file.fptr == NULL) { 19262306a36Sopenharmony_ci data->file.fd = fd; 19362306a36Sopenharmony_ci data->use_stdio = false; 19462306a36Sopenharmony_ci } 19562306a36Sopenharmony_ci } else { 19662306a36Sopenharmony_ci data->file.fd = fd; 19762306a36Sopenharmony_ci } 19862306a36Sopenharmony_ci } 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci return data->is_pipe = is_pipe; 20162306a36Sopenharmony_ci} 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_cistatic int check_backup(struct perf_data *data) 20462306a36Sopenharmony_ci{ 20562306a36Sopenharmony_ci struct stat st; 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci if (perf_data__is_read(data)) 20862306a36Sopenharmony_ci return 0; 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci if (!stat(data->path, &st) && st.st_size) { 21162306a36Sopenharmony_ci char oldname[PATH_MAX]; 21262306a36Sopenharmony_ci int ret; 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci snprintf(oldname, sizeof(oldname), "%s.old", 21562306a36Sopenharmony_ci data->path); 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci ret = rm_rf_perf_data(oldname); 21862306a36Sopenharmony_ci if (ret) { 21962306a36Sopenharmony_ci pr_err("Can't remove old data: %s (%s)\n", 22062306a36Sopenharmony_ci ret == -2 ? 22162306a36Sopenharmony_ci "Unknown file found" : strerror(errno), 22262306a36Sopenharmony_ci oldname); 22362306a36Sopenharmony_ci return -1; 22462306a36Sopenharmony_ci } 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci if (rename(data->path, oldname)) { 22762306a36Sopenharmony_ci pr_err("Can't move data: %s (%s to %s)\n", 22862306a36Sopenharmony_ci strerror(errno), 22962306a36Sopenharmony_ci data->path, oldname); 23062306a36Sopenharmony_ci return -1; 23162306a36Sopenharmony_ci } 23262306a36Sopenharmony_ci } 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci return 0; 23562306a36Sopenharmony_ci} 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_cistatic bool is_dir(struct perf_data *data) 23862306a36Sopenharmony_ci{ 23962306a36Sopenharmony_ci struct stat st; 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci if (stat(data->path, &st)) 24262306a36Sopenharmony_ci return false; 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci return (st.st_mode & S_IFMT) == S_IFDIR; 24562306a36Sopenharmony_ci} 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_cistatic int open_file_read(struct perf_data *data) 24862306a36Sopenharmony_ci{ 24962306a36Sopenharmony_ci int flags = data->in_place_update ? O_RDWR : O_RDONLY; 25062306a36Sopenharmony_ci struct stat st; 25162306a36Sopenharmony_ci int fd; 25262306a36Sopenharmony_ci char sbuf[STRERR_BUFSIZE]; 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci fd = open(data->file.path, flags); 25562306a36Sopenharmony_ci if (fd < 0) { 25662306a36Sopenharmony_ci int err = errno; 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci pr_err("failed to open %s: %s", data->file.path, 25962306a36Sopenharmony_ci str_error_r(err, sbuf, sizeof(sbuf))); 26062306a36Sopenharmony_ci if (err == ENOENT && !strcmp(data->file.path, "perf.data")) 26162306a36Sopenharmony_ci pr_err(" (try 'perf record' first)"); 26262306a36Sopenharmony_ci pr_err("\n"); 26362306a36Sopenharmony_ci return -err; 26462306a36Sopenharmony_ci } 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci if (fstat(fd, &st) < 0) 26762306a36Sopenharmony_ci goto out_close; 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci if (!data->force && st.st_uid && (st.st_uid != geteuid())) { 27062306a36Sopenharmony_ci pr_err("File %s not owned by current user or root (use -f to override)\n", 27162306a36Sopenharmony_ci data->file.path); 27262306a36Sopenharmony_ci goto out_close; 27362306a36Sopenharmony_ci } 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci if (!st.st_size) { 27662306a36Sopenharmony_ci pr_info("zero-sized data (%s), nothing to do!\n", 27762306a36Sopenharmony_ci data->file.path); 27862306a36Sopenharmony_ci goto out_close; 27962306a36Sopenharmony_ci } 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci data->file.size = st.st_size; 28262306a36Sopenharmony_ci return fd; 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci out_close: 28562306a36Sopenharmony_ci close(fd); 28662306a36Sopenharmony_ci return -1; 28762306a36Sopenharmony_ci} 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_cistatic int open_file_write(struct perf_data *data) 29062306a36Sopenharmony_ci{ 29162306a36Sopenharmony_ci int fd; 29262306a36Sopenharmony_ci char sbuf[STRERR_BUFSIZE]; 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci fd = open(data->file.path, O_CREAT|O_RDWR|O_TRUNC|O_CLOEXEC, 29562306a36Sopenharmony_ci S_IRUSR|S_IWUSR); 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci if (fd < 0) 29862306a36Sopenharmony_ci pr_err("failed to open %s : %s\n", data->file.path, 29962306a36Sopenharmony_ci str_error_r(errno, sbuf, sizeof(sbuf))); 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci return fd; 30262306a36Sopenharmony_ci} 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_cistatic int open_file(struct perf_data *data) 30562306a36Sopenharmony_ci{ 30662306a36Sopenharmony_ci int fd; 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci fd = perf_data__is_read(data) ? 30962306a36Sopenharmony_ci open_file_read(data) : open_file_write(data); 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci if (fd < 0) { 31262306a36Sopenharmony_ci zfree(&data->file.path); 31362306a36Sopenharmony_ci return -1; 31462306a36Sopenharmony_ci } 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci data->file.fd = fd; 31762306a36Sopenharmony_ci return 0; 31862306a36Sopenharmony_ci} 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_cistatic int open_file_dup(struct perf_data *data) 32162306a36Sopenharmony_ci{ 32262306a36Sopenharmony_ci data->file.path = strdup(data->path); 32362306a36Sopenharmony_ci if (!data->file.path) 32462306a36Sopenharmony_ci return -ENOMEM; 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci return open_file(data); 32762306a36Sopenharmony_ci} 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_cistatic int open_dir(struct perf_data *data) 33062306a36Sopenharmony_ci{ 33162306a36Sopenharmony_ci int ret; 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci /* 33462306a36Sopenharmony_ci * So far we open only the header, so we can read the data version and 33562306a36Sopenharmony_ci * layout. 33662306a36Sopenharmony_ci */ 33762306a36Sopenharmony_ci if (asprintf(&data->file.path, "%s/data", data->path) < 0) 33862306a36Sopenharmony_ci return -1; 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci if (perf_data__is_write(data) && 34162306a36Sopenharmony_ci mkdir(data->path, S_IRWXU) < 0) 34262306a36Sopenharmony_ci return -1; 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci ret = open_file(data); 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci /* Cleanup whatever we managed to create so far. */ 34762306a36Sopenharmony_ci if (ret && perf_data__is_write(data)) 34862306a36Sopenharmony_ci rm_rf_perf_data(data->path); 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci return ret; 35162306a36Sopenharmony_ci} 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ciint perf_data__open(struct perf_data *data) 35462306a36Sopenharmony_ci{ 35562306a36Sopenharmony_ci if (check_pipe(data)) 35662306a36Sopenharmony_ci return 0; 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci /* currently it allows stdio for pipe only */ 35962306a36Sopenharmony_ci data->use_stdio = false; 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci if (!data->path) 36262306a36Sopenharmony_ci data->path = "perf.data"; 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci if (check_backup(data)) 36562306a36Sopenharmony_ci return -1; 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci if (perf_data__is_read(data)) 36862306a36Sopenharmony_ci data->is_dir = is_dir(data); 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci return perf_data__is_dir(data) ? 37162306a36Sopenharmony_ci open_dir(data) : open_file_dup(data); 37262306a36Sopenharmony_ci} 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_civoid perf_data__close(struct perf_data *data) 37562306a36Sopenharmony_ci{ 37662306a36Sopenharmony_ci if (perf_data__is_dir(data)) 37762306a36Sopenharmony_ci perf_data__close_dir(data); 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci zfree(&data->file.path); 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci if (data->use_stdio) 38262306a36Sopenharmony_ci fclose(data->file.fptr); 38362306a36Sopenharmony_ci else 38462306a36Sopenharmony_ci close(data->file.fd); 38562306a36Sopenharmony_ci} 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_cissize_t perf_data__read(struct perf_data *data, void *buf, size_t size) 38862306a36Sopenharmony_ci{ 38962306a36Sopenharmony_ci if (data->use_stdio) { 39062306a36Sopenharmony_ci if (fread(buf, size, 1, data->file.fptr) == 1) 39162306a36Sopenharmony_ci return size; 39262306a36Sopenharmony_ci return feof(data->file.fptr) ? 0 : -1; 39362306a36Sopenharmony_ci } 39462306a36Sopenharmony_ci return readn(data->file.fd, buf, size); 39562306a36Sopenharmony_ci} 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_cissize_t perf_data_file__write(struct perf_data_file *file, 39862306a36Sopenharmony_ci void *buf, size_t size) 39962306a36Sopenharmony_ci{ 40062306a36Sopenharmony_ci return writen(file->fd, buf, size); 40162306a36Sopenharmony_ci} 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_cissize_t perf_data__write(struct perf_data *data, 40462306a36Sopenharmony_ci void *buf, size_t size) 40562306a36Sopenharmony_ci{ 40662306a36Sopenharmony_ci if (data->use_stdio) { 40762306a36Sopenharmony_ci if (fwrite(buf, size, 1, data->file.fptr) == 1) 40862306a36Sopenharmony_ci return size; 40962306a36Sopenharmony_ci return -1; 41062306a36Sopenharmony_ci } 41162306a36Sopenharmony_ci return perf_data_file__write(&data->file, buf, size); 41262306a36Sopenharmony_ci} 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ciint perf_data__switch(struct perf_data *data, 41562306a36Sopenharmony_ci const char *postfix, 41662306a36Sopenharmony_ci size_t pos, bool at_exit, 41762306a36Sopenharmony_ci char **new_filepath) 41862306a36Sopenharmony_ci{ 41962306a36Sopenharmony_ci int ret; 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci if (perf_data__is_read(data)) 42262306a36Sopenharmony_ci return -EINVAL; 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci if (asprintf(new_filepath, "%s.%s", data->path, postfix) < 0) 42562306a36Sopenharmony_ci return -ENOMEM; 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci /* 42862306a36Sopenharmony_ci * Only fire a warning, don't return error, continue fill 42962306a36Sopenharmony_ci * original file. 43062306a36Sopenharmony_ci */ 43162306a36Sopenharmony_ci if (rename(data->path, *new_filepath)) 43262306a36Sopenharmony_ci pr_warning("Failed to rename %s to %s\n", data->path, *new_filepath); 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci if (!at_exit) { 43562306a36Sopenharmony_ci close(data->file.fd); 43662306a36Sopenharmony_ci ret = perf_data__open(data); 43762306a36Sopenharmony_ci if (ret < 0) 43862306a36Sopenharmony_ci goto out; 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci if (lseek(data->file.fd, pos, SEEK_SET) == (off_t)-1) { 44162306a36Sopenharmony_ci ret = -errno; 44262306a36Sopenharmony_ci pr_debug("Failed to lseek to %zu: %s", 44362306a36Sopenharmony_ci pos, strerror(errno)); 44462306a36Sopenharmony_ci goto out; 44562306a36Sopenharmony_ci } 44662306a36Sopenharmony_ci } 44762306a36Sopenharmony_ci ret = data->file.fd; 44862306a36Sopenharmony_ciout: 44962306a36Sopenharmony_ci return ret; 45062306a36Sopenharmony_ci} 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ciunsigned long perf_data__size(struct perf_data *data) 45362306a36Sopenharmony_ci{ 45462306a36Sopenharmony_ci u64 size = data->file.size; 45562306a36Sopenharmony_ci int i; 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci if (perf_data__is_single_file(data)) 45862306a36Sopenharmony_ci return size; 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci for (i = 0; i < data->dir.nr; i++) { 46162306a36Sopenharmony_ci struct perf_data_file *file = &data->dir.files[i]; 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci size += file->size; 46462306a36Sopenharmony_ci } 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci return size; 46762306a36Sopenharmony_ci} 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ciint perf_data__make_kcore_dir(struct perf_data *data, char *buf, size_t buf_sz) 47062306a36Sopenharmony_ci{ 47162306a36Sopenharmony_ci int ret; 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci if (!data->is_dir) 47462306a36Sopenharmony_ci return -1; 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci ret = snprintf(buf, buf_sz, "%s/kcore_dir", data->path); 47762306a36Sopenharmony_ci if (ret < 0 || (size_t)ret >= buf_sz) 47862306a36Sopenharmony_ci return -1; 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci return mkdir(buf, S_IRWXU); 48162306a36Sopenharmony_ci} 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_cibool has_kcore_dir(const char *path) 48462306a36Sopenharmony_ci{ 48562306a36Sopenharmony_ci struct dirent *d = ERR_PTR(-EINVAL); 48662306a36Sopenharmony_ci const char *name = "kcore_dir"; 48762306a36Sopenharmony_ci DIR *dir = opendir(path); 48862306a36Sopenharmony_ci size_t n = strlen(name); 48962306a36Sopenharmony_ci bool result = false; 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci if (dir) { 49262306a36Sopenharmony_ci while (d && !result) { 49362306a36Sopenharmony_ci d = readdir(dir); 49462306a36Sopenharmony_ci result = d ? strncmp(d->d_name, name, n) : false; 49562306a36Sopenharmony_ci } 49662306a36Sopenharmony_ci closedir(dir); 49762306a36Sopenharmony_ci } 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci return result; 50062306a36Sopenharmony_ci} 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_cichar *perf_data__kallsyms_name(struct perf_data *data) 50362306a36Sopenharmony_ci{ 50462306a36Sopenharmony_ci char *kallsyms_name; 50562306a36Sopenharmony_ci struct stat st; 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci if (!data->is_dir) 50862306a36Sopenharmony_ci return NULL; 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci if (asprintf(&kallsyms_name, "%s/kcore_dir/kallsyms", data->path) < 0) 51162306a36Sopenharmony_ci return NULL; 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci if (stat(kallsyms_name, &st)) { 51462306a36Sopenharmony_ci free(kallsyms_name); 51562306a36Sopenharmony_ci return NULL; 51662306a36Sopenharmony_ci } 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci return kallsyms_name; 51962306a36Sopenharmony_ci} 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_cichar *perf_data__guest_kallsyms_name(struct perf_data *data, pid_t machine_pid) 52262306a36Sopenharmony_ci{ 52362306a36Sopenharmony_ci char *kallsyms_name; 52462306a36Sopenharmony_ci struct stat st; 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci if (!data->is_dir) 52762306a36Sopenharmony_ci return NULL; 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci if (asprintf(&kallsyms_name, "%s/kcore_dir__%d/kallsyms", data->path, machine_pid) < 0) 53062306a36Sopenharmony_ci return NULL; 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci if (stat(kallsyms_name, &st)) { 53362306a36Sopenharmony_ci free(kallsyms_name); 53462306a36Sopenharmony_ci return NULL; 53562306a36Sopenharmony_ci } 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_ci return kallsyms_name; 53862306a36Sopenharmony_ci} 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_cibool is_perf_data(const char *path) 54162306a36Sopenharmony_ci{ 54262306a36Sopenharmony_ci bool ret = false; 54362306a36Sopenharmony_ci FILE *file; 54462306a36Sopenharmony_ci u64 magic; 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ci file = fopen(path, "r"); 54762306a36Sopenharmony_ci if (!file) 54862306a36Sopenharmony_ci return false; 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci if (fread(&magic, 1, 8, file) < 8) 55162306a36Sopenharmony_ci goto out; 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci ret = is_perf_magic(magic); 55462306a36Sopenharmony_ciout: 55562306a36Sopenharmony_ci fclose(file); 55662306a36Sopenharmony_ci return ret; 55762306a36Sopenharmony_ci} 558