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