xref: /openbmc/linux/tools/perf/util/data.c (revision 9dae47aba0a055f761176d9297371d5bb24289ec)
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 
25 static 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 
46 static 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 
62 static 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 
103 static 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 
121 static 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 
132 int 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 
143 void perf_data__close(struct perf_data *data)
144 {
145 	close(data->file.fd);
146 }
147 
148 ssize_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 
154 ssize_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 
160 int 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;
196 out:
197 	free(new_filepath);
198 	return ret;
199 }
200