root/tools/perf/util/util.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. perf_set_singlethreaded
  2. perf_set_multithreaded
  3. sysctl__max_stack
  4. event_attr_init
  5. mkdir_p
  6. match_pat
  7. rm_rf_depth_pat
  8. rm_rf_perf_data
  9. rm_rf
  10. lsdir_no_dot_filter
  11. lsdir
  12. hex_width
  13. perf_event_paranoid
  14. perf_event_paranoid_check
  15. fetch_ubuntu_kernel_version
  16. fetch_kernel_version
  17. perf_tip
  18. perf_exe

   1 // SPDX-License-Identifier: GPL-2.0
   2 #include "util.h"
   3 #include "debug.h"
   4 #include "event.h"
   5 #include <api/fs/fs.h>
   6 #include <sys/stat.h>
   7 #include <sys/utsname.h>
   8 #include <dirent.h>
   9 #include <fcntl.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/capability.h>
  18 #include <linux/kernel.h>
  19 #include <linux/log2.h>
  20 #include <linux/time64.h>
  21 #include <unistd.h>
  22 #include "cap.h"
  23 #include "strlist.h"
  24 #include "string2.h"
  25 
  26 /*
  27  * XXX We need to find a better place for these things...
  28  */
  29 
  30 bool perf_singlethreaded = true;
  31 
  32 void perf_set_singlethreaded(void)
  33 {
  34         perf_singlethreaded = true;
  35 }
  36 
  37 void perf_set_multithreaded(void)
  38 {
  39         perf_singlethreaded = false;
  40 }
  41 
  42 int sysctl_perf_event_max_stack = PERF_MAX_STACK_DEPTH;
  43 int sysctl_perf_event_max_contexts_per_stack = PERF_MAX_CONTEXTS_PER_STACK;
  44 
  45 int sysctl__max_stack(void)
  46 {
  47         int value;
  48 
  49         if (sysctl__read_int("kernel/perf_event_max_stack", &value) == 0)
  50                 sysctl_perf_event_max_stack = value;
  51 
  52         if (sysctl__read_int("kernel/perf_event_max_contexts_per_stack", &value) == 0)
  53                 sysctl_perf_event_max_contexts_per_stack = value;
  54 
  55         return sysctl_perf_event_max_stack;
  56 }
  57 
  58 bool test_attr__enabled;
  59 
  60 bool perf_host  = true;
  61 bool perf_guest = false;
  62 
  63 void event_attr_init(struct perf_event_attr *attr)
  64 {
  65         if (!perf_host)
  66                 attr->exclude_host  = 1;
  67         if (!perf_guest)
  68                 attr->exclude_guest = 1;
  69         /* to capture ABI version */
  70         attr->size = sizeof(*attr);
  71 }
  72 
  73 int mkdir_p(char *path, mode_t mode)
  74 {
  75         struct stat st;
  76         int err;
  77         char *d = path;
  78 
  79         if (*d != '/')
  80                 return -1;
  81 
  82         if (stat(path, &st) == 0)
  83                 return 0;
  84 
  85         while (*++d == '/');
  86 
  87         while ((d = strchr(d, '/'))) {
  88                 *d = '\0';
  89                 err = stat(path, &st) && mkdir(path, mode);
  90                 *d++ = '/';
  91                 if (err)
  92                         return -1;
  93                 while (*d == '/')
  94                         ++d;
  95         }
  96         return (stat(path, &st) && mkdir(path, mode)) ? -1 : 0;
  97 }
  98 
  99 static bool match_pat(char *file, const char **pat)
 100 {
 101         int i = 0;
 102 
 103         if (!pat)
 104                 return true;
 105 
 106         while (pat[i]) {
 107                 if (strglobmatch(file, pat[i]))
 108                         return true;
 109 
 110                 i++;
 111         }
 112 
 113         return false;
 114 }
 115 
 116 /*
 117  * The depth specify how deep the removal will go.
 118  * 0       - will remove only files under the 'path' directory
 119  * 1 .. x  - will dive in x-level deep under the 'path' directory
 120  *
 121  * If specified the pat is array of string patterns ended with NULL,
 122  * which are checked upon every file/directory found. Only matching
 123  * ones are removed.
 124  *
 125  * The function returns:
 126  *    0 on success
 127  *   -1 on removal failure with errno set
 128  *   -2 on pattern failure
 129  */
 130 static int rm_rf_depth_pat(const char *path, int depth, const char **pat)
 131 {
 132         DIR *dir;
 133         int ret;
 134         struct dirent *d;
 135         char namebuf[PATH_MAX];
 136         struct stat statbuf;
 137 
 138         /* Do not fail if there's no file. */
 139         ret = lstat(path, &statbuf);
 140         if (ret)
 141                 return 0;
 142 
 143         /* Try to remove any file we get. */
 144         if (!(statbuf.st_mode & S_IFDIR))
 145                 return unlink(path);
 146 
 147         /* We have directory in path. */
 148         dir = opendir(path);
 149         if (dir == NULL)
 150                 return -1;
 151 
 152         while ((d = readdir(dir)) != NULL && !ret) {
 153 
 154                 if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
 155                         continue;
 156 
 157                 if (!match_pat(d->d_name, pat)) {
 158                         ret =  -2;
 159                         break;
 160                 }
 161 
 162                 scnprintf(namebuf, sizeof(namebuf), "%s/%s",
 163                           path, d->d_name);
 164 
 165                 /* We have to check symbolic link itself */
 166                 ret = lstat(namebuf, &statbuf);
 167                 if (ret < 0) {
 168                         pr_debug("stat failed: %s\n", namebuf);
 169                         break;
 170                 }
 171 
 172                 if (S_ISDIR(statbuf.st_mode))
 173                         ret = depth ? rm_rf_depth_pat(namebuf, depth - 1, pat) : 0;
 174                 else
 175                         ret = unlink(namebuf);
 176         }
 177         closedir(dir);
 178 
 179         if (ret < 0)
 180                 return ret;
 181 
 182         return rmdir(path);
 183 }
 184 
 185 int rm_rf_perf_data(const char *path)
 186 {
 187         const char *pat[] = {
 188                 "header",
 189                 "data.*",
 190                 NULL,
 191         };
 192 
 193         return rm_rf_depth_pat(path, 0, pat);
 194 }
 195 
 196 int rm_rf(const char *path)
 197 {
 198         return rm_rf_depth_pat(path, INT_MAX, NULL);
 199 }
 200 
 201 /* A filter which removes dot files */
 202 bool lsdir_no_dot_filter(const char *name __maybe_unused, struct dirent *d)
 203 {
 204         return d->d_name[0] != '.';
 205 }
 206 
 207 /* lsdir reads a directory and store it in strlist */
 208 struct strlist *lsdir(const char *name,
 209                       bool (*filter)(const char *, struct dirent *))
 210 {
 211         struct strlist *list = NULL;
 212         DIR *dir;
 213         struct dirent *d;
 214 
 215         dir = opendir(name);
 216         if (!dir)
 217                 return NULL;
 218 
 219         list = strlist__new(NULL, NULL);
 220         if (!list) {
 221                 errno = ENOMEM;
 222                 goto out;
 223         }
 224 
 225         while ((d = readdir(dir)) != NULL) {
 226                 if (!filter || filter(name, d))
 227                         strlist__add(list, d->d_name);
 228         }
 229 
 230 out:
 231         closedir(dir);
 232         return list;
 233 }
 234 
 235 size_t hex_width(u64 v)
 236 {
 237         size_t n = 1;
 238 
 239         while ((v >>= 4))
 240                 ++n;
 241 
 242         return n;
 243 }
 244 
 245 int perf_event_paranoid(void)
 246 {
 247         int value;
 248 
 249         if (sysctl__read_int("kernel/perf_event_paranoid", &value))
 250                 return INT_MAX;
 251 
 252         return value;
 253 }
 254 
 255 bool perf_event_paranoid_check(int max_level)
 256 {
 257         return perf_cap__capable(CAP_SYS_ADMIN) ||
 258                         perf_event_paranoid() <= max_level;
 259 }
 260 
 261 static int
 262 fetch_ubuntu_kernel_version(unsigned int *puint)
 263 {
 264         ssize_t len;
 265         size_t line_len = 0;
 266         char *ptr, *line = NULL;
 267         int version, patchlevel, sublevel, err;
 268         FILE *vsig;
 269 
 270         if (!puint)
 271                 return 0;
 272 
 273         vsig = fopen("/proc/version_signature", "r");
 274         if (!vsig) {
 275                 pr_debug("Open /proc/version_signature failed: %s\n",
 276                          strerror(errno));
 277                 return -1;
 278         }
 279 
 280         len = getline(&line, &line_len, vsig);
 281         fclose(vsig);
 282         err = -1;
 283         if (len <= 0) {
 284                 pr_debug("Reading from /proc/version_signature failed: %s\n",
 285                          strerror(errno));
 286                 goto errout;
 287         }
 288 
 289         ptr = strrchr(line, ' ');
 290         if (!ptr) {
 291                 pr_debug("Parsing /proc/version_signature failed: %s\n", line);
 292                 goto errout;
 293         }
 294 
 295         err = sscanf(ptr + 1, "%d.%d.%d",
 296                      &version, &patchlevel, &sublevel);
 297         if (err != 3) {
 298                 pr_debug("Unable to get kernel version from /proc/version_signature '%s'\n",
 299                          line);
 300                 goto errout;
 301         }
 302 
 303         *puint = (version << 16) + (patchlevel << 8) + sublevel;
 304         err = 0;
 305 errout:
 306         free(line);
 307         return err;
 308 }
 309 
 310 int
 311 fetch_kernel_version(unsigned int *puint, char *str,
 312                      size_t str_size)
 313 {
 314         struct utsname utsname;
 315         int version, patchlevel, sublevel, err;
 316         bool int_ver_ready = false;
 317 
 318         if (access("/proc/version_signature", R_OK) == 0)
 319                 if (!fetch_ubuntu_kernel_version(puint))
 320                         int_ver_ready = true;
 321 
 322         if (uname(&utsname))
 323                 return -1;
 324 
 325         if (str && str_size) {
 326                 strncpy(str, utsname.release, str_size);
 327                 str[str_size - 1] = '\0';
 328         }
 329 
 330         if (!puint || int_ver_ready)
 331                 return 0;
 332 
 333         err = sscanf(utsname.release, "%d.%d.%d",
 334                      &version, &patchlevel, &sublevel);
 335 
 336         if (err != 3) {
 337                 pr_debug("Unable to get kernel version from uname '%s'\n",
 338                          utsname.release);
 339                 return -1;
 340         }
 341 
 342         *puint = (version << 16) + (patchlevel << 8) + sublevel;
 343         return 0;
 344 }
 345 
 346 const char *perf_tip(const char *dirpath)
 347 {
 348         struct strlist *tips;
 349         struct str_node *node;
 350         char *tip = NULL;
 351         struct strlist_config conf = {
 352                 .dirname = dirpath,
 353                 .file_only = true,
 354         };
 355 
 356         tips = strlist__new("tips.txt", &conf);
 357         if (tips == NULL)
 358                 return errno == ENOENT ? NULL :
 359                         "Tip: check path of tips.txt or get more memory! ;-p";
 360 
 361         if (strlist__nr_entries(tips) == 0)
 362                 goto out;
 363 
 364         node = strlist__entry(tips, random() % strlist__nr_entries(tips));
 365         if (asprintf(&tip, "Tip: %s", node->s) < 0)
 366                 tip = (char *)"Tip: get more memory! ;-)";
 367 
 368 out:
 369         strlist__delete(tips);
 370 
 371         return tip;
 372 }
 373 
 374 char *perf_exe(char *buf, int len)
 375 {
 376         int n = readlink("/proc/self/exe", buf, len);
 377         if (n > 0) {
 378                 buf[n] = 0;
 379                 return buf;
 380         }
 381         return strcpy(buf, "perf");
 382 }

/* [<][>][^][v][top][bottom][index][help] */