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 #include <asm/bug.h> 11 #include <sys/types.h> 12 #include <dirent.h> 13 14 #include "data.h" 15 #include "util.h" 16 #include "debug.h" 17 #include "header.h" 18 19 static void close_dir(struct perf_data_file *files, int nr) 20 { 21 while (--nr >= 1) { 22 close(files[nr].fd); 23 free(files[nr].path); 24 } 25 free(files); 26 } 27 28 void perf_data__close_dir(struct perf_data *data) 29 { 30 close_dir(data->dir.files, data->dir.nr); 31 } 32 33 int perf_data__create_dir(struct perf_data *data, int nr) 34 { 35 struct perf_data_file *files = NULL; 36 int i, ret = -1; 37 38 if (WARN_ON(!data->is_dir)) 39 return -EINVAL; 40 41 files = zalloc(nr * sizeof(*files)); 42 if (!files) 43 return -ENOMEM; 44 45 data->dir.version = PERF_DIR_VERSION; 46 data->dir.files = files; 47 data->dir.nr = nr; 48 49 for (i = 0; i < nr; i++) { 50 struct perf_data_file *file = &files[i]; 51 52 if (asprintf(&file->path, "%s/data.%d", data->path, i) < 0) 53 goto out_err; 54 55 ret = open(file->path, O_RDWR|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR); 56 if (ret < 0) 57 goto out_err; 58 59 file->fd = ret; 60 } 61 62 return 0; 63 64 out_err: 65 close_dir(files, i); 66 return ret; 67 } 68 69 int perf_data__open_dir(struct perf_data *data) 70 { 71 struct perf_data_file *files = NULL; 72 struct dirent *dent; 73 int ret = -1; 74 DIR *dir; 75 int nr = 0; 76 77 if (WARN_ON(!data->is_dir)) 78 return -EINVAL; 79 80 /* The version is provided by DIR_FORMAT feature. */ 81 if (WARN_ON(data->dir.version != PERF_DIR_VERSION)) 82 return -1; 83 84 dir = opendir(data->path); 85 if (!dir) 86 return -EINVAL; 87 88 while ((dent = readdir(dir)) != NULL) { 89 struct perf_data_file *file; 90 char path[PATH_MAX]; 91 struct stat st; 92 93 snprintf(path, sizeof(path), "%s/%s", data->path, dent->d_name); 94 if (stat(path, &st)) 95 continue; 96 97 if (!S_ISREG(st.st_mode) || strncmp(dent->d_name, "data", 4)) 98 continue; 99 100 ret = -ENOMEM; 101 102 file = realloc(files, (nr + 1) * sizeof(*files)); 103 if (!file) 104 goto out_err; 105 106 files = file; 107 file = &files[nr++]; 108 109 file->path = strdup(path); 110 if (!file->path) 111 goto out_err; 112 113 ret = open(file->path, O_RDONLY); 114 if (ret < 0) 115 goto out_err; 116 117 file->fd = ret; 118 file->size = st.st_size; 119 } 120 121 if (!files) 122 return -EINVAL; 123 124 data->dir.files = files; 125 data->dir.nr = nr; 126 return 0; 127 128 out_err: 129 close_dir(files, nr); 130 return ret; 131 } 132 133 int perf_data__update_dir(struct perf_data *data) 134 { 135 int i; 136 137 if (WARN_ON(!data->is_dir)) 138 return -EINVAL; 139 140 for (i = 0; i < data->dir.nr; i++) { 141 struct perf_data_file *file = &data->dir.files[i]; 142 struct stat st; 143 144 if (fstat(file->fd, &st)) 145 return -1; 146 147 file->size = st.st_size; 148 } 149 150 return 0; 151 } 152 153 static bool check_pipe(struct perf_data *data) 154 { 155 struct stat st; 156 bool is_pipe = false; 157 int fd = perf_data__is_read(data) ? 158 STDIN_FILENO : STDOUT_FILENO; 159 160 if (!data->path) { 161 if (!fstat(fd, &st) && S_ISFIFO(st.st_mode)) 162 is_pipe = true; 163 } else { 164 if (!strcmp(data->path, "-")) 165 is_pipe = true; 166 } 167 168 if (is_pipe) 169 data->file.fd = fd; 170 171 return data->is_pipe = is_pipe; 172 } 173 174 static int check_backup(struct perf_data *data) 175 { 176 struct stat st; 177 178 if (perf_data__is_read(data)) 179 return 0; 180 181 if (!stat(data->path, &st) && st.st_size) { 182 char oldname[PATH_MAX]; 183 int ret; 184 185 snprintf(oldname, sizeof(oldname), "%s.old", 186 data->path); 187 188 ret = rm_rf_perf_data(oldname); 189 if (ret) { 190 pr_err("Can't remove old data: %s (%s)\n", 191 ret == -2 ? 192 "Unknown file found" : strerror(errno), 193 oldname); 194 return -1; 195 } 196 197 if (rename(data->path, oldname)) { 198 pr_err("Can't move data: %s (%s to %s)\n", 199 strerror(errno), 200 data->path, oldname); 201 return -1; 202 } 203 } 204 205 return 0; 206 } 207 208 static bool is_dir(struct perf_data *data) 209 { 210 struct stat st; 211 212 if (stat(data->path, &st)) 213 return false; 214 215 return (st.st_mode & S_IFMT) == S_IFDIR; 216 } 217 218 static int open_file_read(struct perf_data *data) 219 { 220 struct stat st; 221 int fd; 222 char sbuf[STRERR_BUFSIZE]; 223 224 fd = open(data->file.path, O_RDONLY); 225 if (fd < 0) { 226 int err = errno; 227 228 pr_err("failed to open %s: %s", data->file.path, 229 str_error_r(err, sbuf, sizeof(sbuf))); 230 if (err == ENOENT && !strcmp(data->file.path, "perf.data")) 231 pr_err(" (try 'perf record' first)"); 232 pr_err("\n"); 233 return -err; 234 } 235 236 if (fstat(fd, &st) < 0) 237 goto out_close; 238 239 if (!data->force && st.st_uid && (st.st_uid != geteuid())) { 240 pr_err("File %s not owned by current user or root (use -f to override)\n", 241 data->file.path); 242 goto out_close; 243 } 244 245 if (!st.st_size) { 246 pr_info("zero-sized data (%s), nothing to do!\n", 247 data->file.path); 248 goto out_close; 249 } 250 251 data->file.size = st.st_size; 252 return fd; 253 254 out_close: 255 close(fd); 256 return -1; 257 } 258 259 static int open_file_write(struct perf_data *data) 260 { 261 int fd; 262 char sbuf[STRERR_BUFSIZE]; 263 264 fd = open(data->file.path, O_CREAT|O_RDWR|O_TRUNC|O_CLOEXEC, 265 S_IRUSR|S_IWUSR); 266 267 if (fd < 0) 268 pr_err("failed to open %s : %s\n", data->file.path, 269 str_error_r(errno, sbuf, sizeof(sbuf))); 270 271 return fd; 272 } 273 274 static int open_file(struct perf_data *data) 275 { 276 int fd; 277 278 fd = perf_data__is_read(data) ? 279 open_file_read(data) : open_file_write(data); 280 281 if (fd < 0) { 282 zfree(&data->file.path); 283 return -1; 284 } 285 286 data->file.fd = fd; 287 return 0; 288 } 289 290 static int open_file_dup(struct perf_data *data) 291 { 292 data->file.path = strdup(data->path); 293 if (!data->file.path) 294 return -ENOMEM; 295 296 return open_file(data); 297 } 298 299 static int open_dir(struct perf_data *data) 300 { 301 int ret; 302 303 /* 304 * So far we open only the header, so we can read the data version and 305 * layout. 306 */ 307 if (asprintf(&data->file.path, "%s/header", data->path) < 0) 308 return -1; 309 310 if (perf_data__is_write(data) && 311 mkdir(data->path, S_IRWXU) < 0) 312 return -1; 313 314 ret = open_file(data); 315 316 /* Cleanup whatever we managed to create so far. */ 317 if (ret && perf_data__is_write(data)) 318 rm_rf_perf_data(data->path); 319 320 return ret; 321 } 322 323 int perf_data__open(struct perf_data *data) 324 { 325 if (check_pipe(data)) 326 return 0; 327 328 if (!data->path) 329 data->path = "perf.data"; 330 331 if (check_backup(data)) 332 return -1; 333 334 if (perf_data__is_read(data)) 335 data->is_dir = is_dir(data); 336 337 return perf_data__is_dir(data) ? 338 open_dir(data) : open_file_dup(data); 339 } 340 341 void perf_data__close(struct perf_data *data) 342 { 343 if (perf_data__is_dir(data)) 344 perf_data__close_dir(data); 345 346 zfree(&data->file.path); 347 close(data->file.fd); 348 } 349 350 ssize_t perf_data_file__write(struct perf_data_file *file, 351 void *buf, size_t size) 352 { 353 return writen(file->fd, buf, size); 354 } 355 356 ssize_t perf_data__write(struct perf_data *data, 357 void *buf, size_t size) 358 { 359 return perf_data_file__write(&data->file, buf, size); 360 } 361 362 int perf_data__switch(struct perf_data *data, 363 const char *postfix, 364 size_t pos, bool at_exit, 365 char **new_filepath) 366 { 367 int ret; 368 369 if (check_pipe(data)) 370 return -EINVAL; 371 if (perf_data__is_read(data)) 372 return -EINVAL; 373 374 if (asprintf(new_filepath, "%s.%s", data->path, postfix) < 0) 375 return -ENOMEM; 376 377 /* 378 * Only fire a warning, don't return error, continue fill 379 * original file. 380 */ 381 if (rename(data->path, *new_filepath)) 382 pr_warning("Failed to rename %s to %s\n", data->path, *new_filepath); 383 384 if (!at_exit) { 385 close(data->file.fd); 386 ret = perf_data__open(data); 387 if (ret < 0) 388 goto out; 389 390 if (lseek(data->file.fd, pos, SEEK_SET) == (off_t)-1) { 391 ret = -errno; 392 pr_debug("Failed to lseek to %zu: %s", 393 pos, strerror(errno)); 394 goto out; 395 } 396 } 397 ret = data->file.fd; 398 out: 399 return ret; 400 } 401 402 unsigned long perf_data__size(struct perf_data *data) 403 { 404 u64 size = data->file.size; 405 int i; 406 407 if (!data->is_dir) 408 return size; 409 410 for (i = 0; i < data->dir.nr; i++) { 411 struct perf_data_file *file = &data->dir.files[i]; 412 413 size += file->size; 414 } 415 416 return size; 417 } 418