]> Git Repo - linux.git/blob - tools/perf/util/data.c
powerpc/vdso64: Fix CLOCK_MONOTONIC inconsistencies across Y2038
[linux.git] / tools / perf / util / data.c
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
18 static void close_dir(struct perf_data_file *files, int nr)
19 {
20         while (--nr >= 1) {
21                 close(files[nr].fd);
22                 free(files[nr].path);
23         }
24         free(files);
25 }
26
27 void perf_data__close_dir(struct perf_data *data)
28 {
29         close_dir(data->dir.files, data->dir.nr);
30 }
31
32 int perf_data__create_dir(struct perf_data *data, int nr)
33 {
34         struct perf_data_file *files = NULL;
35         int i, ret = -1;
36
37         files = zalloc(nr * sizeof(*files));
38         if (!files)
39                 return -ENOMEM;
40
41         data->dir.files = files;
42         data->dir.nr    = nr;
43
44         for (i = 0; i < nr; i++) {
45                 struct perf_data_file *file = &files[i];
46
47                 if (asprintf(&file->path, "%s/data.%d", data->path, i) < 0)
48                         goto out_err;
49
50                 ret = open(file->path, O_RDWR|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR);
51                 if (ret < 0)
52                         goto out_err;
53
54                 file->fd = ret;
55         }
56
57         return 0;
58
59 out_err:
60         close_dir(files, i);
61         return ret;
62 }
63
64 int perf_data__open_dir(struct perf_data *data)
65 {
66         struct perf_data_file *files = NULL;
67         struct dirent *dent;
68         int ret = -1;
69         DIR *dir;
70         int nr = 0;
71
72         dir = opendir(data->path);
73         if (!dir)
74                 return -EINVAL;
75
76         while ((dent = readdir(dir)) != NULL) {
77                 struct perf_data_file *file;
78                 char path[PATH_MAX];
79                 struct stat st;
80
81                 snprintf(path, sizeof(path), "%s/%s", data->path, dent->d_name);
82                 if (stat(path, &st))
83                         continue;
84
85                 if (!S_ISREG(st.st_mode) || strncmp(dent->d_name, "data", 4))
86                         continue;
87
88                 ret = -ENOMEM;
89
90                 file = realloc(files, (nr + 1) * sizeof(*files));
91                 if (!file)
92                         goto out_err;
93
94                 files = file;
95                 file = &files[nr++];
96
97                 file->path = strdup(path);
98                 if (!file->path)
99                         goto out_err;
100
101                 ret = open(file->path, O_RDONLY);
102                 if (ret < 0)
103                         goto out_err;
104
105                 file->fd = ret;
106                 file->size = st.st_size;
107         }
108
109         if (!files)
110                 return -EINVAL;
111
112         data->dir.files = files;
113         data->dir.nr    = nr;
114         return 0;
115
116 out_err:
117         close_dir(files, nr);
118         return ret;
119 }
120
121 static bool check_pipe(struct perf_data *data)
122 {
123         struct stat st;
124         bool is_pipe = false;
125         int fd = perf_data__is_read(data) ?
126                  STDIN_FILENO : STDOUT_FILENO;
127
128         if (!data->path) {
129                 if (!fstat(fd, &st) && S_ISFIFO(st.st_mode))
130                         is_pipe = true;
131         } else {
132                 if (!strcmp(data->path, "-"))
133                         is_pipe = true;
134         }
135
136         if (is_pipe)
137                 data->file.fd = fd;
138
139         return data->is_pipe = is_pipe;
140 }
141
142 static int check_backup(struct perf_data *data)
143 {
144         struct stat st;
145
146         if (perf_data__is_read(data))
147                 return 0;
148
149         if (!stat(data->path, &st) && st.st_size) {
150                 char oldname[PATH_MAX];
151                 int ret;
152
153                 snprintf(oldname, sizeof(oldname), "%s.old",
154                          data->path);
155
156                 ret = rm_rf_perf_data(oldname);
157                 if (ret) {
158                         pr_err("Can't remove old data: %s (%s)\n",
159                                ret == -2 ?
160                                "Unknown file found" : strerror(errno),
161                                oldname);
162                         return -1;
163                 }
164
165                 if (rename(data->path, oldname)) {
166                         pr_err("Can't move data: %s (%s to %s)\n",
167                                strerror(errno),
168                                data->path, oldname);
169                         return -1;
170                 }
171         }
172
173         return 0;
174 }
175
176 static int open_file_read(struct perf_data *data)
177 {
178         struct stat st;
179         int fd;
180         char sbuf[STRERR_BUFSIZE];
181
182         fd = open(data->file.path, O_RDONLY);
183         if (fd < 0) {
184                 int err = errno;
185
186                 pr_err("failed to open %s: %s", data->file.path,
187                         str_error_r(err, sbuf, sizeof(sbuf)));
188                 if (err == ENOENT && !strcmp(data->file.path, "perf.data"))
189                         pr_err("  (try 'perf record' first)");
190                 pr_err("\n");
191                 return -err;
192         }
193
194         if (fstat(fd, &st) < 0)
195                 goto out_close;
196
197         if (!data->force && st.st_uid && (st.st_uid != geteuid())) {
198                 pr_err("File %s not owned by current user or root (use -f to override)\n",
199                        data->file.path);
200                 goto out_close;
201         }
202
203         if (!st.st_size) {
204                 pr_info("zero-sized data (%s), nothing to do!\n",
205                         data->file.path);
206                 goto out_close;
207         }
208
209         data->file.size = st.st_size;
210         return fd;
211
212  out_close:
213         close(fd);
214         return -1;
215 }
216
217 static int open_file_write(struct perf_data *data)
218 {
219         int fd;
220         char sbuf[STRERR_BUFSIZE];
221
222         fd = open(data->file.path, O_CREAT|O_RDWR|O_TRUNC|O_CLOEXEC,
223                   S_IRUSR|S_IWUSR);
224
225         if (fd < 0)
226                 pr_err("failed to open %s : %s\n", data->file.path,
227                         str_error_r(errno, sbuf, sizeof(sbuf)));
228
229         return fd;
230 }
231
232 static int open_file(struct perf_data *data)
233 {
234         int fd;
235
236         fd = perf_data__is_read(data) ?
237              open_file_read(data) : open_file_write(data);
238
239         if (fd < 0) {
240                 zfree(&data->file.path);
241                 return -1;
242         }
243
244         data->file.fd = fd;
245         return 0;
246 }
247
248 static int open_file_dup(struct perf_data *data)
249 {
250         data->file.path = strdup(data->path);
251         if (!data->file.path)
252                 return -ENOMEM;
253
254         return open_file(data);
255 }
256
257 int perf_data__open(struct perf_data *data)
258 {
259         if (check_pipe(data))
260                 return 0;
261
262         if (!data->path)
263                 data->path = "perf.data";
264
265         if (check_backup(data))
266                 return -1;
267
268         return open_file_dup(data);
269 }
270
271 void perf_data__close(struct perf_data *data)
272 {
273         zfree(&data->file.path);
274         close(data->file.fd);
275 }
276
277 ssize_t perf_data_file__write(struct perf_data_file *file,
278                               void *buf, size_t size)
279 {
280         return writen(file->fd, buf, size);
281 }
282
283 ssize_t perf_data__write(struct perf_data *data,
284                               void *buf, size_t size)
285 {
286         return perf_data_file__write(&data->file, buf, size);
287 }
288
289 int perf_data__switch(struct perf_data *data,
290                            const char *postfix,
291                            size_t pos, bool at_exit)
292 {
293         char *new_filepath;
294         int ret;
295
296         if (check_pipe(data))
297                 return -EINVAL;
298         if (perf_data__is_read(data))
299                 return -EINVAL;
300
301         if (asprintf(&new_filepath, "%s.%s", data->path, postfix) < 0)
302                 return -ENOMEM;
303
304         /*
305          * Only fire a warning, don't return error, continue fill
306          * original file.
307          */
308         if (rename(data->path, new_filepath))
309                 pr_warning("Failed to rename %s to %s\n", data->path, new_filepath);
310
311         if (!at_exit) {
312                 close(data->file.fd);
313                 ret = perf_data__open(data);
314                 if (ret < 0)
315                         goto out;
316
317                 if (lseek(data->file.fd, pos, SEEK_SET) == (off_t)-1) {
318                         ret = -errno;
319                         pr_debug("Failed to lseek to %zu: %s",
320                                  pos, strerror(errno));
321                         goto out;
322                 }
323         }
324         ret = data->file.fd;
325 out:
326         free(new_filepath);
327         return ret;
328 }
This page took 0.051075 seconds and 4 git commands to generate.