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