linux/tools/perf/util/util.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2#include "../perf.h"
   3#include "util.h"
   4#include "debug.h"
   5#include <api/fs/fs.h>
   6#include <sys/mman.h>
   7#include <sys/stat.h>
   8#include <sys/utsname.h>
   9#include <dirent.h>
  10#include <inttypes.h>
  11#include <signal.h>
  12#include <stdio.h>
  13#include <stdlib.h>
  14#include <string.h>
  15#include <errno.h>
  16#include <limits.h>
  17#include <linux/kernel.h>
  18#include <linux/log2.h>
  19#include <linux/time64.h>
  20#include <unistd.h>
  21#include "strlist.h"
  22
  23/*
  24 * XXX We need to find a better place for these things...
  25 */
  26unsigned int page_size;
  27int cacheline_size;
  28
  29int sysctl_perf_event_max_stack = PERF_MAX_STACK_DEPTH;
  30int sysctl_perf_event_max_contexts_per_stack = PERF_MAX_CONTEXTS_PER_STACK;
  31
  32bool test_attr__enabled;
  33
  34bool perf_host  = true;
  35bool perf_guest = false;
  36
  37void event_attr_init(struct perf_event_attr *attr)
  38{
  39        if (!perf_host)
  40                attr->exclude_host  = 1;
  41        if (!perf_guest)
  42                attr->exclude_guest = 1;
  43        /* to capture ABI version */
  44        attr->size = sizeof(*attr);
  45}
  46
  47int mkdir_p(char *path, mode_t mode)
  48{
  49        struct stat st;
  50        int err;
  51        char *d = path;
  52
  53        if (*d != '/')
  54                return -1;
  55
  56        if (stat(path, &st) == 0)
  57                return 0;
  58
  59        while (*++d == '/');
  60
  61        while ((d = strchr(d, '/'))) {
  62                *d = '\0';
  63                err = stat(path, &st) && mkdir(path, mode);
  64                *d++ = '/';
  65                if (err)
  66                        return -1;
  67                while (*d == '/')
  68                        ++d;
  69        }
  70        return (stat(path, &st) && mkdir(path, mode)) ? -1 : 0;
  71}
  72
  73int rm_rf(const char *path)
  74{
  75        DIR *dir;
  76        int ret = 0;
  77        struct dirent *d;
  78        char namebuf[PATH_MAX];
  79
  80        dir = opendir(path);
  81        if (dir == NULL)
  82                return 0;
  83
  84        while ((d = readdir(dir)) != NULL && !ret) {
  85                struct stat statbuf;
  86
  87                if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
  88                        continue;
  89
  90                scnprintf(namebuf, sizeof(namebuf), "%s/%s",
  91                          path, d->d_name);
  92
  93                /* We have to check symbolic link itself */
  94                ret = lstat(namebuf, &statbuf);
  95                if (ret < 0) {
  96                        pr_debug("stat failed: %s\n", namebuf);
  97                        break;
  98                }
  99
 100                if (S_ISDIR(statbuf.st_mode))
 101                        ret = rm_rf(namebuf);
 102                else
 103                        ret = unlink(namebuf);
 104        }
 105        closedir(dir);
 106
 107        if (ret < 0)
 108                return ret;
 109
 110        return rmdir(path);
 111}
 112
 113/* A filter which removes dot files */
 114bool lsdir_no_dot_filter(const char *name __maybe_unused, struct dirent *d)
 115{
 116        return d->d_name[0] != '.';
 117}
 118
 119/* lsdir reads a directory and store it in strlist */
 120struct strlist *lsdir(const char *name,
 121                      bool (*filter)(const char *, struct dirent *))
 122{
 123        struct strlist *list = NULL;
 124        DIR *dir;
 125        struct dirent *d;
 126
 127        dir = opendir(name);
 128        if (!dir)
 129                return NULL;
 130
 131        list = strlist__new(NULL, NULL);
 132        if (!list) {
 133                errno = ENOMEM;
 134                goto out;
 135        }
 136
 137        while ((d = readdir(dir)) != NULL) {
 138                if (!filter || filter(name, d))
 139                        strlist__add(list, d->d_name);
 140        }
 141
 142out:
 143        closedir(dir);
 144        return list;
 145}
 146
 147static int slow_copyfile(const char *from, const char *to, struct nsinfo *nsi)
 148{
 149        int err = -1;
 150        char *line = NULL;
 151        size_t n;
 152        FILE *from_fp, *to_fp;
 153        struct nscookie nsc;
 154
 155        nsinfo__mountns_enter(nsi, &nsc);
 156        from_fp = fopen(from, "r");
 157        nsinfo__mountns_exit(&nsc);
 158        if (from_fp == NULL)
 159                goto out;
 160
 161        to_fp = fopen(to, "w");
 162        if (to_fp == NULL)
 163                goto out_fclose_from;
 164
 165        while (getline(&line, &n, from_fp) > 0)
 166                if (fputs(line, to_fp) == EOF)
 167                        goto out_fclose_to;
 168        err = 0;
 169out_fclose_to:
 170        fclose(to_fp);
 171        free(line);
 172out_fclose_from:
 173        fclose(from_fp);
 174out:
 175        return err;
 176}
 177
 178int copyfile_offset(int ifd, loff_t off_in, int ofd, loff_t off_out, u64 size)
 179{
 180        void *ptr;
 181        loff_t pgoff;
 182
 183        pgoff = off_in & ~(page_size - 1);
 184        off_in -= pgoff;
 185
 186        ptr = mmap(NULL, off_in + size, PROT_READ, MAP_PRIVATE, ifd, pgoff);
 187        if (ptr == MAP_FAILED)
 188                return -1;
 189
 190        while (size) {
 191                ssize_t ret = pwrite(ofd, ptr + off_in, size, off_out);
 192                if (ret < 0 && errno == EINTR)
 193                        continue;
 194                if (ret <= 0)
 195                        break;
 196
 197                size -= ret;
 198                off_in += ret;
 199                off_out -= ret;
 200        }
 201        munmap(ptr, off_in + size);
 202
 203        return size ? -1 : 0;
 204}
 205
 206static int copyfile_mode_ns(const char *from, const char *to, mode_t mode,
 207                            struct nsinfo *nsi)
 208{
 209        int fromfd, tofd;
 210        struct stat st;
 211        int err;
 212        char *tmp = NULL, *ptr = NULL;
 213        struct nscookie nsc;
 214
 215        nsinfo__mountns_enter(nsi, &nsc);
 216        err = stat(from, &st);
 217        nsinfo__mountns_exit(&nsc);
 218        if (err)
 219                goto out;
 220        err = -1;
 221
 222        /* extra 'x' at the end is to reserve space for '.' */
 223        if (asprintf(&tmp, "%s.XXXXXXx", to) < 0) {
 224                tmp = NULL;
 225                goto out;
 226        }
 227        ptr = strrchr(tmp, '/');
 228        if (!ptr)
 229                goto out;
 230        ptr = memmove(ptr + 1, ptr, strlen(ptr) - 1);
 231        *ptr = '.';
 232
 233        tofd = mkstemp(tmp);
 234        if (tofd < 0)
 235                goto out;
 236
 237        if (fchmod(tofd, mode))
 238                goto out_close_to;
 239
 240        if (st.st_size == 0) { /* /proc? do it slowly... */
 241                err = slow_copyfile(from, tmp, nsi);
 242                goto out_close_to;
 243        }
 244
 245        nsinfo__mountns_enter(nsi, &nsc);
 246        fromfd = open(from, O_RDONLY);
 247        nsinfo__mountns_exit(&nsc);
 248        if (fromfd < 0)
 249                goto out_close_to;
 250
 251        err = copyfile_offset(fromfd, 0, tofd, 0, st.st_size);
 252
 253        close(fromfd);
 254out_close_to:
 255        close(tofd);
 256        if (!err)
 257                err = link(tmp, to);
 258        unlink(tmp);
 259out:
 260        free(tmp);
 261        return err;
 262}
 263
 264int copyfile_ns(const char *from, const char *to, struct nsinfo *nsi)
 265{
 266        return copyfile_mode_ns(from, to, 0755, nsi);
 267}
 268
 269int copyfile_mode(const char *from, const char *to, mode_t mode)
 270{
 271        return copyfile_mode_ns(from, to, mode, NULL);
 272}
 273
 274int copyfile(const char *from, const char *to)
 275{
 276        return copyfile_mode(from, to, 0755);
 277}
 278
 279static ssize_t ion(bool is_read, int fd, void *buf, size_t n)
 280{
 281        void *buf_start = buf;
 282        size_t left = n;
 283
 284        while (left) {
 285                /* buf must be treated as const if !is_read. */
 286                ssize_t ret = is_read ? read(fd, buf, left) :
 287                                        write(fd, buf, left);
 288
 289                if (ret < 0 && errno == EINTR)
 290                        continue;
 291                if (ret <= 0)
 292                        return ret;
 293
 294                left -= ret;
 295                buf  += ret;
 296        }
 297
 298        BUG_ON((size_t)(buf - buf_start) != n);
 299        return n;
 300}
 301
 302/*
 303 * Read exactly 'n' bytes or return an error.
 304 */
 305ssize_t readn(int fd, void *buf, size_t n)
 306{
 307        return ion(true, fd, buf, n);
 308}
 309
 310/*
 311 * Write exactly 'n' bytes or return an error.
 312 */
 313ssize_t writen(int fd, const void *buf, size_t n)
 314{
 315        /* ion does not modify buf. */
 316        return ion(false, fd, (void *)buf, n);
 317}
 318
 319size_t hex_width(u64 v)
 320{
 321        size_t n = 1;
 322
 323        while ((v >>= 4))
 324                ++n;
 325
 326        return n;
 327}
 328
 329static int hex(char ch)
 330{
 331        if ((ch >= '0') && (ch <= '9'))
 332                return ch - '0';
 333        if ((ch >= 'a') && (ch <= 'f'))
 334                return ch - 'a' + 10;
 335        if ((ch >= 'A') && (ch <= 'F'))
 336                return ch - 'A' + 10;
 337        return -1;
 338}
 339
 340/*
 341 * While we find nice hex chars, build a long_val.
 342 * Return number of chars processed.
 343 */
 344int hex2u64(const char *ptr, u64 *long_val)
 345{
 346        const char *p = ptr;
 347        *long_val = 0;
 348
 349        while (*p) {
 350                const int hex_val = hex(*p);
 351
 352                if (hex_val < 0)
 353                        break;
 354
 355                *long_val = (*long_val << 4) | hex_val;
 356                p++;
 357        }
 358
 359        return p - ptr;
 360}
 361
 362int perf_event_paranoid(void)
 363{
 364        int value;
 365
 366        if (sysctl__read_int("kernel/perf_event_paranoid", &value))
 367                return INT_MAX;
 368
 369        return value;
 370}
 371static int
 372fetch_ubuntu_kernel_version(unsigned int *puint)
 373{
 374        ssize_t len;
 375        size_t line_len = 0;
 376        char *ptr, *line = NULL;
 377        int version, patchlevel, sublevel, err;
 378        FILE *vsig;
 379
 380        if (!puint)
 381                return 0;
 382
 383        vsig = fopen("/proc/version_signature", "r");
 384        if (!vsig) {
 385                pr_debug("Open /proc/version_signature failed: %s\n",
 386                         strerror(errno));
 387                return -1;
 388        }
 389
 390        len = getline(&line, &line_len, vsig);
 391        fclose(vsig);
 392        err = -1;
 393        if (len <= 0) {
 394                pr_debug("Reading from /proc/version_signature failed: %s\n",
 395                         strerror(errno));
 396                goto errout;
 397        }
 398
 399        ptr = strrchr(line, ' ');
 400        if (!ptr) {
 401                pr_debug("Parsing /proc/version_signature failed: %s\n", line);
 402                goto errout;
 403        }
 404
 405        err = sscanf(ptr + 1, "%d.%d.%d",
 406                     &version, &patchlevel, &sublevel);
 407        if (err != 3) {
 408                pr_debug("Unable to get kernel version from /proc/version_signature '%s'\n",
 409                         line);
 410                goto errout;
 411        }
 412
 413        *puint = (version << 16) + (patchlevel << 8) + sublevel;
 414        err = 0;
 415errout:
 416        free(line);
 417        return err;
 418}
 419
 420int
 421fetch_kernel_version(unsigned int *puint, char *str,
 422                     size_t str_size)
 423{
 424        struct utsname utsname;
 425        int version, patchlevel, sublevel, err;
 426        bool int_ver_ready = false;
 427
 428        if (access("/proc/version_signature", R_OK) == 0)
 429                if (!fetch_ubuntu_kernel_version(puint))
 430                        int_ver_ready = true;
 431
 432        if (uname(&utsname))
 433                return -1;
 434
 435        if (str && str_size) {
 436                strncpy(str, utsname.release, str_size);
 437                str[str_size - 1] = '\0';
 438        }
 439
 440        if (!puint || int_ver_ready)
 441                return 0;
 442
 443        err = sscanf(utsname.release, "%d.%d.%d",
 444                     &version, &patchlevel, &sublevel);
 445
 446        if (err != 3) {
 447                pr_debug("Unable to get kernel version from uname '%s'\n",
 448                         utsname.release);
 449                return -1;
 450        }
 451
 452        *puint = (version << 16) + (patchlevel << 8) + sublevel;
 453        return 0;
 454}
 455
 456const char *perf_tip(const char *dirpath)
 457{
 458        struct strlist *tips;
 459        struct str_node *node;
 460        char *tip = NULL;
 461        struct strlist_config conf = {
 462                .dirname = dirpath,
 463                .file_only = true,
 464        };
 465
 466        tips = strlist__new("tips.txt", &conf);
 467        if (tips == NULL)
 468                return errno == ENOENT ? NULL :
 469                        "Tip: check path of tips.txt or get more memory! ;-p";
 470
 471        if (strlist__nr_entries(tips) == 0)
 472                goto out;
 473
 474        node = strlist__entry(tips, random() % strlist__nr_entries(tips));
 475        if (asprintf(&tip, "Tip: %s", node->s) < 0)
 476                tip = (char *)"Tip: get more memory! ;-)";
 477
 478out:
 479        strlist__delete(tips);
 480
 481        return tip;
 482}
 483