]> git.ipfire.org Git - thirdparty/kernel/linux.git/blob - tools/perf/util/data.c
License cleanup: add SPDX GPL-2.0 license identifier to files with no license
[thirdparty/kernel/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 <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
24 static 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
45 static 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
61 static 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
102 static 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
120 static 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
131 int 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
142 void perf_data_file__close(struct perf_data_file *file)
143 {
144 close(file->fd);
145 }
146
147 ssize_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
153 int 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;
189 out:
190 free(new_filepath);
191 return ret;
192 }