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