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