162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci#include "util.h" 362306a36Sopenharmony_ci#include "debug.h" 462306a36Sopenharmony_ci#include "event.h" 562306a36Sopenharmony_ci#include <api/fs/fs.h> 662306a36Sopenharmony_ci#include <sys/stat.h> 762306a36Sopenharmony_ci#include <sys/utsname.h> 862306a36Sopenharmony_ci#include <dirent.h> 962306a36Sopenharmony_ci#include <fcntl.h> 1062306a36Sopenharmony_ci#include <inttypes.h> 1162306a36Sopenharmony_ci#include <signal.h> 1262306a36Sopenharmony_ci#include <stdio.h> 1362306a36Sopenharmony_ci#include <stdlib.h> 1462306a36Sopenharmony_ci#include <string.h> 1562306a36Sopenharmony_ci#include <errno.h> 1662306a36Sopenharmony_ci#include <limits.h> 1762306a36Sopenharmony_ci#include <linux/capability.h> 1862306a36Sopenharmony_ci#include <linux/kernel.h> 1962306a36Sopenharmony_ci#include <linux/log2.h> 2062306a36Sopenharmony_ci#include <linux/time64.h> 2162306a36Sopenharmony_ci#include <linux/overflow.h> 2262306a36Sopenharmony_ci#include <unistd.h> 2362306a36Sopenharmony_ci#include "cap.h" 2462306a36Sopenharmony_ci#include "strlist.h" 2562306a36Sopenharmony_ci#include "string2.h" 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci/* 2862306a36Sopenharmony_ci * XXX We need to find a better place for these things... 2962306a36Sopenharmony_ci */ 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ciconst char *input_name; 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_cibool perf_singlethreaded = true; 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_civoid perf_set_singlethreaded(void) 3662306a36Sopenharmony_ci{ 3762306a36Sopenharmony_ci perf_singlethreaded = true; 3862306a36Sopenharmony_ci} 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_civoid perf_set_multithreaded(void) 4162306a36Sopenharmony_ci{ 4262306a36Sopenharmony_ci perf_singlethreaded = false; 4362306a36Sopenharmony_ci} 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ciint sysctl_perf_event_max_stack = PERF_MAX_STACK_DEPTH; 4662306a36Sopenharmony_ciint sysctl_perf_event_max_contexts_per_stack = PERF_MAX_CONTEXTS_PER_STACK; 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ciint sysctl__max_stack(void) 4962306a36Sopenharmony_ci{ 5062306a36Sopenharmony_ci int value; 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci if (sysctl__read_int("kernel/perf_event_max_stack", &value) == 0) 5362306a36Sopenharmony_ci sysctl_perf_event_max_stack = value; 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci if (sysctl__read_int("kernel/perf_event_max_contexts_per_stack", &value) == 0) 5662306a36Sopenharmony_ci sysctl_perf_event_max_contexts_per_stack = value; 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci return sysctl_perf_event_max_stack; 5962306a36Sopenharmony_ci} 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_cibool sysctl__nmi_watchdog_enabled(void) 6262306a36Sopenharmony_ci{ 6362306a36Sopenharmony_ci static bool cached; 6462306a36Sopenharmony_ci static bool nmi_watchdog; 6562306a36Sopenharmony_ci int value; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci if (cached) 6862306a36Sopenharmony_ci return nmi_watchdog; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci if (sysctl__read_int("kernel/nmi_watchdog", &value) < 0) 7162306a36Sopenharmony_ci return false; 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci nmi_watchdog = (value > 0) ? true : false; 7462306a36Sopenharmony_ci cached = true; 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci return nmi_watchdog; 7762306a36Sopenharmony_ci} 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_cibool test_attr__enabled; 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_cibool perf_host = true; 8262306a36Sopenharmony_cibool perf_guest = false; 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_civoid event_attr_init(struct perf_event_attr *attr) 8562306a36Sopenharmony_ci{ 8662306a36Sopenharmony_ci if (!perf_host) 8762306a36Sopenharmony_ci attr->exclude_host = 1; 8862306a36Sopenharmony_ci if (!perf_guest) 8962306a36Sopenharmony_ci attr->exclude_guest = 1; 9062306a36Sopenharmony_ci /* to capture ABI version */ 9162306a36Sopenharmony_ci attr->size = sizeof(*attr); 9262306a36Sopenharmony_ci} 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ciint mkdir_p(char *path, mode_t mode) 9562306a36Sopenharmony_ci{ 9662306a36Sopenharmony_ci struct stat st; 9762306a36Sopenharmony_ci int err; 9862306a36Sopenharmony_ci char *d = path; 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci if (*d != '/') 10162306a36Sopenharmony_ci return -1; 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci if (stat(path, &st) == 0) 10462306a36Sopenharmony_ci return 0; 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci while (*++d == '/'); 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci while ((d = strchr(d, '/'))) { 10962306a36Sopenharmony_ci *d = '\0'; 11062306a36Sopenharmony_ci err = stat(path, &st) && mkdir(path, mode); 11162306a36Sopenharmony_ci *d++ = '/'; 11262306a36Sopenharmony_ci if (err) 11362306a36Sopenharmony_ci return -1; 11462306a36Sopenharmony_ci while (*d == '/') 11562306a36Sopenharmony_ci ++d; 11662306a36Sopenharmony_ci } 11762306a36Sopenharmony_ci return (stat(path, &st) && mkdir(path, mode)) ? -1 : 0; 11862306a36Sopenharmony_ci} 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_cistatic bool match_pat(char *file, const char **pat) 12162306a36Sopenharmony_ci{ 12262306a36Sopenharmony_ci int i = 0; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci if (!pat) 12562306a36Sopenharmony_ci return true; 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci while (pat[i]) { 12862306a36Sopenharmony_ci if (strglobmatch(file, pat[i])) 12962306a36Sopenharmony_ci return true; 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci i++; 13262306a36Sopenharmony_ci } 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci return false; 13562306a36Sopenharmony_ci} 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci/* 13862306a36Sopenharmony_ci * The depth specify how deep the removal will go. 13962306a36Sopenharmony_ci * 0 - will remove only files under the 'path' directory 14062306a36Sopenharmony_ci * 1 .. x - will dive in x-level deep under the 'path' directory 14162306a36Sopenharmony_ci * 14262306a36Sopenharmony_ci * If specified the pat is array of string patterns ended with NULL, 14362306a36Sopenharmony_ci * which are checked upon every file/directory found. Only matching 14462306a36Sopenharmony_ci * ones are removed. 14562306a36Sopenharmony_ci * 14662306a36Sopenharmony_ci * The function returns: 14762306a36Sopenharmony_ci * 0 on success 14862306a36Sopenharmony_ci * -1 on removal failure with errno set 14962306a36Sopenharmony_ci * -2 on pattern failure 15062306a36Sopenharmony_ci */ 15162306a36Sopenharmony_cistatic int rm_rf_depth_pat(const char *path, int depth, const char **pat) 15262306a36Sopenharmony_ci{ 15362306a36Sopenharmony_ci DIR *dir; 15462306a36Sopenharmony_ci int ret; 15562306a36Sopenharmony_ci struct dirent *d; 15662306a36Sopenharmony_ci char namebuf[PATH_MAX]; 15762306a36Sopenharmony_ci struct stat statbuf; 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci /* Do not fail if there's no file. */ 16062306a36Sopenharmony_ci ret = lstat(path, &statbuf); 16162306a36Sopenharmony_ci if (ret) 16262306a36Sopenharmony_ci return 0; 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci /* Try to remove any file we get. */ 16562306a36Sopenharmony_ci if (!(statbuf.st_mode & S_IFDIR)) 16662306a36Sopenharmony_ci return unlink(path); 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci /* We have directory in path. */ 16962306a36Sopenharmony_ci dir = opendir(path); 17062306a36Sopenharmony_ci if (dir == NULL) 17162306a36Sopenharmony_ci return -1; 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci while ((d = readdir(dir)) != NULL && !ret) { 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, "..")) 17662306a36Sopenharmony_ci continue; 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci if (!match_pat(d->d_name, pat)) { 17962306a36Sopenharmony_ci ret = -2; 18062306a36Sopenharmony_ci break; 18162306a36Sopenharmony_ci } 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci scnprintf(namebuf, sizeof(namebuf), "%s/%s", 18462306a36Sopenharmony_ci path, d->d_name); 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci /* We have to check symbolic link itself */ 18762306a36Sopenharmony_ci ret = lstat(namebuf, &statbuf); 18862306a36Sopenharmony_ci if (ret < 0) { 18962306a36Sopenharmony_ci pr_debug("stat failed: %s\n", namebuf); 19062306a36Sopenharmony_ci break; 19162306a36Sopenharmony_ci } 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci if (S_ISDIR(statbuf.st_mode)) 19462306a36Sopenharmony_ci ret = depth ? rm_rf_depth_pat(namebuf, depth - 1, pat) : 0; 19562306a36Sopenharmony_ci else 19662306a36Sopenharmony_ci ret = unlink(namebuf); 19762306a36Sopenharmony_ci } 19862306a36Sopenharmony_ci closedir(dir); 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci if (ret < 0) 20162306a36Sopenharmony_ci return ret; 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci return rmdir(path); 20462306a36Sopenharmony_ci} 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_cistatic int rm_rf_a_kcore_dir(const char *path, const char *name) 20762306a36Sopenharmony_ci{ 20862306a36Sopenharmony_ci char kcore_dir_path[PATH_MAX]; 20962306a36Sopenharmony_ci const char *pat[] = { 21062306a36Sopenharmony_ci "kcore", 21162306a36Sopenharmony_ci "kallsyms", 21262306a36Sopenharmony_ci "modules", 21362306a36Sopenharmony_ci NULL, 21462306a36Sopenharmony_ci }; 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci snprintf(kcore_dir_path, sizeof(kcore_dir_path), "%s/%s", path, name); 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci return rm_rf_depth_pat(kcore_dir_path, 0, pat); 21962306a36Sopenharmony_ci} 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_cistatic bool kcore_dir_filter(const char *name __maybe_unused, struct dirent *d) 22262306a36Sopenharmony_ci{ 22362306a36Sopenharmony_ci const char *pat[] = { 22462306a36Sopenharmony_ci "kcore_dir", 22562306a36Sopenharmony_ci "kcore_dir__[1-9]*", 22662306a36Sopenharmony_ci NULL, 22762306a36Sopenharmony_ci }; 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci return match_pat(d->d_name, pat); 23062306a36Sopenharmony_ci} 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_cistatic int rm_rf_kcore_dir(const char *path) 23362306a36Sopenharmony_ci{ 23462306a36Sopenharmony_ci struct strlist *kcore_dirs; 23562306a36Sopenharmony_ci struct str_node *nd; 23662306a36Sopenharmony_ci int ret; 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci kcore_dirs = lsdir(path, kcore_dir_filter); 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci if (!kcore_dirs) 24162306a36Sopenharmony_ci return 0; 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci strlist__for_each_entry(nd, kcore_dirs) { 24462306a36Sopenharmony_ci ret = rm_rf_a_kcore_dir(path, nd->s); 24562306a36Sopenharmony_ci if (ret) 24662306a36Sopenharmony_ci return ret; 24762306a36Sopenharmony_ci } 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci strlist__delete(kcore_dirs); 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci return 0; 25262306a36Sopenharmony_ci} 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ciint rm_rf_perf_data(const char *path) 25562306a36Sopenharmony_ci{ 25662306a36Sopenharmony_ci const char *pat[] = { 25762306a36Sopenharmony_ci "data", 25862306a36Sopenharmony_ci "data.*", 25962306a36Sopenharmony_ci NULL, 26062306a36Sopenharmony_ci }; 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci rm_rf_kcore_dir(path); 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci return rm_rf_depth_pat(path, 0, pat); 26562306a36Sopenharmony_ci} 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ciint rm_rf(const char *path) 26862306a36Sopenharmony_ci{ 26962306a36Sopenharmony_ci return rm_rf_depth_pat(path, INT_MAX, NULL); 27062306a36Sopenharmony_ci} 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci/* A filter which removes dot files */ 27362306a36Sopenharmony_cibool lsdir_no_dot_filter(const char *name __maybe_unused, struct dirent *d) 27462306a36Sopenharmony_ci{ 27562306a36Sopenharmony_ci return d->d_name[0] != '.'; 27662306a36Sopenharmony_ci} 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci/* lsdir reads a directory and store it in strlist */ 27962306a36Sopenharmony_cistruct strlist *lsdir(const char *name, 28062306a36Sopenharmony_ci bool (*filter)(const char *, struct dirent *)) 28162306a36Sopenharmony_ci{ 28262306a36Sopenharmony_ci struct strlist *list = NULL; 28362306a36Sopenharmony_ci DIR *dir; 28462306a36Sopenharmony_ci struct dirent *d; 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci dir = opendir(name); 28762306a36Sopenharmony_ci if (!dir) 28862306a36Sopenharmony_ci return NULL; 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci list = strlist__new(NULL, NULL); 29162306a36Sopenharmony_ci if (!list) { 29262306a36Sopenharmony_ci errno = ENOMEM; 29362306a36Sopenharmony_ci goto out; 29462306a36Sopenharmony_ci } 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci while ((d = readdir(dir)) != NULL) { 29762306a36Sopenharmony_ci if (!filter || filter(name, d)) 29862306a36Sopenharmony_ci strlist__add(list, d->d_name); 29962306a36Sopenharmony_ci } 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ciout: 30262306a36Sopenharmony_ci closedir(dir); 30362306a36Sopenharmony_ci return list; 30462306a36Sopenharmony_ci} 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_cisize_t hex_width(u64 v) 30762306a36Sopenharmony_ci{ 30862306a36Sopenharmony_ci size_t n = 1; 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci while ((v >>= 4)) 31162306a36Sopenharmony_ci ++n; 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci return n; 31462306a36Sopenharmony_ci} 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ciint perf_event_paranoid(void) 31762306a36Sopenharmony_ci{ 31862306a36Sopenharmony_ci int value; 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci if (sysctl__read_int("kernel/perf_event_paranoid", &value)) 32162306a36Sopenharmony_ci return INT_MAX; 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci return value; 32462306a36Sopenharmony_ci} 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_cibool perf_event_paranoid_check(int max_level) 32762306a36Sopenharmony_ci{ 32862306a36Sopenharmony_ci return perf_cap__capable(CAP_SYS_ADMIN) || 32962306a36Sopenharmony_ci perf_cap__capable(CAP_PERFMON) || 33062306a36Sopenharmony_ci perf_event_paranoid() <= max_level; 33162306a36Sopenharmony_ci} 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_cistatic int 33462306a36Sopenharmony_cifetch_ubuntu_kernel_version(unsigned int *puint) 33562306a36Sopenharmony_ci{ 33662306a36Sopenharmony_ci ssize_t len; 33762306a36Sopenharmony_ci size_t line_len = 0; 33862306a36Sopenharmony_ci char *ptr, *line = NULL; 33962306a36Sopenharmony_ci int version, patchlevel, sublevel, err; 34062306a36Sopenharmony_ci FILE *vsig; 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci if (!puint) 34362306a36Sopenharmony_ci return 0; 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci vsig = fopen("/proc/version_signature", "r"); 34662306a36Sopenharmony_ci if (!vsig) { 34762306a36Sopenharmony_ci pr_debug("Open /proc/version_signature failed: %s\n", 34862306a36Sopenharmony_ci strerror(errno)); 34962306a36Sopenharmony_ci return -1; 35062306a36Sopenharmony_ci } 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci len = getline(&line, &line_len, vsig); 35362306a36Sopenharmony_ci fclose(vsig); 35462306a36Sopenharmony_ci err = -1; 35562306a36Sopenharmony_ci if (len <= 0) { 35662306a36Sopenharmony_ci pr_debug("Reading from /proc/version_signature failed: %s\n", 35762306a36Sopenharmony_ci strerror(errno)); 35862306a36Sopenharmony_ci goto errout; 35962306a36Sopenharmony_ci } 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci ptr = strrchr(line, ' '); 36262306a36Sopenharmony_ci if (!ptr) { 36362306a36Sopenharmony_ci pr_debug("Parsing /proc/version_signature failed: %s\n", line); 36462306a36Sopenharmony_ci goto errout; 36562306a36Sopenharmony_ci } 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci err = sscanf(ptr + 1, "%d.%d.%d", 36862306a36Sopenharmony_ci &version, &patchlevel, &sublevel); 36962306a36Sopenharmony_ci if (err != 3) { 37062306a36Sopenharmony_ci pr_debug("Unable to get kernel version from /proc/version_signature '%s'\n", 37162306a36Sopenharmony_ci line); 37262306a36Sopenharmony_ci goto errout; 37362306a36Sopenharmony_ci } 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci *puint = (version << 16) + (patchlevel << 8) + sublevel; 37662306a36Sopenharmony_ci err = 0; 37762306a36Sopenharmony_cierrout: 37862306a36Sopenharmony_ci free(line); 37962306a36Sopenharmony_ci return err; 38062306a36Sopenharmony_ci} 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ciint 38362306a36Sopenharmony_cifetch_kernel_version(unsigned int *puint, char *str, 38462306a36Sopenharmony_ci size_t str_size) 38562306a36Sopenharmony_ci{ 38662306a36Sopenharmony_ci struct utsname utsname; 38762306a36Sopenharmony_ci int version, patchlevel, sublevel, err; 38862306a36Sopenharmony_ci bool int_ver_ready = false; 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci if (access("/proc/version_signature", R_OK) == 0) 39162306a36Sopenharmony_ci if (!fetch_ubuntu_kernel_version(puint)) 39262306a36Sopenharmony_ci int_ver_ready = true; 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci if (uname(&utsname)) 39562306a36Sopenharmony_ci return -1; 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci if (str && str_size) { 39862306a36Sopenharmony_ci strncpy(str, utsname.release, str_size); 39962306a36Sopenharmony_ci str[str_size - 1] = '\0'; 40062306a36Sopenharmony_ci } 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci if (!puint || int_ver_ready) 40362306a36Sopenharmony_ci return 0; 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci err = sscanf(utsname.release, "%d.%d.%d", 40662306a36Sopenharmony_ci &version, &patchlevel, &sublevel); 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci if (err != 3) { 40962306a36Sopenharmony_ci pr_debug("Unable to get kernel version from uname '%s'\n", 41062306a36Sopenharmony_ci utsname.release); 41162306a36Sopenharmony_ci return -1; 41262306a36Sopenharmony_ci } 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci *puint = (version << 16) + (patchlevel << 8) + sublevel; 41562306a36Sopenharmony_ci return 0; 41662306a36Sopenharmony_ci} 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ciint perf_tip(char **strp, const char *dirpath) 41962306a36Sopenharmony_ci{ 42062306a36Sopenharmony_ci struct strlist *tips; 42162306a36Sopenharmony_ci struct str_node *node; 42262306a36Sopenharmony_ci struct strlist_config conf = { 42362306a36Sopenharmony_ci .dirname = dirpath, 42462306a36Sopenharmony_ci .file_only = true, 42562306a36Sopenharmony_ci }; 42662306a36Sopenharmony_ci int ret = 0; 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci *strp = NULL; 42962306a36Sopenharmony_ci tips = strlist__new("tips.txt", &conf); 43062306a36Sopenharmony_ci if (tips == NULL) 43162306a36Sopenharmony_ci return -errno; 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci if (strlist__nr_entries(tips) == 0) 43462306a36Sopenharmony_ci goto out; 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci node = strlist__entry(tips, random() % strlist__nr_entries(tips)); 43762306a36Sopenharmony_ci if (asprintf(strp, "Tip: %s", node->s) < 0) 43862306a36Sopenharmony_ci ret = -ENOMEM; 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ciout: 44162306a36Sopenharmony_ci strlist__delete(tips); 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci return ret; 44462306a36Sopenharmony_ci} 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_cichar *perf_exe(char *buf, int len) 44762306a36Sopenharmony_ci{ 44862306a36Sopenharmony_ci int n = readlink("/proc/self/exe", buf, len); 44962306a36Sopenharmony_ci if (n > 0) { 45062306a36Sopenharmony_ci buf[n] = 0; 45162306a36Sopenharmony_ci return buf; 45262306a36Sopenharmony_ci } 45362306a36Sopenharmony_ci return strcpy(buf, "perf"); 45462306a36Sopenharmony_ci} 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_civoid perf_debuginfod_setup(struct perf_debuginfod *di) 45762306a36Sopenharmony_ci{ 45862306a36Sopenharmony_ci /* 45962306a36Sopenharmony_ci * By default '!di->set' we clear DEBUGINFOD_URLS, so debuginfod 46062306a36Sopenharmony_ci * processing is not triggered, otherwise we set it to 'di->urls' 46162306a36Sopenharmony_ci * value. If 'di->urls' is "system" we keep DEBUGINFOD_URLS value. 46262306a36Sopenharmony_ci */ 46362306a36Sopenharmony_ci if (!di->set) 46462306a36Sopenharmony_ci setenv("DEBUGINFOD_URLS", "", 1); 46562306a36Sopenharmony_ci else if (di->urls && strcmp(di->urls, "system")) 46662306a36Sopenharmony_ci setenv("DEBUGINFOD_URLS", di->urls, 1); 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci pr_debug("DEBUGINFOD_URLS=%s\n", getenv("DEBUGINFOD_URLS")); 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci#ifndef HAVE_DEBUGINFOD_SUPPORT 47162306a36Sopenharmony_ci if (di->set) 47262306a36Sopenharmony_ci pr_warning("WARNING: debuginfod support requested, but perf is not built with it\n"); 47362306a36Sopenharmony_ci#endif 47462306a36Sopenharmony_ci} 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci/* 47762306a36Sopenharmony_ci * Return a new filename prepended with task's root directory if it's in 47862306a36Sopenharmony_ci * a chroot. Callers should free the returned string. 47962306a36Sopenharmony_ci */ 48062306a36Sopenharmony_cichar *filename_with_chroot(int pid, const char *filename) 48162306a36Sopenharmony_ci{ 48262306a36Sopenharmony_ci char buf[PATH_MAX]; 48362306a36Sopenharmony_ci char proc_root[32]; 48462306a36Sopenharmony_ci char *new_name = NULL; 48562306a36Sopenharmony_ci int ret; 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci scnprintf(proc_root, sizeof(proc_root), "/proc/%d/root", pid); 48862306a36Sopenharmony_ci ret = readlink(proc_root, buf, sizeof(buf) - 1); 48962306a36Sopenharmony_ci if (ret <= 0) 49062306a36Sopenharmony_ci return NULL; 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci /* readlink(2) does not append a null byte to buf */ 49362306a36Sopenharmony_ci buf[ret] = '\0'; 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci if (!strcmp(buf, "/")) 49662306a36Sopenharmony_ci return NULL; 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci if (strstr(buf, "(deleted)")) 49962306a36Sopenharmony_ci return NULL; 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci if (asprintf(&new_name, "%s/%s", buf, filename) < 0) 50262306a36Sopenharmony_ci return NULL; 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci return new_name; 50562306a36Sopenharmony_ci} 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci/* 50862306a36Sopenharmony_ci * Reallocate an array *arr of size *arr_sz so that it is big enough to contain 50962306a36Sopenharmony_ci * x elements of size msz, initializing new entries to *init_val or zero if 51062306a36Sopenharmony_ci * init_val is NULL 51162306a36Sopenharmony_ci */ 51262306a36Sopenharmony_ciint do_realloc_array_as_needed(void **arr, size_t *arr_sz, size_t x, size_t msz, const void *init_val) 51362306a36Sopenharmony_ci{ 51462306a36Sopenharmony_ci size_t new_sz = *arr_sz; 51562306a36Sopenharmony_ci void *new_arr; 51662306a36Sopenharmony_ci size_t i; 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci if (!new_sz) 51962306a36Sopenharmony_ci new_sz = msz >= 64 ? 1 : roundup(64, msz); /* Start with at least 64 bytes */ 52062306a36Sopenharmony_ci while (x >= new_sz) { 52162306a36Sopenharmony_ci if (check_mul_overflow(new_sz, (size_t)2, &new_sz)) 52262306a36Sopenharmony_ci return -ENOMEM; 52362306a36Sopenharmony_ci } 52462306a36Sopenharmony_ci if (new_sz == *arr_sz) 52562306a36Sopenharmony_ci return 0; 52662306a36Sopenharmony_ci new_arr = calloc(new_sz, msz); 52762306a36Sopenharmony_ci if (!new_arr) 52862306a36Sopenharmony_ci return -ENOMEM; 52962306a36Sopenharmony_ci if (*arr_sz) 53062306a36Sopenharmony_ci memcpy(new_arr, *arr, *arr_sz * msz); 53162306a36Sopenharmony_ci if (init_val) { 53262306a36Sopenharmony_ci for (i = *arr_sz; i < new_sz; i++) 53362306a36Sopenharmony_ci memcpy(new_arr + (i * msz), init_val, msz); 53462306a36Sopenharmony_ci } 53562306a36Sopenharmony_ci *arr = new_arr; 53662306a36Sopenharmony_ci *arr_sz = new_sz; 53762306a36Sopenharmony_ci return 0; 53862306a36Sopenharmony_ci} 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci#ifndef HAVE_SCHED_GETCPU_SUPPORT 54162306a36Sopenharmony_ciint sched_getcpu(void) 54262306a36Sopenharmony_ci{ 54362306a36Sopenharmony_ci#ifdef __NR_getcpu 54462306a36Sopenharmony_ci unsigned int cpu; 54562306a36Sopenharmony_ci int err = syscall(__NR_getcpu, &cpu, NULL, NULL); 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci if (!err) 54862306a36Sopenharmony_ci return cpu; 54962306a36Sopenharmony_ci#else 55062306a36Sopenharmony_ci errno = ENOSYS; 55162306a36Sopenharmony_ci#endif 55262306a36Sopenharmony_ci return -1; 55362306a36Sopenharmony_ci} 55462306a36Sopenharmony_ci#endif 555