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