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
, "-"))
180 return data
->is_pipe
= is_pipe
;
183 static int check_backup(struct perf_data
*data
)
187 if (perf_data__is_read(data
))
190 if (!stat(data
->path
, &st
) && st
.st_size
) {
191 char oldname
[PATH_MAX
];
194 snprintf(oldname
, sizeof(oldname
), "%s.old",
197 ret
= rm_rf_perf_data(oldname
);
199 pr_err("Can't remove old data: %s (%s)\n",
201 "Unknown file found" : strerror(errno
),
206 if (rename(data
->path
, oldname
)) {
207 pr_err("Can't move data: %s (%s to %s)\n",
209 data
->path
, oldname
);
217 static bool is_dir(struct perf_data
*data
)
221 if (stat(data
->path
, &st
))
224 return (st
.st_mode
& S_IFMT
) == S_IFDIR
;
227 static int open_file_read(struct perf_data
*data
)
231 char sbuf
[STRERR_BUFSIZE
];
233 fd
= open(data
->file
.path
, O_RDONLY
);
237 pr_err("failed to open %s: %s", data
->file
.path
,
238 str_error_r(err
, sbuf
, sizeof(sbuf
)));
239 if (err
== ENOENT
&& !strcmp(data
->file
.path
, "perf.data"))
240 pr_err(" (try 'perf record' first)");
245 if (fstat(fd
, &st
) < 0)
248 if (!data
->force
&& st
.st_uid
&& (st
.st_uid
!= geteuid())) {
249 pr_err("File %s not owned by current user or root (use -f to override)\n",
255 pr_info("zero-sized data (%s), nothing to do!\n",
260 data
->file
.size
= st
.st_size
;
268 static int open_file_write(struct perf_data
*data
)
271 char sbuf
[STRERR_BUFSIZE
];
273 fd
= open(data
->file
.path
, O_CREAT
|O_RDWR
|O_TRUNC
|O_CLOEXEC
,
277 pr_err("failed to open %s : %s\n", data
->file
.path
,
278 str_error_r(errno
, sbuf
, sizeof(sbuf
)));
283 static int open_file(struct perf_data
*data
)
287 fd
= perf_data__is_read(data
) ?
288 open_file_read(data
) : open_file_write(data
);
291 zfree(&data
->file
.path
);
299 static int open_file_dup(struct perf_data
*data
)
301 data
->file
.path
= strdup(data
->path
);
302 if (!data
->file
.path
)
305 return open_file(data
);
308 static int open_dir(struct perf_data
*data
)
313 * So far we open only the header, so we can read the data version and
316 if (asprintf(&data
->file
.path
, "%s/data", data
->path
) < 0)
319 if (perf_data__is_write(data
) &&
320 mkdir(data
->path
, S_IRWXU
) < 0)
323 ret
= open_file(data
);
325 /* Cleanup whatever we managed to create so far. */
326 if (ret
&& perf_data__is_write(data
))
327 rm_rf_perf_data(data
->path
);
332 int perf_data__open(struct perf_data
*data
)
334 if (check_pipe(data
))
338 data
->path
= "perf.data";
340 if (check_backup(data
))
343 if (perf_data__is_read(data
))
344 data
->is_dir
= is_dir(data
);
346 return perf_data__is_dir(data
) ?
347 open_dir(data
) : open_file_dup(data
);
350 void perf_data__close(struct perf_data
*data
)
352 if (perf_data__is_dir(data
))
353 perf_data__close_dir(data
);
355 zfree(&data
->file
.path
);
356 close(data
->file
.fd
);
359 ssize_t
perf_data_file__write(struct perf_data_file
*file
,
360 void *buf
, size_t size
)
362 return writen(file
->fd
, buf
, size
);
365 ssize_t
perf_data__write(struct perf_data
*data
,
366 void *buf
, size_t size
)
368 return perf_data_file__write(&data
->file
, buf
, size
);
371 int perf_data__switch(struct perf_data
*data
,
373 size_t pos
, bool at_exit
,
378 if (check_pipe(data
))
380 if (perf_data__is_read(data
))
383 if (asprintf(new_filepath
, "%s.%s", data
->path
, postfix
) < 0)
387 * Only fire a warning, don't return error, continue fill
390 if (rename(data
->path
, *new_filepath
))
391 pr_warning("Failed to rename %s to %s\n", data
->path
, *new_filepath
);
394 close(data
->file
.fd
);
395 ret
= perf_data__open(data
);
399 if (lseek(data
->file
.fd
, pos
, SEEK_SET
) == (off_t
)-1) {
401 pr_debug("Failed to lseek to %zu: %s",
402 pos
, strerror(errno
));
411 unsigned long perf_data__size(struct perf_data
*data
)
413 u64 size
= data
->file
.size
;
416 if (perf_data__is_single_file(data
))
419 for (i
= 0; i
< data
->dir
.nr
; i
++) {
420 struct perf_data_file
*file
= &data
->dir
.files
[i
];
428 int perf_data__make_kcore_dir(struct perf_data
*data
, char *buf
, size_t buf_sz
)
435 ret
= snprintf(buf
, buf_sz
, "%s/kcore_dir", data
->path
);
436 if (ret
< 0 || (size_t)ret
>= buf_sz
)
439 return mkdir(buf
, S_IRWXU
);
442 char *perf_data__kallsyms_name(struct perf_data
*data
)
450 if (asprintf(&kallsyms_name
, "%s/kcore_dir/kallsyms", data
->path
) < 0)
453 if (stat(kallsyms_name
, &st
)) {
458 return kallsyms_name
;