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