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