Merge remote-tracking branch 'asoc/topic/pcm512x' into asoc-next
[sfrench/cifs-2.6.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 }