1 // SPDX-License-Identifier: GPL-2.0
2 #include <linux/compiler.h>
3 #include <linux/kernel.h>
4 #include <linux/string.h>
5 #include <linux/zalloc.h>
16 #include "util.h" // rm_rf_perf_data()
19 #include <internal/lib.h>
21 static void close_dir(struct perf_data_file
*files
, int nr
)
25 zfree(&files
[nr
].path
);
30 void perf_data__close_dir(struct perf_data
*data
)
32 close_dir(data
->dir
.files
, data
->dir
.nr
);
35 int perf_data__create_dir(struct perf_data
*data
, int nr
)
37 struct perf_data_file
*files
= NULL
;
40 if (WARN_ON(!data
->is_dir
))
43 files
= zalloc(nr
* sizeof(*files
));
47 data
->dir
.version
= PERF_DIR_VERSION
;
48 data
->dir
.files
= files
;
51 for (i
= 0; i
< nr
; i
++) {
52 struct perf_data_file
*file
= &files
[i
];
54 if (asprintf(&file
->path
, "%s/data.%d", data
->path
, i
) < 0)
57 ret
= open(file
->path
, O_RDWR
|O_CREAT
|O_TRUNC
, S_IRUSR
|S_IWUSR
);
71 int perf_data__open_dir(struct perf_data
*data
)
73 struct perf_data_file
*files
= NULL
;
80 * Directory containing a single regular perf data file which is already
81 * open, means there is nothing more to do here.
83 if (perf_data__is_single_file(data
))
86 if (WARN_ON(!data
->is_dir
))
89 /* The version is provided by DIR_FORMAT feature. */
90 if (WARN_ON(data
->dir
.version
!= PERF_DIR_VERSION
))
93 dir
= opendir(data
->path
);
97 while ((dent
= readdir(dir
)) != NULL
) {
98 struct perf_data_file
*file
;
102 snprintf(path
, sizeof(path
), "%s/%s", data
->path
, dent
->d_name
);
106 if (!S_ISREG(st
.st_mode
) || strncmp(dent
->d_name
, "data.", 5))
111 file
= realloc(files
, (nr
+ 1) * sizeof(*files
));
118 file
->path
= strdup(path
);
122 ret
= open(file
->path
, O_RDONLY
);
127 file
->size
= st
.st_size
;
133 data
->dir
.files
= files
;
138 close_dir(files
, nr
);
142 int perf_data__update_dir(struct perf_data
*data
)
146 if (WARN_ON(!data
->is_dir
))
149 for (i
= 0; i
< data
->dir
.nr
; i
++) {
150 struct perf_data_file
*file
= &data
->dir
.files
[i
];
153 if (fstat(file
->fd
, &st
))
156 file
->size
= st
.st_size
;
162 static bool check_pipe(struct perf_data
*data
)
165 bool is_pipe
= false;
166 int fd
= perf_data__is_read(data
) ?
167 STDIN_FILENO
: STDOUT_FILENO
;
170 if (!fstat(fd
, &st
) && S_ISFIFO(st
.st_mode
))
173 if (!strcmp(data
->path
, "-"))
178 if (data
->use_stdio
) {
181 mode
= perf_data__is_read(data
) ? "r" : "w";
182 data
->file
.fptr
= fdopen(fd
, mode
);
184 if (data
->file
.fptr
== NULL
) {
186 data
->use_stdio
= false;
193 return data
->is_pipe
= is_pipe
;
196 static int check_backup(struct perf_data
*data
)
200 if (perf_data__is_read(data
))
203 if (!stat(data
->path
, &st
) && st
.st_size
) {
204 char oldname
[PATH_MAX
];
207 snprintf(oldname
, sizeof(oldname
), "%s.old",
210 ret
= rm_rf_perf_data(oldname
);
212 pr_err("Can't remove old data: %s (%s)\n",
214 "Unknown file found" : strerror(errno
),
219 if (rename(data
->path
, oldname
)) {
220 pr_err("Can't move data: %s (%s to %s)\n",
222 data
->path
, oldname
);
230 static bool is_dir(struct perf_data
*data
)
234 if (stat(data
->path
, &st
))
237 return (st
.st_mode
& S_IFMT
) == S_IFDIR
;
240 static int open_file_read(struct perf_data
*data
)
244 char sbuf
[STRERR_BUFSIZE
];
246 fd
= open(data
->file
.path
, O_RDONLY
);
250 pr_err("failed to open %s: %s", data
->file
.path
,
251 str_error_r(err
, sbuf
, sizeof(sbuf
)));
252 if (err
== ENOENT
&& !strcmp(data
->file
.path
, "perf.data"))
253 pr_err(" (try 'perf record' first)");
258 if (fstat(fd
, &st
) < 0)
261 if (!data
->force
&& st
.st_uid
&& (st
.st_uid
!= geteuid())) {
262 pr_err("File %s not owned by current user or root (use -f to override)\n",
268 pr_info("zero-sized data (%s), nothing to do!\n",
273 data
->file
.size
= st
.st_size
;
281 static int open_file_write(struct perf_data
*data
)
284 char sbuf
[STRERR_BUFSIZE
];
286 fd
= open(data
->file
.path
, O_CREAT
|O_RDWR
|O_TRUNC
|O_CLOEXEC
,
290 pr_err("failed to open %s : %s\n", data
->file
.path
,
291 str_error_r(errno
, sbuf
, sizeof(sbuf
)));
296 static int open_file(struct perf_data
*data
)
300 fd
= perf_data__is_read(data
) ?
301 open_file_read(data
) : open_file_write(data
);
304 zfree(&data
->file
.path
);
312 static int open_file_dup(struct perf_data
*data
)
314 data
->file
.path
= strdup(data
->path
);
315 if (!data
->file
.path
)
318 return open_file(data
);
321 static int open_dir(struct perf_data
*data
)
326 * So far we open only the header, so we can read the data version and
329 if (asprintf(&data
->file
.path
, "%s/data", data
->path
) < 0)
332 if (perf_data__is_write(data
) &&
333 mkdir(data
->path
, S_IRWXU
) < 0)
336 ret
= open_file(data
);
338 /* Cleanup whatever we managed to create so far. */
339 if (ret
&& perf_data__is_write(data
))
340 rm_rf_perf_data(data
->path
);
345 int perf_data__open(struct perf_data
*data
)
347 if (check_pipe(data
))
350 /* currently it allows stdio for pipe only */
351 data
->use_stdio
= false;
354 data
->path
= "perf.data";
356 if (check_backup(data
))
359 if (perf_data__is_read(data
))
360 data
->is_dir
= is_dir(data
);
362 return perf_data__is_dir(data
) ?
363 open_dir(data
) : open_file_dup(data
);
366 void perf_data__close(struct perf_data
*data
)
368 if (perf_data__is_dir(data
))
369 perf_data__close_dir(data
);
371 zfree(&data
->file
.path
);
374 fclose(data
->file
.fptr
);
376 close(data
->file
.fd
);
379 ssize_t
perf_data__read(struct perf_data
*data
, void *buf
, size_t size
)
381 if (data
->use_stdio
) {
382 if (fread(buf
, size
, 1, data
->file
.fptr
) == 1)
384 return feof(data
->file
.fptr
) ? 0 : -1;
386 return readn(data
->file
.fd
, buf
, size
);
389 ssize_t
perf_data_file__write(struct perf_data_file
*file
,
390 void *buf
, size_t size
)
392 return writen(file
->fd
, buf
, size
);
395 ssize_t
perf_data__write(struct perf_data
*data
,
396 void *buf
, size_t size
)
398 if (data
->use_stdio
) {
399 if (fwrite(buf
, size
, 1, data
->file
.fptr
) == 1)
403 return perf_data_file__write(&data
->file
, buf
, size
);
406 int perf_data__switch(struct perf_data
*data
,
408 size_t pos
, bool at_exit
,
413 if (check_pipe(data
))
415 if (perf_data__is_read(data
))
418 if (asprintf(new_filepath
, "%s.%s", data
->path
, postfix
) < 0)
422 * Only fire a warning, don't return error, continue fill
425 if (rename(data
->path
, *new_filepath
))
426 pr_warning("Failed to rename %s to %s\n", data
->path
, *new_filepath
);
429 close(data
->file
.fd
);
430 ret
= perf_data__open(data
);
434 if (lseek(data
->file
.fd
, pos
, SEEK_SET
) == (off_t
)-1) {
436 pr_debug("Failed to lseek to %zu: %s",
437 pos
, strerror(errno
));
446 unsigned long perf_data__size(struct perf_data
*data
)
448 u64 size
= data
->file
.size
;
451 if (perf_data__is_single_file(data
))
454 for (i
= 0; i
< data
->dir
.nr
; i
++) {
455 struct perf_data_file
*file
= &data
->dir
.files
[i
];
463 int perf_data__make_kcore_dir(struct perf_data
*data
, char *buf
, size_t buf_sz
)
470 ret
= snprintf(buf
, buf_sz
, "%s/kcore_dir", data
->path
);
471 if (ret
< 0 || (size_t)ret
>= buf_sz
)
474 return mkdir(buf
, S_IRWXU
);
477 char *perf_data__kallsyms_name(struct perf_data
*data
)
485 if (asprintf(&kallsyms_name
, "%s/kcore_dir/kallsyms", data
->path
) < 0)
488 if (stat(kallsyms_name
, &st
)) {
493 return kallsyms_name
;
496 bool is_perf_data(const char *path
)
502 file
= fopen(path
, "r");
506 if (fread(&magic
, 1, 8, file
) < 8)
509 ret
= is_perf_magic(magic
);