Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 #include <linux/compiler.h>
0003 #include <linux/kernel.h>
0004 #include <linux/string.h>
0005 #include <linux/zalloc.h>
0006 #include <linux/err.h>
0007 #include <sys/types.h>
0008 #include <sys/stat.h>
0009 #include <errno.h>
0010 #include <fcntl.h>
0011 #include <unistd.h>
0012 #include <string.h>
0013 #include <asm/bug.h>
0014 #include <dirent.h>
0015 
0016 #include "data.h"
0017 #include "util.h" // rm_rf_perf_data()
0018 #include "debug.h"
0019 #include "header.h"
0020 #include <internal/lib.h>
0021 
0022 static void close_dir(struct perf_data_file *files, int nr)
0023 {
0024     while (--nr >= 0) {
0025         close(files[nr].fd);
0026         zfree(&files[nr].path);
0027     }
0028     free(files);
0029 }
0030 
0031 void perf_data__close_dir(struct perf_data *data)
0032 {
0033     close_dir(data->dir.files, data->dir.nr);
0034 }
0035 
0036 int perf_data__create_dir(struct perf_data *data, int nr)
0037 {
0038     struct perf_data_file *files = NULL;
0039     int i, ret;
0040 
0041     if (WARN_ON(!data->is_dir))
0042         return -EINVAL;
0043 
0044     files = zalloc(nr * sizeof(*files));
0045     if (!files)
0046         return -ENOMEM;
0047 
0048     for (i = 0; i < nr; i++) {
0049         struct perf_data_file *file = &files[i];
0050 
0051         ret = asprintf(&file->path, "%s/data.%d", data->path, i);
0052         if (ret < 0) {
0053             ret = -ENOMEM;
0054             goto out_err;
0055         }
0056 
0057         ret = open(file->path, O_RDWR|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR);
0058         if (ret < 0) {
0059             ret = -errno;
0060             goto out_err;
0061         }
0062 
0063         file->fd = ret;
0064     }
0065 
0066     data->dir.version = PERF_DIR_VERSION;
0067     data->dir.files   = files;
0068     data->dir.nr      = nr;
0069     return 0;
0070 
0071 out_err:
0072     close_dir(files, i);
0073     return ret;
0074 }
0075 
0076 int perf_data__open_dir(struct perf_data *data)
0077 {
0078     struct perf_data_file *files = NULL;
0079     struct dirent *dent;
0080     int ret = -1;
0081     DIR *dir;
0082     int nr = 0;
0083 
0084     /*
0085      * Directory containing a single regular perf data file which is already
0086      * open, means there is nothing more to do here.
0087      */
0088     if (perf_data__is_single_file(data))
0089         return 0;
0090 
0091     if (WARN_ON(!data->is_dir))
0092         return -EINVAL;
0093 
0094     /* The version is provided by DIR_FORMAT feature. */
0095     if (WARN_ON(data->dir.version != PERF_DIR_VERSION))
0096         return -1;
0097 
0098     dir = opendir(data->path);
0099     if (!dir)
0100         return -EINVAL;
0101 
0102     while ((dent = readdir(dir)) != NULL) {
0103         struct perf_data_file *file;
0104         char path[PATH_MAX];
0105         struct stat st;
0106 
0107         snprintf(path, sizeof(path), "%s/%s", data->path, dent->d_name);
0108         if (stat(path, &st))
0109             continue;
0110 
0111         if (!S_ISREG(st.st_mode) || strncmp(dent->d_name, "data.", 5))
0112             continue;
0113 
0114         ret = -ENOMEM;
0115 
0116         file = realloc(files, (nr + 1) * sizeof(*files));
0117         if (!file)
0118             goto out_err;
0119 
0120         files = file;
0121         file = &files[nr++];
0122 
0123         file->path = strdup(path);
0124         if (!file->path)
0125             goto out_err;
0126 
0127         ret = open(file->path, O_RDONLY);
0128         if (ret < 0)
0129             goto out_err;
0130 
0131         file->fd = ret;
0132         file->size = st.st_size;
0133     }
0134 
0135     if (!files)
0136         return -EINVAL;
0137 
0138     data->dir.files = files;
0139     data->dir.nr    = nr;
0140     return 0;
0141 
0142 out_err:
0143     close_dir(files, nr);
0144     return ret;
0145 }
0146 
0147 int perf_data__update_dir(struct perf_data *data)
0148 {
0149     int i;
0150 
0151     if (WARN_ON(!data->is_dir))
0152         return -EINVAL;
0153 
0154     for (i = 0; i < data->dir.nr; i++) {
0155         struct perf_data_file *file = &data->dir.files[i];
0156         struct stat st;
0157 
0158         if (fstat(file->fd, &st))
0159             return -1;
0160 
0161         file->size = st.st_size;
0162     }
0163 
0164     return 0;
0165 }
0166 
0167 static bool check_pipe(struct perf_data *data)
0168 {
0169     struct stat st;
0170     bool is_pipe = false;
0171     int fd = perf_data__is_read(data) ?
0172          STDIN_FILENO : STDOUT_FILENO;
0173 
0174     if (!data->path) {
0175         if (!fstat(fd, &st) && S_ISFIFO(st.st_mode))
0176             is_pipe = true;
0177     } else {
0178         if (!strcmp(data->path, "-"))
0179             is_pipe = true;
0180     }
0181 
0182     if (is_pipe) {
0183         if (data->use_stdio) {
0184             const char *mode;
0185 
0186             mode = perf_data__is_read(data) ? "r" : "w";
0187             data->file.fptr = fdopen(fd, mode);
0188 
0189             if (data->file.fptr == NULL) {
0190                 data->file.fd = fd;
0191                 data->use_stdio = false;
0192             }
0193         } else {
0194             data->file.fd = fd;
0195         }
0196     }
0197 
0198     return data->is_pipe = is_pipe;
0199 }
0200 
0201 static int check_backup(struct perf_data *data)
0202 {
0203     struct stat st;
0204 
0205     if (perf_data__is_read(data))
0206         return 0;
0207 
0208     if (!stat(data->path, &st) && st.st_size) {
0209         char oldname[PATH_MAX];
0210         int ret;
0211 
0212         snprintf(oldname, sizeof(oldname), "%s.old",
0213              data->path);
0214 
0215         ret = rm_rf_perf_data(oldname);
0216         if (ret) {
0217             pr_err("Can't remove old data: %s (%s)\n",
0218                    ret == -2 ?
0219                    "Unknown file found" : strerror(errno),
0220                    oldname);
0221             return -1;
0222         }
0223 
0224         if (rename(data->path, oldname)) {
0225             pr_err("Can't move data: %s (%s to %s)\n",
0226                    strerror(errno),
0227                    data->path, oldname);
0228             return -1;
0229         }
0230     }
0231 
0232     return 0;
0233 }
0234 
0235 static bool is_dir(struct perf_data *data)
0236 {
0237     struct stat st;
0238 
0239     if (stat(data->path, &st))
0240         return false;
0241 
0242     return (st.st_mode & S_IFMT) == S_IFDIR;
0243 }
0244 
0245 static int open_file_read(struct perf_data *data)
0246 {
0247     int flags = data->in_place_update ? O_RDWR : O_RDONLY;
0248     struct stat st;
0249     int fd;
0250     char sbuf[STRERR_BUFSIZE];
0251 
0252     fd = open(data->file.path, flags);
0253     if (fd < 0) {
0254         int err = errno;
0255 
0256         pr_err("failed to open %s: %s", data->file.path,
0257             str_error_r(err, sbuf, sizeof(sbuf)));
0258         if (err == ENOENT && !strcmp(data->file.path, "perf.data"))
0259             pr_err("  (try 'perf record' first)");
0260         pr_err("\n");
0261         return -err;
0262     }
0263 
0264     if (fstat(fd, &st) < 0)
0265         goto out_close;
0266 
0267     if (!data->force && st.st_uid && (st.st_uid != geteuid())) {
0268         pr_err("File %s not owned by current user or root (use -f to override)\n",
0269                data->file.path);
0270         goto out_close;
0271     }
0272 
0273     if (!st.st_size) {
0274         pr_info("zero-sized data (%s), nothing to do!\n",
0275             data->file.path);
0276         goto out_close;
0277     }
0278 
0279     data->file.size = st.st_size;
0280     return fd;
0281 
0282  out_close:
0283     close(fd);
0284     return -1;
0285 }
0286 
0287 static int open_file_write(struct perf_data *data)
0288 {
0289     int fd;
0290     char sbuf[STRERR_BUFSIZE];
0291 
0292     fd = open(data->file.path, O_CREAT|O_RDWR|O_TRUNC|O_CLOEXEC,
0293           S_IRUSR|S_IWUSR);
0294 
0295     if (fd < 0)
0296         pr_err("failed to open %s : %s\n", data->file.path,
0297             str_error_r(errno, sbuf, sizeof(sbuf)));
0298 
0299     return fd;
0300 }
0301 
0302 static int open_file(struct perf_data *data)
0303 {
0304     int fd;
0305 
0306     fd = perf_data__is_read(data) ?
0307          open_file_read(data) : open_file_write(data);
0308 
0309     if (fd < 0) {
0310         zfree(&data->file.path);
0311         return -1;
0312     }
0313 
0314     data->file.fd = fd;
0315     return 0;
0316 }
0317 
0318 static int open_file_dup(struct perf_data *data)
0319 {
0320     data->file.path = strdup(data->path);
0321     if (!data->file.path)
0322         return -ENOMEM;
0323 
0324     return open_file(data);
0325 }
0326 
0327 static int open_dir(struct perf_data *data)
0328 {
0329     int ret;
0330 
0331     /*
0332      * So far we open only the header, so we can read the data version and
0333      * layout.
0334      */
0335     if (asprintf(&data->file.path, "%s/data", data->path) < 0)
0336         return -1;
0337 
0338     if (perf_data__is_write(data) &&
0339         mkdir(data->path, S_IRWXU) < 0)
0340         return -1;
0341 
0342     ret = open_file(data);
0343 
0344     /* Cleanup whatever we managed to create so far. */
0345     if (ret && perf_data__is_write(data))
0346         rm_rf_perf_data(data->path);
0347 
0348     return ret;
0349 }
0350 
0351 int perf_data__open(struct perf_data *data)
0352 {
0353     if (check_pipe(data))
0354         return 0;
0355 
0356     /* currently it allows stdio for pipe only */
0357     data->use_stdio = false;
0358 
0359     if (!data->path)
0360         data->path = "perf.data";
0361 
0362     if (check_backup(data))
0363         return -1;
0364 
0365     if (perf_data__is_read(data))
0366         data->is_dir = is_dir(data);
0367 
0368     return perf_data__is_dir(data) ?
0369            open_dir(data) : open_file_dup(data);
0370 }
0371 
0372 void perf_data__close(struct perf_data *data)
0373 {
0374     if (perf_data__is_dir(data))
0375         perf_data__close_dir(data);
0376 
0377     zfree(&data->file.path);
0378 
0379     if (data->use_stdio)
0380         fclose(data->file.fptr);
0381     else
0382         close(data->file.fd);
0383 }
0384 
0385 ssize_t perf_data__read(struct perf_data *data, void *buf, size_t size)
0386 {
0387     if (data->use_stdio) {
0388         if (fread(buf, size, 1, data->file.fptr) == 1)
0389             return size;
0390         return feof(data->file.fptr) ? 0 : -1;
0391     }
0392     return readn(data->file.fd, buf, size);
0393 }
0394 
0395 ssize_t perf_data_file__write(struct perf_data_file *file,
0396                   void *buf, size_t size)
0397 {
0398     return writen(file->fd, buf, size);
0399 }
0400 
0401 ssize_t perf_data__write(struct perf_data *data,
0402                   void *buf, size_t size)
0403 {
0404     if (data->use_stdio) {
0405         if (fwrite(buf, size, 1, data->file.fptr) == 1)
0406             return size;
0407         return -1;
0408     }
0409     return perf_data_file__write(&data->file, buf, size);
0410 }
0411 
0412 int perf_data__switch(struct perf_data *data,
0413                const char *postfix,
0414                size_t pos, bool at_exit,
0415                char **new_filepath)
0416 {
0417     int ret;
0418 
0419     if (check_pipe(data))
0420         return -EINVAL;
0421     if (perf_data__is_read(data))
0422         return -EINVAL;
0423 
0424     if (asprintf(new_filepath, "%s.%s", data->path, postfix) < 0)
0425         return -ENOMEM;
0426 
0427     /*
0428      * Only fire a warning, don't return error, continue fill
0429      * original file.
0430      */
0431     if (rename(data->path, *new_filepath))
0432         pr_warning("Failed to rename %s to %s\n", data->path, *new_filepath);
0433 
0434     if (!at_exit) {
0435         close(data->file.fd);
0436         ret = perf_data__open(data);
0437         if (ret < 0)
0438             goto out;
0439 
0440         if (lseek(data->file.fd, pos, SEEK_SET) == (off_t)-1) {
0441             ret = -errno;
0442             pr_debug("Failed to lseek to %zu: %s",
0443                  pos, strerror(errno));
0444             goto out;
0445         }
0446     }
0447     ret = data->file.fd;
0448 out:
0449     return ret;
0450 }
0451 
0452 unsigned long perf_data__size(struct perf_data *data)
0453 {
0454     u64 size = data->file.size;
0455     int i;
0456 
0457     if (perf_data__is_single_file(data))
0458         return size;
0459 
0460     for (i = 0; i < data->dir.nr; i++) {
0461         struct perf_data_file *file = &data->dir.files[i];
0462 
0463         size += file->size;
0464     }
0465 
0466     return size;
0467 }
0468 
0469 int perf_data__make_kcore_dir(struct perf_data *data, char *buf, size_t buf_sz)
0470 {
0471     int ret;
0472 
0473     if (!data->is_dir)
0474         return -1;
0475 
0476     ret = snprintf(buf, buf_sz, "%s/kcore_dir", data->path);
0477     if (ret < 0 || (size_t)ret >= buf_sz)
0478         return -1;
0479 
0480     return mkdir(buf, S_IRWXU);
0481 }
0482 
0483 bool has_kcore_dir(const char *path)
0484 {
0485     struct dirent *d = ERR_PTR(-EINVAL);
0486     const char *name = "kcore_dir";
0487     DIR *dir = opendir(path);
0488     size_t n = strlen(name);
0489     bool result = false;
0490 
0491     if (dir) {
0492         while (d && !result) {
0493             d = readdir(dir);
0494             result = d ? strncmp(d->d_name, name, n) : false;
0495         }
0496         closedir(dir);
0497     }
0498 
0499     return result;
0500 }
0501 
0502 char *perf_data__kallsyms_name(struct perf_data *data)
0503 {
0504     char *kallsyms_name;
0505     struct stat st;
0506 
0507     if (!data->is_dir)
0508         return NULL;
0509 
0510     if (asprintf(&kallsyms_name, "%s/kcore_dir/kallsyms", data->path) < 0)
0511         return NULL;
0512 
0513     if (stat(kallsyms_name, &st)) {
0514         free(kallsyms_name);
0515         return NULL;
0516     }
0517 
0518     return kallsyms_name;
0519 }
0520 
0521 char *perf_data__guest_kallsyms_name(struct perf_data *data, pid_t machine_pid)
0522 {
0523     char *kallsyms_name;
0524     struct stat st;
0525 
0526     if (!data->is_dir)
0527         return NULL;
0528 
0529     if (asprintf(&kallsyms_name, "%s/kcore_dir__%d/kallsyms", data->path, machine_pid) < 0)
0530         return NULL;
0531 
0532     if (stat(kallsyms_name, &st)) {
0533         free(kallsyms_name);
0534         return NULL;
0535     }
0536 
0537     return kallsyms_name;
0538 }
0539 
0540 bool is_perf_data(const char *path)
0541 {
0542     bool ret = false;
0543     FILE *file;
0544     u64 magic;
0545 
0546     file = fopen(path, "r");
0547     if (!file)
0548         return false;
0549 
0550     if (fread(&magic, 1, 8, file) < 8)
0551         goto out;
0552 
0553     ret = is_perf_magic(magic);
0554 out:
0555     fclose(file);
0556     return ret;
0557 }