1 // SPDX-License-Identifier: GPL-2.0 2 #include <linux/compiler.h> 3 #include <linux/kernel.h> 4 #include <sys/types.h> 5 #include <sys/stat.h> 6 #include <errno.h> 7 #include <fcntl.h> 8 #include <unistd.h> 9 #include <string.h> 10 11 #include "data.h" 12 #include "util.h" 13 #include "debug.h" 14 15 static bool check_pipe(struct perf_data *data) 16 { 17 struct stat st; 18 bool is_pipe = false; 19 int fd = perf_data__is_read(data) ? 20 STDIN_FILENO : STDOUT_FILENO; 21 22 if (!data->file.path) { 23 if (!fstat(fd, &st) && S_ISFIFO(st.st_mode)) 24 is_pipe = true; 25 } else { 26 if (!strcmp(data->file.path, "-")) 27 is_pipe = true; 28 } 29 30 if (is_pipe) 31 data->file.fd = fd; 32 33 return data->is_pipe = is_pipe; 34 } 35 36 static int check_backup(struct perf_data *data) 37 { 38 struct stat st; 39 40 if (!stat(data->file.path, &st) && st.st_size) { 41 /* TODO check errors properly */ 42 char oldname[PATH_MAX]; 43 snprintf(oldname, sizeof(oldname), "%s.old", 44 data->file.path); 45 unlink(oldname); 46 rename(data->file.path, oldname); 47 } 48 49 return 0; 50 } 51 52 static int open_file_read(struct perf_data *data) 53 { 54 struct stat st; 55 int fd; 56 char sbuf[STRERR_BUFSIZE]; 57 58 fd = open(data->file.path, O_RDONLY); 59 if (fd < 0) { 60 int err = errno; 61 62 pr_err("failed to open %s: %s", data->file.path, 63 str_error_r(err, sbuf, sizeof(sbuf))); 64 if (err == ENOENT && !strcmp(data->file.path, "perf.data")) 65 pr_err(" (try 'perf record' first)"); 66 pr_err("\n"); 67 return -err; 68 } 69 70 if (fstat(fd, &st) < 0) 71 goto out_close; 72 73 if (!data->force && st.st_uid && (st.st_uid != geteuid())) { 74 pr_err("File %s not owned by current user or root (use -f to override)\n", 75 data->file.path); 76 goto out_close; 77 } 78 79 if (!st.st_size) { 80 pr_info("zero-sized data (%s), nothing to do!\n", 81 data->file.path); 82 goto out_close; 83 } 84 85 data->size = st.st_size; 86 return fd; 87 88 out_close: 89 close(fd); 90 return -1; 91 } 92 93 static int open_file_write(struct perf_data *data) 94 { 95 int fd; 96 char sbuf[STRERR_BUFSIZE]; 97 98 if (check_backup(data)) 99 return -1; 100 101 fd = open(data->file.path, O_CREAT|O_RDWR|O_TRUNC|O_CLOEXEC, 102 S_IRUSR|S_IWUSR); 103 104 if (fd < 0) 105 pr_err("failed to open %s : %s\n", data->file.path, 106 str_error_r(errno, sbuf, sizeof(sbuf))); 107 108 return fd; 109 } 110 111 static int open_file(struct perf_data *data) 112 { 113 int fd; 114 115 fd = perf_data__is_read(data) ? 116 open_file_read(data) : open_file_write(data); 117 118 data->file.fd = fd; 119 return fd < 0 ? -1 : 0; 120 } 121 122 int perf_data__open(struct perf_data *data) 123 { 124 if (check_pipe(data)) 125 return 0; 126 127 if (!data->file.path) 128 data->file.path = "perf.data"; 129 130 return open_file(data); 131 } 132 133 void perf_data__close(struct perf_data *data) 134 { 135 close(data->file.fd); 136 } 137 138 ssize_t perf_data_file__write(struct perf_data_file *file, 139 void *buf, size_t size) 140 { 141 return writen(file->fd, buf, size); 142 } 143 144 ssize_t perf_data__write(struct perf_data *data, 145 void *buf, size_t size) 146 { 147 return perf_data_file__write(&data->file, buf, size); 148 } 149 150 int perf_data__switch(struct perf_data *data, 151 const char *postfix, 152 size_t pos, bool at_exit) 153 { 154 char *new_filepath; 155 int ret; 156 157 if (check_pipe(data)) 158 return -EINVAL; 159 if (perf_data__is_read(data)) 160 return -EINVAL; 161 162 if (asprintf(&new_filepath, "%s.%s", data->file.path, postfix) < 0) 163 return -ENOMEM; 164 165 /* 166 * Only fire a warning, don't return error, continue fill 167 * original file. 168 */ 169 if (rename(data->file.path, new_filepath)) 170 pr_warning("Failed to rename %s to %s\n", data->file.path, new_filepath); 171 172 if (!at_exit) { 173 close(data->file.fd); 174 ret = perf_data__open(data); 175 if (ret < 0) 176 goto out; 177 178 if (lseek(data->file.fd, pos, SEEK_SET) == (off_t)-1) { 179 ret = -errno; 180 pr_debug("Failed to lseek to %zu: %s", 181 pos, strerror(errno)); 182 goto out; 183 } 184 } 185 ret = data->file.fd; 186 out: 187 free(new_filepath); 188 return ret; 189 } 190