at v5.2 7.7 kB view raw
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#include <asm/bug.h> 11#include <sys/types.h> 12#include <dirent.h> 13 14#include "data.h" 15#include "util.h" 16#include "debug.h" 17#include "header.h" 18 19static void close_dir(struct perf_data_file *files, int nr) 20{ 21 while (--nr >= 1) { 22 close(files[nr].fd); 23 free(files[nr].path); 24 } 25 free(files); 26} 27 28void perf_data__close_dir(struct perf_data *data) 29{ 30 close_dir(data->dir.files, data->dir.nr); 31} 32 33int perf_data__create_dir(struct perf_data *data, int nr) 34{ 35 struct perf_data_file *files = NULL; 36 int i, ret = -1; 37 38 if (WARN_ON(!data->is_dir)) 39 return -EINVAL; 40 41 files = zalloc(nr * sizeof(*files)); 42 if (!files) 43 return -ENOMEM; 44 45 data->dir.version = PERF_DIR_VERSION; 46 data->dir.files = files; 47 data->dir.nr = nr; 48 49 for (i = 0; i < nr; i++) { 50 struct perf_data_file *file = &files[i]; 51 52 if (asprintf(&file->path, "%s/data.%d", data->path, i) < 0) 53 goto out_err; 54 55 ret = open(file->path, O_RDWR|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR); 56 if (ret < 0) 57 goto out_err; 58 59 file->fd = ret; 60 } 61 62 return 0; 63 64out_err: 65 close_dir(files, i); 66 return ret; 67} 68 69int perf_data__open_dir(struct perf_data *data) 70{ 71 struct perf_data_file *files = NULL; 72 struct dirent *dent; 73 int ret = -1; 74 DIR *dir; 75 int nr = 0; 76 77 if (WARN_ON(!data->is_dir)) 78 return -EINVAL; 79 80 /* The version is provided by DIR_FORMAT feature. */ 81 if (WARN_ON(data->dir.version != PERF_DIR_VERSION)) 82 return -1; 83 84 dir = opendir(data->path); 85 if (!dir) 86 return -EINVAL; 87 88 while ((dent = readdir(dir)) != NULL) { 89 struct perf_data_file *file; 90 char path[PATH_MAX]; 91 struct stat st; 92 93 snprintf(path, sizeof(path), "%s/%s", data->path, dent->d_name); 94 if (stat(path, &st)) 95 continue; 96 97 if (!S_ISREG(st.st_mode) || strncmp(dent->d_name, "data", 4)) 98 continue; 99 100 ret = -ENOMEM; 101 102 file = realloc(files, (nr + 1) * sizeof(*files)); 103 if (!file) 104 goto out_err; 105 106 files = file; 107 file = &files[nr++]; 108 109 file->path = strdup(path); 110 if (!file->path) 111 goto out_err; 112 113 ret = open(file->path, O_RDONLY); 114 if (ret < 0) 115 goto out_err; 116 117 file->fd = ret; 118 file->size = st.st_size; 119 } 120 121 if (!files) 122 return -EINVAL; 123 124 data->dir.files = files; 125 data->dir.nr = nr; 126 return 0; 127 128out_err: 129 close_dir(files, nr); 130 return ret; 131} 132 133int perf_data__update_dir(struct perf_data *data) 134{ 135 int i; 136 137 if (WARN_ON(!data->is_dir)) 138 return -EINVAL; 139 140 for (i = 0; i < data->dir.nr; i++) { 141 struct perf_data_file *file = &data->dir.files[i]; 142 struct stat st; 143 144 if (fstat(file->fd, &st)) 145 return -1; 146 147 file->size = st.st_size; 148 } 149 150 return 0; 151} 152 153static bool check_pipe(struct perf_data *data) 154{ 155 struct stat st; 156 bool is_pipe = false; 157 int fd = perf_data__is_read(data) ? 158 STDIN_FILENO : STDOUT_FILENO; 159 160 if (!data->path) { 161 if (!fstat(fd, &st) && S_ISFIFO(st.st_mode)) 162 is_pipe = true; 163 } else { 164 if (!strcmp(data->path, "-")) 165 is_pipe = true; 166 } 167 168 if (is_pipe) 169 data->file.fd = fd; 170 171 return data->is_pipe = is_pipe; 172} 173 174static int check_backup(struct perf_data *data) 175{ 176 struct stat st; 177 178 if (perf_data__is_read(data)) 179 return 0; 180 181 if (!stat(data->path, &st) && st.st_size) { 182 char oldname[PATH_MAX]; 183 int ret; 184 185 snprintf(oldname, sizeof(oldname), "%s.old", 186 data->path); 187 188 ret = rm_rf_perf_data(oldname); 189 if (ret) { 190 pr_err("Can't remove old data: %s (%s)\n", 191 ret == -2 ? 192 "Unknown file found" : strerror(errno), 193 oldname); 194 return -1; 195 } 196 197 if (rename(data->path, oldname)) { 198 pr_err("Can't move data: %s (%s to %s)\n", 199 strerror(errno), 200 data->path, oldname); 201 return -1; 202 } 203 } 204 205 return 0; 206} 207 208static bool is_dir(struct perf_data *data) 209{ 210 struct stat st; 211 212 if (stat(data->path, &st)) 213 return false; 214 215 return (st.st_mode & S_IFMT) == S_IFDIR; 216} 217 218static int open_file_read(struct perf_data *data) 219{ 220 struct stat st; 221 int fd; 222 char sbuf[STRERR_BUFSIZE]; 223 224 fd = open(data->file.path, O_RDONLY); 225 if (fd < 0) { 226 int err = errno; 227 228 pr_err("failed to open %s: %s", data->file.path, 229 str_error_r(err, sbuf, sizeof(sbuf))); 230 if (err == ENOENT && !strcmp(data->file.path, "perf.data")) 231 pr_err(" (try 'perf record' first)"); 232 pr_err("\n"); 233 return -err; 234 } 235 236 if (fstat(fd, &st) < 0) 237 goto out_close; 238 239 if (!data->force && st.st_uid && (st.st_uid != geteuid())) { 240 pr_err("File %s not owned by current user or root (use -f to override)\n", 241 data->file.path); 242 goto out_close; 243 } 244 245 if (!st.st_size) { 246 pr_info("zero-sized data (%s), nothing to do!\n", 247 data->file.path); 248 goto out_close; 249 } 250 251 data->file.size = st.st_size; 252 return fd; 253 254 out_close: 255 close(fd); 256 return -1; 257} 258 259static int open_file_write(struct perf_data *data) 260{ 261 int fd; 262 char sbuf[STRERR_BUFSIZE]; 263 264 fd = open(data->file.path, O_CREAT|O_RDWR|O_TRUNC|O_CLOEXEC, 265 S_IRUSR|S_IWUSR); 266 267 if (fd < 0) 268 pr_err("failed to open %s : %s\n", data->file.path, 269 str_error_r(errno, sbuf, sizeof(sbuf))); 270 271 return fd; 272} 273 274static int open_file(struct perf_data *data) 275{ 276 int fd; 277 278 fd = perf_data__is_read(data) ? 279 open_file_read(data) : open_file_write(data); 280 281 if (fd < 0) { 282 zfree(&data->file.path); 283 return -1; 284 } 285 286 data->file.fd = fd; 287 return 0; 288} 289 290static int open_file_dup(struct perf_data *data) 291{ 292 data->file.path = strdup(data->path); 293 if (!data->file.path) 294 return -ENOMEM; 295 296 return open_file(data); 297} 298 299static int open_dir(struct perf_data *data) 300{ 301 int ret; 302 303 /* 304 * So far we open only the header, so we can read the data version and 305 * layout. 306 */ 307 if (asprintf(&data->file.path, "%s/header", data->path) < 0) 308 return -1; 309 310 if (perf_data__is_write(data) && 311 mkdir(data->path, S_IRWXU) < 0) 312 return -1; 313 314 ret = open_file(data); 315 316 /* Cleanup whatever we managed to create so far. */ 317 if (ret && perf_data__is_write(data)) 318 rm_rf_perf_data(data->path); 319 320 return ret; 321} 322 323int perf_data__open(struct perf_data *data) 324{ 325 if (check_pipe(data)) 326 return 0; 327 328 if (!data->path) 329 data->path = "perf.data"; 330 331 if (check_backup(data)) 332 return -1; 333 334 if (perf_data__is_read(data)) 335 data->is_dir = is_dir(data); 336 337 return perf_data__is_dir(data) ? 338 open_dir(data) : open_file_dup(data); 339} 340 341void perf_data__close(struct perf_data *data) 342{ 343 if (perf_data__is_dir(data)) 344 perf_data__close_dir(data); 345 346 zfree(&data->file.path); 347 close(data->file.fd); 348} 349 350ssize_t perf_data_file__write(struct perf_data_file *file, 351 void *buf, size_t size) 352{ 353 return writen(file->fd, buf, size); 354} 355 356ssize_t perf_data__write(struct perf_data *data, 357 void *buf, size_t size) 358{ 359 return perf_data_file__write(&data->file, buf, size); 360} 361 362int perf_data__switch(struct perf_data *data, 363 const char *postfix, 364 size_t pos, bool at_exit, 365 char **new_filepath) 366{ 367 int ret; 368 369 if (check_pipe(data)) 370 return -EINVAL; 371 if (perf_data__is_read(data)) 372 return -EINVAL; 373 374 if (asprintf(new_filepath, "%s.%s", data->path, postfix) < 0) 375 return -ENOMEM; 376 377 /* 378 * Only fire a warning, don't return error, continue fill 379 * original file. 380 */ 381 if (rename(data->path, *new_filepath)) 382 pr_warning("Failed to rename %s to %s\n", data->path, *new_filepath); 383 384 if (!at_exit) { 385 close(data->file.fd); 386 ret = perf_data__open(data); 387 if (ret < 0) 388 goto out; 389 390 if (lseek(data->file.fd, pos, SEEK_SET) == (off_t)-1) { 391 ret = -errno; 392 pr_debug("Failed to lseek to %zu: %s", 393 pos, strerror(errno)); 394 goto out; 395 } 396 } 397 ret = data->file.fd; 398out: 399 return ret; 400} 401 402unsigned long perf_data__size(struct perf_data *data) 403{ 404 u64 size = data->file.size; 405 int i; 406 407 if (!data->is_dir) 408 return size; 409 410 for (i = 0; i < data->dir.nr; i++) { 411 struct perf_data_file *file = &data->dir.files[i]; 412 413 size += file->size; 414 } 415 416 return size; 417}