如何使用 c 程序确定用户是否输入了 linux 中存在的命令

How to use a c program to determine if the user entered a command that exists in linux

我正在做这个让用户输入 c 字符串的程序,然后我想创建一个函数来检查用户输入的字符串是否是 linux 命令。 前任。 用户:猫 输出:cat 是一个命令

用户:你好 输出:你好不是命令

等...

有人告诉我可以使用 execvp,但我不想执行命令只是为了弄清楚它是否存在,我只想确定它是否存在。

我认为可以利用 linux 的 whereis 命令来输出特定命令的位置,但是我不知道如何在 c 中实现它。

我还被告知 stat() 可以工作,但我不确定如何工作,因为它的 marcos 只针对目录和文件进行更改。 cat 文件之类的命令也是如此吗?如果是这样,当我做 运行 统计时:

stat( cmd, &buff );

我不需要cmd的路径吗?

总体而言,我如何确定用户是否使用 c 在 linux 中输入了有效命令并让解决方案相对有利?

stat 系统调用提供有关文件的信息,前提是您已提供文件名的完整路径。如果您想知道文件和类型以及是否是exe和Linux cmd,则需要从根目录搜索然后检查每个文件然后确定类型等。我建议您尝试理解 unix shell 是如何工作的,那么你就会理解你的问题的答案。 exec 系列系统调用执行程序,您需要 fork 然后在子系统中调用 exec,否则您的程序将执行新命令。

你写:

wouldn't I need the cmd's path

是的。对于没有路径的任何命令(cat 不是 /usr/bin/cat),您需要在伪代码中遍历 PATH 变量的所有元素:

for (path in PATH) {
    cmdpath = concat(path, "/", cmd);
    stat(cmdpath, &statbuff);
    ...
}

但是,在不厌其烦地复制 execvp 中的工作之后,您所做的只是为奇怪的计时 ("race") 错误创建一个位置,可能会引入安全漏洞.有关此主题的介绍,请参阅此维基百科文章:https://en.wikipedia.org/wiki/Time_of_check_to_time_of_use

所以解决方案通常是您不想使用的解决方案:

if (execvp(cmd, args) == -1) {
    printf("well, that didn't go well, did it?\n");
}

想要 "look before you leap" 方法很自然,但 "try it and see" 方法通常更简单、更安全。

编辑

您对破坏文件的担心令人钦佩,但这正是 "real" shell:

中发生的事情
# date >victim
# cat victim 
Fri Feb 12 09:23:56 CST 2016
# shjsds >victim
shjsds: Command not found.
# cat victim
#                                  ! file was clobbered

您可以结合使用 Linux which 命令和 C 函数 popen:

char testCmd[100];
char usrCmd[100];

strcpy(testCmd, "which ");
strcpy(usrCmd, "cat hello.txt");
strncat(testCmd, usrCmd, 93);

char path[100];
FILE *p = popen( testCmd , "r");
if(p ) {
    while(fgets(path, sizeof(path), p) != NULL) {
        printf("%s", path);
    }
}

which 命令 returns 其参数的路径,传递 cat hello.txt 似乎也有效。如果你期望像输出重定向这样令人讨厌的事情,那么只将用户输入的第一个单词发送到 which 是有意义的。

which 打印命令的路径(如果它在路径中)或换行符(如果找不到命令)。