【问题标题】:Using execvp or execlp with a flag?使用带有标志的 execvp 或 execlp?
【发布时间】:2017-05-12 04:30:43
【问题描述】:

我正在尝试编写一个 C 程序来软链接 Unix 上的 2 个文件。在 Unix 中,这个命令是:

ln -s oldfile newlink  

所以我编写了一个代码来创建一个char * 参数数组,如下所示:

char *args[4];
args[0] = "ln";
args[1] = "-s";
args[2] = argv[2]; //argv[2] is the name of the old file
args[3] = argv[3]; //argv[3] is the name of the new soft link file


execvp(args[0], args); 

但是 Linux 处理器不读取 -s 标志。如何以处理 -s 标志的方式重写它?我也尝试使用execlp 来做到这一点:

execlp(args[0], args[0], args[1], args[2], args[3], NULL);  

但这也行不通。我在这些方面做错了什么?

编辑:我也尝试了 symlink() 命令,但我认为我的 linux 版本不支持它,除非我错了并且我的代码存在缺陷:

char *args[4];
args[0] = "symlink";
args[1] = argv[2];
args[2] = argv[3];
args[3] = NULL;



execvp(args[0], args);

【问题讨论】:

  • 对于execvp(),你需要一个最终的NULL指针——所以你需要char *args[5];args[4] = NULL;(或= 0)。 execlp() 几乎没问题;严格来说,你应该使用(char *)NULL 作为最后一个参数。这在系统提供 #define NULL 0 而没有其他类型的 64 位机器上可能很重要。这是一个有效的空指针——但仅在已知需要空指针的上下文中,execlp() 的参数列表不是这些上下文之一。
  • 你怎么知道它没有被阅读?
  • 请注意,symlink 不是命令(在您的 shell 中可用)。这是一个系统调用。
  • 否:建议您使用symlink() 系统调用。 if (symlink(argv[2], argv[3]) != 0) { …report error… }.

标签: c linux file-link


【解决方案1】:

在 linux 上编写 C 代码软链接 2 个文件

为此,您无需在 C 代码中启动 /bin/ln 进程。您应该改用symlink(2) 系统调用(将由ln 进程使用);这更简单,更快。不要忘记检查它的成功。请注意,symlink 是一个 system call(即使是旧的 Linux 内核也应该有)作为 C 函数,而不是命令(所以实际上你不能运行任何 symlink在你的 shell 中敲击> commandexecutable)。如文档所述,您需要在 C 源文件中使用 #include <unistd.h>。另请阅读symlink(7)

使用symlink 系统调用

例如,要执行 ln -s ~/somefile /tmp 的等效操作,您首先需要计算与 ~/somefile 对应的路径(例如使用 snprintf(3)...)(通过 using getenv ...):

char* somefilepath = "somefile";
char oldpathbuf[256];
snprintf(oldpathbuf, sizeof(pathbuf), "%s/%s", getenv("HOME"), somefilepath);
/// missing detecting and handling of errors in above

(我让您处理所有错误情况,包括snprintf 的空间不足,它们很重要!)

然后你需要计算新链接的路径(你不能在目录上使用symlink系统调用):

 char newpathbuf[256];
 snprintf(newpathbuf, sizeof(newpathbuf), "/tmp/%s", somefilepath);

(再次处理错误,想想如果somefilepath../ 开头会发生什么)

最后,进行系统调用但检查失败:

 if (symlink(newpathbuf, oldpathbuf)) {
   perror("symlink");
   exit(EXIT_FAILURE);
 }

执行/bin/ln 程序

如果您坚持(错误地恕我直言)在/bin/ln 或某些exec(3) 函数(将调用execve)上使用execve(2) 系统调用,请务必明确添加NULL 指针。顺便说一句,这些exec 函数不会返回成功,因此您可能需要先调用fork(2),然后再使用waitpid(2)

注意execvp 使用PATH variable。因此,仅将ln 传递给它可能会运行(如果您的用户有一个奇怪的$PATH 设置)/bin/ln(该文件路径在Linux FHS 和POSIX 中指定)以外的其他东西,并具有一些意想不到的副作用。但是请参阅environ(7)

Linux 处理器不读取 -s 标志

不涉及“Linux 处理器”。 -s 标志由/bin/ln executable 程序处理(其main 函数获取扩展程序参数,然后调用symlink 系统调用)。您需要更多地了解 unix shell 的作用以及globbing 是什么以及 shell 的命令是如何expanded

有用的阅读参考

我建议阅读 Advanced Linux Programming 以及 intro(2)syscalls(2) 手册页。

您可能应该阅读更多关于Operating Systems 的信息,并了解命令和系统调用之间的区别以及任何Unix shell 的作用。我建议阅读免费提供的Operating Systems : Three Easy Pieces

【讨论】:

  • 我已经编辑了这个问题——我不认为我的(我大学的)版本的 linux(一个非常旧的版本)能够执行 symlink() 命令。有没有办法用 execlp 或 execvp 做到这一点?
  • 我很确定你的 Linux 有 symlink 系统调用。 AFAIK 甚至在 1993 年的 Linux 内核中甚至可能在第一个内核中都可以使用它。没有它你基本上就不能拥有一个 Unix 系统(因为它需要 实现/bin/ln 命令)
  • Here is what I get when I attempt it in the command line. 这是 Unix 的旧版本(我很抱歉),我不相信它包含在内。
  • 您使用的是哪个“旧版本的 Unix”,@JohnStawket?它必须非常古老(20 年或更长时间),并且即使在那时也是 staider 变体之一。 POSIX 需要 symlink() 作为 90 年代某个时候的系统调用。 POSIX 1990 没有强制使用符号链接——我检查了该标准的纸质副本; POSIX 1997 做到了。我不确定是否有中间版本。
  • @JohnStawket:Solaris 10 有 symlink() 系统调用。很少有系统有symlink 命令——它不是标准的,ln -s 命令就足够了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-08-28
  • 2020-06-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多