cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

help-unknown-cmd.c (3084B)


      1// SPDX-License-Identifier: GPL-2.0
      2#include "cache.h"
      3#include "config.h"
      4#include <poll.h>
      5#include <stdio.h>
      6#include <stdlib.h>
      7#include <subcmd/help.h>
      8#include "../builtin.h"
      9#include "levenshtein.h"
     10#include <linux/zalloc.h>
     11
     12static int autocorrect;
     13
     14static int perf_unknown_cmd_config(const char *var, const char *value,
     15				   void *cb __maybe_unused)
     16{
     17	if (!strcmp(var, "help.autocorrect"))
     18		return perf_config_int(&autocorrect, var,value);
     19
     20	return 0;
     21}
     22
     23static int levenshtein_compare(const void *p1, const void *p2)
     24{
     25	const struct cmdname *const *c1 = p1, *const *c2 = p2;
     26	const char *s1 = (*c1)->name, *s2 = (*c2)->name;
     27	int l1 = (*c1)->len;
     28	int l2 = (*c2)->len;
     29	return l1 != l2 ? l1 - l2 : strcmp(s1, s2);
     30}
     31
     32static int add_cmd_list(struct cmdnames *cmds, struct cmdnames *old)
     33{
     34	unsigned int i, nr = cmds->cnt + old->cnt;
     35	void *tmp;
     36
     37	if (nr > cmds->alloc) {
     38		/* Choose bigger one to alloc */
     39		if (alloc_nr(cmds->alloc) < nr)
     40			cmds->alloc = nr;
     41		else
     42			cmds->alloc = alloc_nr(cmds->alloc);
     43		tmp = realloc(cmds->names, cmds->alloc * sizeof(*cmds->names));
     44		if (!tmp)
     45			return -1;
     46		cmds->names = tmp;
     47	}
     48	for (i = 0; i < old->cnt; i++)
     49		cmds->names[cmds->cnt++] = old->names[i];
     50	zfree(&old->names);
     51	old->cnt = 0;
     52	return 0;
     53}
     54
     55const char *help_unknown_cmd(const char *cmd)
     56{
     57	unsigned int i, n = 0, best_similarity = 0;
     58	struct cmdnames main_cmds, other_cmds;
     59
     60	memset(&main_cmds, 0, sizeof(main_cmds));
     61	memset(&other_cmds, 0, sizeof(main_cmds));
     62
     63	perf_config(perf_unknown_cmd_config, NULL);
     64
     65	load_command_list("perf-", &main_cmds, &other_cmds);
     66
     67	if (add_cmd_list(&main_cmds, &other_cmds) < 0) {
     68		fprintf(stderr, "ERROR: Failed to allocate command list for unknown command.\n");
     69		goto end;
     70	}
     71	qsort(main_cmds.names, main_cmds.cnt,
     72	      sizeof(main_cmds.names), cmdname_compare);
     73	uniq(&main_cmds);
     74
     75	if (main_cmds.cnt) {
     76		/* This reuses cmdname->len for similarity index */
     77		for (i = 0; i < main_cmds.cnt; ++i)
     78			main_cmds.names[i]->len =
     79				levenshtein(cmd, main_cmds.names[i]->name, 0, 2, 1, 4);
     80
     81		qsort(main_cmds.names, main_cmds.cnt,
     82		      sizeof(*main_cmds.names), levenshtein_compare);
     83
     84		best_similarity = main_cmds.names[0]->len;
     85		n = 1;
     86		while (n < main_cmds.cnt && best_similarity == main_cmds.names[n]->len)
     87			++n;
     88	}
     89
     90	if (autocorrect && n == 1) {
     91		const char *assumed = main_cmds.names[0]->name;
     92
     93		main_cmds.names[0] = NULL;
     94		clean_cmdnames(&main_cmds);
     95		fprintf(stderr, "WARNING: You called a perf program named '%s', "
     96			"which does not exist.\n"
     97			"Continuing under the assumption that you meant '%s'\n",
     98			cmd, assumed);
     99		if (autocorrect > 0) {
    100			fprintf(stderr, "in %0.1f seconds automatically...\n",
    101				(float)autocorrect/10.0);
    102			poll(NULL, 0, autocorrect * 100);
    103		}
    104		return assumed;
    105	}
    106
    107	fprintf(stderr, "perf: '%s' is not a perf-command. See 'perf --help'.\n", cmd);
    108
    109	if (main_cmds.cnt && best_similarity < 6) {
    110		fprintf(stderr, "\nDid you mean %s?\n",
    111			n < 2 ? "this": "one of these");
    112
    113		for (i = 0; i < n; i++)
    114			fprintf(stderr, "\t%s\n", main_cmds.names[i]->name);
    115	}
    116end:
    117	exit(1);
    118}