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