xref: /openbmc/linux/tools/perf/util/data.c (revision bc05aa6e)
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 }
190