xref: /openbmc/linux/tools/perf/util/data.c (revision 239480ab)
1 #include <linux/compiler.h>
2 #include <linux/kernel.h>
3 #include <sys/types.h>
4 #include <sys/stat.h>
5 #include <errno.h>
6 #include <unistd.h>
7 #include <string.h>
8 
9 #include "data.h"
10 #include "util.h"
11 #include "debug.h"
12 
13 static bool check_pipe(struct perf_data_file *file)
14 {
15 	struct stat st;
16 	bool is_pipe = false;
17 	int fd = perf_data_file__is_read(file) ?
18 		 STDIN_FILENO : STDOUT_FILENO;
19 
20 	if (!file->path) {
21 		if (!fstat(fd, &st) && S_ISFIFO(st.st_mode))
22 			is_pipe = true;
23 	} else {
24 		if (!strcmp(file->path, "-"))
25 			is_pipe = true;
26 	}
27 
28 	if (is_pipe)
29 		file->fd = fd;
30 
31 	return file->is_pipe = is_pipe;
32 }
33 
34 static int check_backup(struct perf_data_file *file)
35 {
36 	struct stat st;
37 
38 	if (!stat(file->path, &st) && st.st_size) {
39 		/* TODO check errors properly */
40 		char oldname[PATH_MAX];
41 		snprintf(oldname, sizeof(oldname), "%s.old",
42 			 file->path);
43 		unlink(oldname);
44 		rename(file->path, oldname);
45 	}
46 
47 	return 0;
48 }
49 
50 static int open_file_read(struct perf_data_file *file)
51 {
52 	struct stat st;
53 	int fd;
54 	char sbuf[STRERR_BUFSIZE];
55 
56 	fd = open(file->path, O_RDONLY);
57 	if (fd < 0) {
58 		int err = errno;
59 
60 		pr_err("failed to open %s: %s", file->path,
61 			str_error_r(err, sbuf, sizeof(sbuf)));
62 		if (err == ENOENT && !strcmp(file->path, "perf.data"))
63 			pr_err("  (try 'perf record' first)");
64 		pr_err("\n");
65 		return -err;
66 	}
67 
68 	if (fstat(fd, &st) < 0)
69 		goto out_close;
70 
71 	if (!file->force && st.st_uid && (st.st_uid != geteuid())) {
72 		pr_err("File %s not owned by current user or root (use -f to override)\n",
73 		       file->path);
74 		goto out_close;
75 	}
76 
77 	if (!st.st_size) {
78 		pr_info("zero-sized file (%s), nothing to do!\n",
79 			file->path);
80 		goto out_close;
81 	}
82 
83 	file->size = st.st_size;
84 	return fd;
85 
86  out_close:
87 	close(fd);
88 	return -1;
89 }
90 
91 static int open_file_write(struct perf_data_file *file)
92 {
93 	int fd;
94 	char sbuf[STRERR_BUFSIZE];
95 
96 	if (check_backup(file))
97 		return -1;
98 
99 	fd = open(file->path, O_CREAT|O_RDWR|O_TRUNC, S_IRUSR|S_IWUSR);
100 
101 	if (fd < 0)
102 		pr_err("failed to open %s : %s\n", file->path,
103 			str_error_r(errno, sbuf, sizeof(sbuf)));
104 
105 	return fd;
106 }
107 
108 static int open_file(struct perf_data_file *file)
109 {
110 	int fd;
111 
112 	fd = perf_data_file__is_read(file) ?
113 	     open_file_read(file) : open_file_write(file);
114 
115 	file->fd = fd;
116 	return fd < 0 ? -1 : 0;
117 }
118 
119 int perf_data_file__open(struct perf_data_file *file)
120 {
121 	if (check_pipe(file))
122 		return 0;
123 
124 	if (!file->path)
125 		file->path = "perf.data";
126 
127 	return open_file(file);
128 }
129 
130 void perf_data_file__close(struct perf_data_file *file)
131 {
132 	close(file->fd);
133 }
134 
135 ssize_t perf_data_file__write(struct perf_data_file *file,
136 			      void *buf, size_t size)
137 {
138 	return writen(file->fd, buf, size);
139 }
140 
141 int perf_data_file__switch(struct perf_data_file *file,
142 			   const char *postfix,
143 			   size_t pos, bool at_exit)
144 {
145 	char *new_filepath;
146 	int ret;
147 
148 	if (check_pipe(file))
149 		return -EINVAL;
150 	if (perf_data_file__is_read(file))
151 		return -EINVAL;
152 
153 	if (asprintf(&new_filepath, "%s.%s", file->path, postfix) < 0)
154 		return -ENOMEM;
155 
156 	/*
157 	 * Only fire a warning, don't return error, continue fill
158 	 * original file.
159 	 */
160 	if (rename(file->path, new_filepath))
161 		pr_warning("Failed to rename %s to %s\n", file->path, new_filepath);
162 
163 	if (!at_exit) {
164 		close(file->fd);
165 		ret = perf_data_file__open(file);
166 		if (ret < 0)
167 			goto out;
168 
169 		if (lseek(file->fd, pos, SEEK_SET) == (off_t)-1) {
170 			ret = -errno;
171 			pr_debug("Failed to lseek to %zu: %s",
172 				 pos, strerror(errno));
173 			goto out;
174 		}
175 	}
176 	ret = file->fd;
177 out:
178 	free(new_filepath);
179 	return ret;
180 }
181