1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
24cf40131SArnaldo Carvalho de Melo #include "util.h"
384f5d36fSJiri Olsa #include "debug.h"
48520a98dSArnaldo Carvalho de Melo #include "event.h"
5cd0cfad7SBorislav Petkov #include <api/fs/fs.h>
67a8ef4c4SArnaldo Carvalho de Melo #include <sys/stat.h>
707bc5c69SWang Nan #include <sys/utsname.h>
876b31a29SArnaldo Carvalho de Melo #include <dirent.h>
9c23c2a0fSArnaldo Carvalho de Melo #include <fcntl.h>
10fd20e811SArnaldo Carvalho de Melo #include <inttypes.h>
119607ad3aSArnaldo Carvalho de Melo #include <signal.h>
12dc4552bfSArnaldo Carvalho de Melo #include <stdio.h>
13dc4552bfSArnaldo Carvalho de Melo #include <stdlib.h>
14cef82c9fSJiri Olsa #include <string.h>
15cef82c9fSJiri Olsa #include <errno.h>
161a47245dSAdrian Hunter #include <limits.h>
17c22e150eSIgor Lubashev #include <linux/capability.h>
18838d1452SJiri Olsa #include <linux/kernel.h>
19c339b1a9SWang Nan #include <linux/log2.h>
20bd48c63eSArnaldo Carvalho de Melo #include <linux/time64.h>
2110d34700SAdrian Hunter #include <linux/overflow.h>
229398c484SJiri Olsa #include <unistd.h>
23c22e150eSIgor Lubashev #include "cap.h"
2414cbfbebSNamhyung Kim #include "strlist.h"
25cdb6b023SJiri Olsa #include "string2.h"
2623aadb1fSJiri Olsa
271aed2671SJoerg Roedel /*
281aed2671SJoerg Roedel * XXX We need to find a better place for these things...
291aed2671SJoerg Roedel */
300a7c74eaSArnaldo Carvalho de Melo
31*f12ad272SIan Rogers const char *input_name;
32*f12ad272SIan Rogers
330a7c74eaSArnaldo Carvalho de Melo bool perf_singlethreaded = true;
340a7c74eaSArnaldo Carvalho de Melo
perf_set_singlethreaded(void)350a7c74eaSArnaldo Carvalho de Melo void perf_set_singlethreaded(void)
360a7c74eaSArnaldo Carvalho de Melo {
370a7c74eaSArnaldo Carvalho de Melo perf_singlethreaded = true;
380a7c74eaSArnaldo Carvalho de Melo }
390a7c74eaSArnaldo Carvalho de Melo
perf_set_multithreaded(void)400a7c74eaSArnaldo Carvalho de Melo void perf_set_multithreaded(void)
410a7c74eaSArnaldo Carvalho de Melo {
420a7c74eaSArnaldo Carvalho de Melo perf_singlethreaded = false;
430a7c74eaSArnaldo Carvalho de Melo }
440a7c74eaSArnaldo Carvalho de Melo
45a29d5c9bSArnaldo Carvalho de Melo int sysctl_perf_event_max_stack = PERF_MAX_STACK_DEPTH;
46a29d5c9bSArnaldo Carvalho de Melo int sysctl_perf_event_max_contexts_per_stack = PERF_MAX_CONTEXTS_PER_STACK;
474cb93446SArnaldo Carvalho de Melo
sysctl__max_stack(void)48029c75e5SArnaldo Carvalho de Melo int sysctl__max_stack(void)
49029c75e5SArnaldo Carvalho de Melo {
50029c75e5SArnaldo Carvalho de Melo int value;
51029c75e5SArnaldo Carvalho de Melo
52029c75e5SArnaldo Carvalho de Melo if (sysctl__read_int("kernel/perf_event_max_stack", &value) == 0)
53029c75e5SArnaldo Carvalho de Melo sysctl_perf_event_max_stack = value;
54029c75e5SArnaldo Carvalho de Melo
55029c75e5SArnaldo Carvalho de Melo if (sysctl__read_int("kernel/perf_event_max_contexts_per_stack", &value) == 0)
56029c75e5SArnaldo Carvalho de Melo sysctl_perf_event_max_contexts_per_stack = value;
57029c75e5SArnaldo Carvalho de Melo
58029c75e5SArnaldo Carvalho de Melo return sysctl_perf_event_max_stack;
59029c75e5SArnaldo Carvalho de Melo }
60029c75e5SArnaldo Carvalho de Melo
sysctl__nmi_watchdog_enabled(void)612a14c1bfSKan Liang bool sysctl__nmi_watchdog_enabled(void)
622a14c1bfSKan Liang {
632a14c1bfSKan Liang static bool cached;
642a14c1bfSKan Liang static bool nmi_watchdog;
652a14c1bfSKan Liang int value;
662a14c1bfSKan Liang
672a14c1bfSKan Liang if (cached)
682a14c1bfSKan Liang return nmi_watchdog;
692a14c1bfSKan Liang
702a14c1bfSKan Liang if (sysctl__read_int("kernel/nmi_watchdog", &value) < 0)
712a14c1bfSKan Liang return false;
722a14c1bfSKan Liang
732a14c1bfSKan Liang nmi_watchdog = (value > 0) ? true : false;
742a14c1bfSKan Liang cached = true;
752a14c1bfSKan Liang
762a14c1bfSKan Liang return nmi_watchdog;
772a14c1bfSKan Liang }
782a14c1bfSKan Liang
790c6332e9SArnaldo Carvalho de Melo bool test_attr__enabled;
800c6332e9SArnaldo Carvalho de Melo
811aed2671SJoerg Roedel bool perf_host = true;
82c4a7dca9SJoerg Roedel bool perf_guest = false;
831aed2671SJoerg Roedel
event_attr_init(struct perf_event_attr * attr)841aed2671SJoerg Roedel void event_attr_init(struct perf_event_attr *attr)
851aed2671SJoerg Roedel {
861aed2671SJoerg Roedel if (!perf_host)
871aed2671SJoerg Roedel attr->exclude_host = 1;
881aed2671SJoerg Roedel if (!perf_guest)
891aed2671SJoerg Roedel attr->exclude_guest = 1;
907e1ccd38SStephane Eranian /* to capture ABI version */
917e1ccd38SStephane Eranian attr->size = sizeof(*attr);
921aed2671SJoerg Roedel }
931aed2671SJoerg Roedel
mkdir_p(char * path,mode_t mode)944cf40131SArnaldo Carvalho de Melo int mkdir_p(char *path, mode_t mode)
954cf40131SArnaldo Carvalho de Melo {
964cf40131SArnaldo Carvalho de Melo struct stat st;
974cf40131SArnaldo Carvalho de Melo int err;
984cf40131SArnaldo Carvalho de Melo char *d = path;
994cf40131SArnaldo Carvalho de Melo
1004cf40131SArnaldo Carvalho de Melo if (*d != '/')
1014cf40131SArnaldo Carvalho de Melo return -1;
1024cf40131SArnaldo Carvalho de Melo
1034cf40131SArnaldo Carvalho de Melo if (stat(path, &st) == 0)
1044cf40131SArnaldo Carvalho de Melo return 0;
1054cf40131SArnaldo Carvalho de Melo
1064cf40131SArnaldo Carvalho de Melo while (*++d == '/');
1074cf40131SArnaldo Carvalho de Melo
1084cf40131SArnaldo Carvalho de Melo while ((d = strchr(d, '/'))) {
1094cf40131SArnaldo Carvalho de Melo *d = '\0';
1104cf40131SArnaldo Carvalho de Melo err = stat(path, &st) && mkdir(path, mode);
1114cf40131SArnaldo Carvalho de Melo *d++ = '/';
1124cf40131SArnaldo Carvalho de Melo if (err)
1134cf40131SArnaldo Carvalho de Melo return -1;
1144cf40131SArnaldo Carvalho de Melo while (*d == '/')
1154cf40131SArnaldo Carvalho de Melo ++d;
1164cf40131SArnaldo Carvalho de Melo }
1174cf40131SArnaldo Carvalho de Melo return (stat(path, &st) && mkdir(path, mode)) ? -1 : 0;
1184cf40131SArnaldo Carvalho de Melo }
1194cf40131SArnaldo Carvalho de Melo
match_pat(char * file,const char ** pat)120cdb6b023SJiri Olsa static bool match_pat(char *file, const char **pat)
121cdb6b023SJiri Olsa {
122cdb6b023SJiri Olsa int i = 0;
123cdb6b023SJiri Olsa
124cdb6b023SJiri Olsa if (!pat)
125cdb6b023SJiri Olsa return true;
126cdb6b023SJiri Olsa
127cdb6b023SJiri Olsa while (pat[i]) {
128cdb6b023SJiri Olsa if (strglobmatch(file, pat[i]))
129cdb6b023SJiri Olsa return true;
130cdb6b023SJiri Olsa
131cdb6b023SJiri Olsa i++;
132cdb6b023SJiri Olsa }
133cdb6b023SJiri Olsa
134cdb6b023SJiri Olsa return false;
135cdb6b023SJiri Olsa }
136cdb6b023SJiri Olsa
13705a48659SJiri Olsa /*
13805a48659SJiri Olsa * The depth specify how deep the removal will go.
13905a48659SJiri Olsa * 0 - will remove only files under the 'path' directory
14005a48659SJiri Olsa * 1 .. x - will dive in x-level deep under the 'path' directory
141cdb6b023SJiri Olsa *
142cdb6b023SJiri Olsa * If specified the pat is array of string patterns ended with NULL,
143cdb6b023SJiri Olsa * which are checked upon every file/directory found. Only matching
144cdb6b023SJiri Olsa * ones are removed.
145cdb6b023SJiri Olsa *
146cdb6b023SJiri Olsa * The function returns:
147cdb6b023SJiri Olsa * 0 on success
148cdb6b023SJiri Olsa * -1 on removal failure with errno set
149cdb6b023SJiri Olsa * -2 on pattern failure
15005a48659SJiri Olsa */
rm_rf_depth_pat(const char * path,int depth,const char ** pat)151cdb6b023SJiri Olsa static int rm_rf_depth_pat(const char *path, int depth, const char **pat)
1520b1de0beSNamhyung Kim {
1530b1de0beSNamhyung Kim DIR *dir;
154b4409ae1SJiri Olsa int ret;
1550b1de0beSNamhyung Kim struct dirent *d;
1560b1de0beSNamhyung Kim char namebuf[PATH_MAX];
157b4409ae1SJiri Olsa struct stat statbuf;
1580b1de0beSNamhyung Kim
159b4409ae1SJiri Olsa /* Do not fail if there's no file. */
160b4409ae1SJiri Olsa ret = lstat(path, &statbuf);
161b4409ae1SJiri Olsa if (ret)
1620b1de0beSNamhyung Kim return 0;
1630b1de0beSNamhyung Kim
164b4409ae1SJiri Olsa /* Try to remove any file we get. */
165b4409ae1SJiri Olsa if (!(statbuf.st_mode & S_IFDIR))
166b4409ae1SJiri Olsa return unlink(path);
167b4409ae1SJiri Olsa
168b4409ae1SJiri Olsa /* We have directory in path. */
169b4409ae1SJiri Olsa dir = opendir(path);
170b4409ae1SJiri Olsa if (dir == NULL)
171b4409ae1SJiri Olsa return -1;
172b4409ae1SJiri Olsa
1730b1de0beSNamhyung Kim while ((d = readdir(dir)) != NULL && !ret) {
1740b1de0beSNamhyung Kim
1750b1de0beSNamhyung Kim if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
1760b1de0beSNamhyung Kim continue;
1770b1de0beSNamhyung Kim
1786080728fSYunfeng Ye if (!match_pat(d->d_name, pat)) {
1796080728fSYunfeng Ye ret = -2;
1806080728fSYunfeng Ye break;
1816080728fSYunfeng Ye }
182cdb6b023SJiri Olsa
1830b1de0beSNamhyung Kim scnprintf(namebuf, sizeof(namebuf), "%s/%s",
1840b1de0beSNamhyung Kim path, d->d_name);
1850b1de0beSNamhyung Kim
1862a1ef032SMasami Hiramatsu /* We have to check symbolic link itself */
1872a1ef032SMasami Hiramatsu ret = lstat(namebuf, &statbuf);
1880b1de0beSNamhyung Kim if (ret < 0) {
1890b1de0beSNamhyung Kim pr_debug("stat failed: %s\n", namebuf);
1900b1de0beSNamhyung Kim break;
1910b1de0beSNamhyung Kim }
1920b1de0beSNamhyung Kim
1932a1ef032SMasami Hiramatsu if (S_ISDIR(statbuf.st_mode))
194cdb6b023SJiri Olsa ret = depth ? rm_rf_depth_pat(namebuf, depth - 1, pat) : 0;
1952a1ef032SMasami Hiramatsu else
1962a1ef032SMasami Hiramatsu ret = unlink(namebuf);
1970b1de0beSNamhyung Kim }
1980b1de0beSNamhyung Kim closedir(dir);
1990b1de0beSNamhyung Kim
2000b1de0beSNamhyung Kim if (ret < 0)
2010b1de0beSNamhyung Kim return ret;
2020b1de0beSNamhyung Kim
2030b1de0beSNamhyung Kim return rmdir(path);
2040b1de0beSNamhyung Kim }
2050b1de0beSNamhyung Kim
rm_rf_a_kcore_dir(const char * path,const char * name)206386e0d83SAdrian Hunter static int rm_rf_a_kcore_dir(const char *path, const char *name)
207eeb399b5SAdrian Hunter {
208eeb399b5SAdrian Hunter char kcore_dir_path[PATH_MAX];
209eeb399b5SAdrian Hunter const char *pat[] = {
210eeb399b5SAdrian Hunter "kcore",
211eeb399b5SAdrian Hunter "kallsyms",
212eeb399b5SAdrian Hunter "modules",
213eeb399b5SAdrian Hunter NULL,
214eeb399b5SAdrian Hunter };
215eeb399b5SAdrian Hunter
216386e0d83SAdrian Hunter snprintf(kcore_dir_path, sizeof(kcore_dir_path), "%s/%s", path, name);
217eeb399b5SAdrian Hunter
218eeb399b5SAdrian Hunter return rm_rf_depth_pat(kcore_dir_path, 0, pat);
219eeb399b5SAdrian Hunter }
220eeb399b5SAdrian Hunter
kcore_dir_filter(const char * name __maybe_unused,struct dirent * d)221386e0d83SAdrian Hunter static bool kcore_dir_filter(const char *name __maybe_unused, struct dirent *d)
222386e0d83SAdrian Hunter {
223386e0d83SAdrian Hunter const char *pat[] = {
224386e0d83SAdrian Hunter "kcore_dir",
225386e0d83SAdrian Hunter "kcore_dir__[1-9]*",
226386e0d83SAdrian Hunter NULL,
227386e0d83SAdrian Hunter };
228386e0d83SAdrian Hunter
229386e0d83SAdrian Hunter return match_pat(d->d_name, pat);
230386e0d83SAdrian Hunter }
231386e0d83SAdrian Hunter
rm_rf_kcore_dir(const char * path)232386e0d83SAdrian Hunter static int rm_rf_kcore_dir(const char *path)
233386e0d83SAdrian Hunter {
234386e0d83SAdrian Hunter struct strlist *kcore_dirs;
235386e0d83SAdrian Hunter struct str_node *nd;
236386e0d83SAdrian Hunter int ret;
237386e0d83SAdrian Hunter
238386e0d83SAdrian Hunter kcore_dirs = lsdir(path, kcore_dir_filter);
239386e0d83SAdrian Hunter
240386e0d83SAdrian Hunter if (!kcore_dirs)
241386e0d83SAdrian Hunter return 0;
242386e0d83SAdrian Hunter
243386e0d83SAdrian Hunter strlist__for_each_entry(nd, kcore_dirs) {
244386e0d83SAdrian Hunter ret = rm_rf_a_kcore_dir(path, nd->s);
245386e0d83SAdrian Hunter if (ret)
246386e0d83SAdrian Hunter return ret;
247386e0d83SAdrian Hunter }
248386e0d83SAdrian Hunter
249386e0d83SAdrian Hunter strlist__delete(kcore_dirs);
250386e0d83SAdrian Hunter
251386e0d83SAdrian Hunter return 0;
252386e0d83SAdrian Hunter }
253386e0d83SAdrian Hunter
rm_rf_perf_data(const char * path)254c69e4c37SJiri Olsa int rm_rf_perf_data(const char *path)
255c69e4c37SJiri Olsa {
256c69e4c37SJiri Olsa const char *pat[] = {
2579b70b9dbSAdrian Hunter "data",
258c69e4c37SJiri Olsa "data.*",
259c69e4c37SJiri Olsa NULL,
260c69e4c37SJiri Olsa };
261c69e4c37SJiri Olsa
262eeb399b5SAdrian Hunter rm_rf_kcore_dir(path);
263eeb399b5SAdrian Hunter
264c69e4c37SJiri Olsa return rm_rf_depth_pat(path, 0, pat);
265c69e4c37SJiri Olsa }
266c69e4c37SJiri Olsa
rm_rf(const char * path)26705a48659SJiri Olsa int rm_rf(const char *path)
26805a48659SJiri Olsa {
269cdb6b023SJiri Olsa return rm_rf_depth_pat(path, INT_MAX, NULL);
27005a48659SJiri Olsa }
27105a48659SJiri Olsa
272e1ce726eSMasami Hiramatsu /* A filter which removes dot files */
lsdir_no_dot_filter(const char * name __maybe_unused,struct dirent * d)273e1ce726eSMasami Hiramatsu bool lsdir_no_dot_filter(const char *name __maybe_unused, struct dirent *d)
274e1ce726eSMasami Hiramatsu {
275e1ce726eSMasami Hiramatsu return d->d_name[0] != '.';
276e1ce726eSMasami Hiramatsu }
277e1ce726eSMasami Hiramatsu
278e1ce726eSMasami Hiramatsu /* lsdir reads a directory and store it in strlist */
lsdir(const char * name,bool (* filter)(const char *,struct dirent *))279e1ce726eSMasami Hiramatsu struct strlist *lsdir(const char *name,
280e1ce726eSMasami Hiramatsu bool (*filter)(const char *, struct dirent *))
281e1ce726eSMasami Hiramatsu {
282e1ce726eSMasami Hiramatsu struct strlist *list = NULL;
283e1ce726eSMasami Hiramatsu DIR *dir;
284e1ce726eSMasami Hiramatsu struct dirent *d;
285e1ce726eSMasami Hiramatsu
286e1ce726eSMasami Hiramatsu dir = opendir(name);
287e1ce726eSMasami Hiramatsu if (!dir)
288e1ce726eSMasami Hiramatsu return NULL;
289e1ce726eSMasami Hiramatsu
290e1ce726eSMasami Hiramatsu list = strlist__new(NULL, NULL);
291e1ce726eSMasami Hiramatsu if (!list) {
292357a54f3SMasami Hiramatsu errno = ENOMEM;
293e1ce726eSMasami Hiramatsu goto out;
294e1ce726eSMasami Hiramatsu }
295e1ce726eSMasami Hiramatsu
296e1ce726eSMasami Hiramatsu while ((d = readdir(dir)) != NULL) {
297e1ce726eSMasami Hiramatsu if (!filter || filter(name, d))
298e1ce726eSMasami Hiramatsu strlist__add(list, d->d_name);
299e1ce726eSMasami Hiramatsu }
300e1ce726eSMasami Hiramatsu
301e1ce726eSMasami Hiramatsu out:
302e1ce726eSMasami Hiramatsu closedir(dir);
303e1ce726eSMasami Hiramatsu return list;
304e1ce726eSMasami Hiramatsu }
305e1ce726eSMasami Hiramatsu
hex_width(u64 v)30661e04b33SArnaldo Carvalho de Melo size_t hex_width(u64 v)
30761e04b33SArnaldo Carvalho de Melo {
30861e04b33SArnaldo Carvalho de Melo size_t n = 1;
30961e04b33SArnaldo Carvalho de Melo
31061e04b33SArnaldo Carvalho de Melo while ((v >>= 4))
31161e04b33SArnaldo Carvalho de Melo ++n;
31261e04b33SArnaldo Carvalho de Melo
31361e04b33SArnaldo Carvalho de Melo return n;
31461e04b33SArnaldo Carvalho de Melo }
315dc4552bfSArnaldo Carvalho de Melo
perf_event_paranoid(void)3161a47245dSAdrian Hunter int perf_event_paranoid(void)
3171a47245dSAdrian Hunter {
3181a47245dSAdrian Hunter int value;
3191a47245dSAdrian Hunter
320ce27309fSArnaldo Carvalho de Melo if (sysctl__read_int("kernel/perf_event_paranoid", &value))
3211a47245dSAdrian Hunter return INT_MAX;
3221a47245dSAdrian Hunter
3231a47245dSAdrian Hunter return value;
3241a47245dSAdrian Hunter }
325c22e150eSIgor Lubashev
perf_event_paranoid_check(int max_level)326c22e150eSIgor Lubashev bool perf_event_paranoid_check(int max_level)
327c22e150eSIgor Lubashev {
328c22e150eSIgor Lubashev return perf_cap__capable(CAP_SYS_ADMIN) ||
3296b3e0e2eSAlexey Budankov perf_cap__capable(CAP_PERFMON) ||
330c22e150eSIgor Lubashev perf_event_paranoid() <= max_level;
331c22e150eSIgor Lubashev }
332c22e150eSIgor Lubashev
333d18acd15SWang Nan static int
fetch_ubuntu_kernel_version(unsigned int * puint)334d18acd15SWang Nan fetch_ubuntu_kernel_version(unsigned int *puint)
335d18acd15SWang Nan {
336d18acd15SWang Nan ssize_t len;
337d18acd15SWang Nan size_t line_len = 0;
338d18acd15SWang Nan char *ptr, *line = NULL;
339d18acd15SWang Nan int version, patchlevel, sublevel, err;
34044b58e06SArnaldo Carvalho de Melo FILE *vsig;
341d18acd15SWang Nan
34244b58e06SArnaldo Carvalho de Melo if (!puint)
34344b58e06SArnaldo Carvalho de Melo return 0;
34444b58e06SArnaldo Carvalho de Melo
34544b58e06SArnaldo Carvalho de Melo vsig = fopen("/proc/version_signature", "r");
346d18acd15SWang Nan if (!vsig) {
347d18acd15SWang Nan pr_debug("Open /proc/version_signature failed: %s\n",
348d18acd15SWang Nan strerror(errno));
349d18acd15SWang Nan return -1;
350d18acd15SWang Nan }
351d18acd15SWang Nan
352d18acd15SWang Nan len = getline(&line, &line_len, vsig);
353d18acd15SWang Nan fclose(vsig);
354d18acd15SWang Nan err = -1;
355d18acd15SWang Nan if (len <= 0) {
356d18acd15SWang Nan pr_debug("Reading from /proc/version_signature failed: %s\n",
357d18acd15SWang Nan strerror(errno));
358d18acd15SWang Nan goto errout;
359d18acd15SWang Nan }
360d18acd15SWang Nan
361d18acd15SWang Nan ptr = strrchr(line, ' ');
362d18acd15SWang Nan if (!ptr) {
363d18acd15SWang Nan pr_debug("Parsing /proc/version_signature failed: %s\n", line);
364d18acd15SWang Nan goto errout;
365d18acd15SWang Nan }
366d18acd15SWang Nan
367d18acd15SWang Nan err = sscanf(ptr + 1, "%d.%d.%d",
368d18acd15SWang Nan &version, &patchlevel, &sublevel);
369d18acd15SWang Nan if (err != 3) {
370d18acd15SWang Nan pr_debug("Unable to get kernel version from /proc/version_signature '%s'\n",
371d18acd15SWang Nan line);
372d18acd15SWang Nan goto errout;
373d18acd15SWang Nan }
374d18acd15SWang Nan
375d18acd15SWang Nan *puint = (version << 16) + (patchlevel << 8) + sublevel;
376d18acd15SWang Nan err = 0;
377d18acd15SWang Nan errout:
378d18acd15SWang Nan free(line);
379d18acd15SWang Nan return err;
380d18acd15SWang Nan }
381d18acd15SWang Nan
38207bc5c69SWang Nan int
fetch_kernel_version(unsigned int * puint,char * str,size_t str_size)38307bc5c69SWang Nan fetch_kernel_version(unsigned int *puint, char *str,
38407bc5c69SWang Nan size_t str_size)
38507bc5c69SWang Nan {
38607bc5c69SWang Nan struct utsname utsname;
38707bc5c69SWang Nan int version, patchlevel, sublevel, err;
388d18acd15SWang Nan bool int_ver_ready = false;
389d18acd15SWang Nan
390d18acd15SWang Nan if (access("/proc/version_signature", R_OK) == 0)
391d18acd15SWang Nan if (!fetch_ubuntu_kernel_version(puint))
392d18acd15SWang Nan int_ver_ready = true;
39307bc5c69SWang Nan
39407bc5c69SWang Nan if (uname(&utsname))
39507bc5c69SWang Nan return -1;
39607bc5c69SWang Nan
39707bc5c69SWang Nan if (str && str_size) {
39807bc5c69SWang Nan strncpy(str, utsname.release, str_size);
39907bc5c69SWang Nan str[str_size - 1] = '\0';
40007bc5c69SWang Nan }
40107bc5c69SWang Nan
40244b58e06SArnaldo Carvalho de Melo if (!puint || int_ver_ready)
40344b58e06SArnaldo Carvalho de Melo return 0;
40444b58e06SArnaldo Carvalho de Melo
40507bc5c69SWang Nan err = sscanf(utsname.release, "%d.%d.%d",
40607bc5c69SWang Nan &version, &patchlevel, &sublevel);
40707bc5c69SWang Nan
40807bc5c69SWang Nan if (err != 3) {
409d18acd15SWang Nan pr_debug("Unable to get kernel version from uname '%s'\n",
41007bc5c69SWang Nan utsname.release);
41107bc5c69SWang Nan return -1;
41207bc5c69SWang Nan }
41307bc5c69SWang Nan
41407bc5c69SWang Nan *puint = (version << 16) + (patchlevel << 8) + sublevel;
41507bc5c69SWang Nan return 0;
41607bc5c69SWang Nan }
41714cbfbebSNamhyung Kim
perf_tip(char ** strp,const char * dirpath)418d9fc7061SIan Rogers int perf_tip(char **strp, const char *dirpath)
41914cbfbebSNamhyung Kim {
42014cbfbebSNamhyung Kim struct strlist *tips;
42114cbfbebSNamhyung Kim struct str_node *node;
42214cbfbebSNamhyung Kim struct strlist_config conf = {
42334b7b0f9SNamhyung Kim .dirname = dirpath,
42434b7b0f9SNamhyung Kim .file_only = true,
42514cbfbebSNamhyung Kim };
426d9fc7061SIan Rogers int ret = 0;
42714cbfbebSNamhyung Kim
428d9fc7061SIan Rogers *strp = NULL;
42914cbfbebSNamhyung Kim tips = strlist__new("tips.txt", &conf);
43034b7b0f9SNamhyung Kim if (tips == NULL)
431d9fc7061SIan Rogers return -errno;
43234b7b0f9SNamhyung Kim
43334b7b0f9SNamhyung Kim if (strlist__nr_entries(tips) == 0)
43414cbfbebSNamhyung Kim goto out;
43514cbfbebSNamhyung Kim
43614cbfbebSNamhyung Kim node = strlist__entry(tips, random() % strlist__nr_entries(tips));
437d9fc7061SIan Rogers if (asprintf(strp, "Tip: %s", node->s) < 0)
438d9fc7061SIan Rogers ret = -ENOMEM;
43914cbfbebSNamhyung Kim
44014cbfbebSNamhyung Kim out:
44114cbfbebSNamhyung Kim strlist__delete(tips);
44214cbfbebSNamhyung Kim
443d9fc7061SIan Rogers return ret;
44414cbfbebSNamhyung Kim }
44594816addSAndi Kleen
perf_exe(char * buf,int len)44694816addSAndi Kleen char *perf_exe(char *buf, int len)
44794816addSAndi Kleen {
44894816addSAndi Kleen int n = readlink("/proc/self/exe", buf, len);
44994816addSAndi Kleen if (n > 0) {
45094816addSAndi Kleen buf[n] = 0;
45194816addSAndi Kleen return buf;
45294816addSAndi Kleen }
45394816addSAndi Kleen return strcpy(buf, "perf");
45494816addSAndi Kleen }
4559bce13eaSJiri Olsa
perf_debuginfod_setup(struct perf_debuginfod * di)4569bce13eaSJiri Olsa void perf_debuginfod_setup(struct perf_debuginfod *di)
4579bce13eaSJiri Olsa {
4589bce13eaSJiri Olsa /*
4599bce13eaSJiri Olsa * By default '!di->set' we clear DEBUGINFOD_URLS, so debuginfod
4609bce13eaSJiri Olsa * processing is not triggered, otherwise we set it to 'di->urls'
4619bce13eaSJiri Olsa * value. If 'di->urls' is "system" we keep DEBUGINFOD_URLS value.
4629bce13eaSJiri Olsa */
4639bce13eaSJiri Olsa if (!di->set)
4649bce13eaSJiri Olsa setenv("DEBUGINFOD_URLS", "", 1);
4659bce13eaSJiri Olsa else if (di->urls && strcmp(di->urls, "system"))
4669bce13eaSJiri Olsa setenv("DEBUGINFOD_URLS", di->urls, 1);
4679bce13eaSJiri Olsa
4689bce13eaSJiri Olsa pr_debug("DEBUGINFOD_URLS=%s\n", getenv("DEBUGINFOD_URLS"));
469c60664deSMartin Liška
470c60664deSMartin Liška #ifndef HAVE_DEBUGINFOD_SUPPORT
471c60664deSMartin Liška if (di->set)
472c60664deSMartin Liška pr_warning("WARNING: debuginfod support requested, but perf is not built with it\n");
473c60664deSMartin Liška #endif
4749bce13eaSJiri Olsa }
47567fd1892SNamhyung Kim
47667fd1892SNamhyung Kim /*
47767fd1892SNamhyung Kim * Return a new filename prepended with task's root directory if it's in
47867fd1892SNamhyung Kim * a chroot. Callers should free the returned string.
47967fd1892SNamhyung Kim */
filename_with_chroot(int pid,const char * filename)48067fd1892SNamhyung Kim char *filename_with_chroot(int pid, const char *filename)
48167fd1892SNamhyung Kim {
48267fd1892SNamhyung Kim char buf[PATH_MAX];
48367fd1892SNamhyung Kim char proc_root[32];
48467fd1892SNamhyung Kim char *new_name = NULL;
48567fd1892SNamhyung Kim int ret;
48667fd1892SNamhyung Kim
48767fd1892SNamhyung Kim scnprintf(proc_root, sizeof(proc_root), "/proc/%d/root", pid);
48867fd1892SNamhyung Kim ret = readlink(proc_root, buf, sizeof(buf) - 1);
48967fd1892SNamhyung Kim if (ret <= 0)
49067fd1892SNamhyung Kim return NULL;
49167fd1892SNamhyung Kim
49267fd1892SNamhyung Kim /* readlink(2) does not append a null byte to buf */
49367fd1892SNamhyung Kim buf[ret] = '\0';
49467fd1892SNamhyung Kim
49567fd1892SNamhyung Kim if (!strcmp(buf, "/"))
49667fd1892SNamhyung Kim return NULL;
49767fd1892SNamhyung Kim
49867fd1892SNamhyung Kim if (strstr(buf, "(deleted)"))
49967fd1892SNamhyung Kim return NULL;
50067fd1892SNamhyung Kim
50167fd1892SNamhyung Kim if (asprintf(&new_name, "%s/%s", buf, filename) < 0)
50267fd1892SNamhyung Kim return NULL;
50367fd1892SNamhyung Kim
50467fd1892SNamhyung Kim return new_name;
50567fd1892SNamhyung Kim }
50610d34700SAdrian Hunter
50710d34700SAdrian Hunter /*
50810d34700SAdrian Hunter * Reallocate an array *arr of size *arr_sz so that it is big enough to contain
50910d34700SAdrian Hunter * x elements of size msz, initializing new entries to *init_val or zero if
51010d34700SAdrian Hunter * init_val is NULL
51110d34700SAdrian Hunter */
do_realloc_array_as_needed(void ** arr,size_t * arr_sz,size_t x,size_t msz,const void * init_val)51210d34700SAdrian Hunter int do_realloc_array_as_needed(void **arr, size_t *arr_sz, size_t x, size_t msz, const void *init_val)
51310d34700SAdrian Hunter {
51410d34700SAdrian Hunter size_t new_sz = *arr_sz;
51510d34700SAdrian Hunter void *new_arr;
51610d34700SAdrian Hunter size_t i;
51710d34700SAdrian Hunter
51810d34700SAdrian Hunter if (!new_sz)
51910d34700SAdrian Hunter new_sz = msz >= 64 ? 1 : roundup(64, msz); /* Start with at least 64 bytes */
52010d34700SAdrian Hunter while (x >= new_sz) {
52110d34700SAdrian Hunter if (check_mul_overflow(new_sz, (size_t)2, &new_sz))
52210d34700SAdrian Hunter return -ENOMEM;
52310d34700SAdrian Hunter }
52410d34700SAdrian Hunter if (new_sz == *arr_sz)
52510d34700SAdrian Hunter return 0;
52610d34700SAdrian Hunter new_arr = calloc(new_sz, msz);
52710d34700SAdrian Hunter if (!new_arr)
52810d34700SAdrian Hunter return -ENOMEM;
529f5ceb159SAdrian Hunter if (*arr_sz)
53010d34700SAdrian Hunter memcpy(new_arr, *arr, *arr_sz * msz);
53110d34700SAdrian Hunter if (init_val) {
53210d34700SAdrian Hunter for (i = *arr_sz; i < new_sz; i++)
53310d34700SAdrian Hunter memcpy(new_arr + (i * msz), init_val, msz);
53410d34700SAdrian Hunter }
53510d34700SAdrian Hunter *arr = new_arr;
53610d34700SAdrian Hunter *arr_sz = new_sz;
53710d34700SAdrian Hunter return 0;
53810d34700SAdrian Hunter }
5390cd3142fSIan Rogers
5400cd3142fSIan Rogers #ifndef HAVE_SCHED_GETCPU_SUPPORT
sched_getcpu(void)5410cd3142fSIan Rogers int sched_getcpu(void)
5420cd3142fSIan Rogers {
5430cd3142fSIan Rogers #ifdef __NR_getcpu
5440cd3142fSIan Rogers unsigned int cpu;
5450cd3142fSIan Rogers int err = syscall(__NR_getcpu, &cpu, NULL, NULL);
5460cd3142fSIan Rogers
5470cd3142fSIan Rogers if (!err)
5480cd3142fSIan Rogers return cpu;
5490cd3142fSIan Rogers #else
5500cd3142fSIan Rogers errno = ENOSYS;
5510cd3142fSIan Rogers #endif
5520cd3142fSIan Rogers return -1;
5530cd3142fSIan Rogers }
5540cd3142fSIan Rogers #endif
555