Chang的多管道
我正在尝试实现将运行多个 shell 命令链的程序:
| --> cmd3 --> cmd4 -->
cmd2-->|
| --> cmd5 --> cmd6 -->|--> cmd7
|
|--> cmd8
等等...
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <signal.h>
#include <fcntl.h>
#include <stdarg.h>
#include <sys/types.h>
typedef struct command {
char* name;
char** argv;
} command;
command parsecmd(char* cmd) {
command c;
char delimiter[] = " ";
char* buf = malloc(sizeof(char) * strlen(cmd));
strcpy(buf, cmd);
char **args = malloc(sizeof(char*));
char* token = strtok(buf, delimiter);
int i = 0;
while (token != NULL) {
if (i == 0) {
c.name = token;
}
args[i] = token;
token = strtok(NULL, delimiter);
++i;
}
args[i] = NULL;
c.argv = args;
return c;
}
int mkproc(char *cmd, int outfd)
{
command c = parsecmd(cmd);
int pipeleft[2];
pipe(pipeleft);
if(!fork()){
close(pipeleft[1]);
dup2(pipeleft[0], 0);
dup2(outfd, 1);
execvp(c.name, c.argv);
}
close(pipeleft[0]);
return pipeleft[1];
}
int mktree(char *cmd, int ofd0, ...)
{
int piperight[2];
pipe(piperight);
int cmdin = mkproc(cmd, piperight[1]);
close(piperight[1]);
if(!fork()){
uchar buf[4096];
int n;
while((n=read(piperight[0], buf, sizeof buf))>0){
va_list ap;
int fd;
va_start(ap, ofd0);
for(fd=ofd0; fd!=-1; fd=va_arg(ap, int)){
write(fd, buf, n);
}
va_end(ap);
}
}
return cmdin;
}
int main(int argc, char* argv[]) {
// THIS WORK
int chain_in = mkproc("cat foo.txt", mkproc("sort", mkproc("wc -l", 1)));
// THIS WORK
int tree_in1 = mktree("cat /tmp/test.log", mkproc("grep a", 1), mkproc("wc -l", 2), -1);
// NOT WORK -> HANG!
int tree_in2 = mktree("cat /tmp/test.log",
mktree("grep test",
mkproc("uniq", mkproc("wc -l", 1)),
mkproc("wc -l", 2), -1),
mkproc("sort", 2), -1);
}
在子进程上运行 strace 时,它卡在从管道读取上, 当在主进程上运行 starce 时,它也卡在 read 上...... 管道缓冲区是 64K,我一次只为每个管道写入 4k,
这是怎么回事?
谢谢!!!
I am trying to implement program that will run multiple chains of shell commands:
| --> cmd3 --> cmd4 -->
cmd2-->|
| --> cmd5 --> cmd6 -->|--> cmd7
|
|--> cmd8
and so on...
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <signal.h>
#include <fcntl.h>
#include <stdarg.h>
#include <sys/types.h>
typedef struct command {
char* name;
char** argv;
} command;
command parsecmd(char* cmd) {
command c;
char delimiter[] = " ";
char* buf = malloc(sizeof(char) * strlen(cmd));
strcpy(buf, cmd);
char **args = malloc(sizeof(char*));
char* token = strtok(buf, delimiter);
int i = 0;
while (token != NULL) {
if (i == 0) {
c.name = token;
}
args[i] = token;
token = strtok(NULL, delimiter);
++i;
}
args[i] = NULL;
c.argv = args;
return c;
}
int mkproc(char *cmd, int outfd)
{
command c = parsecmd(cmd);
int pipeleft[2];
pipe(pipeleft);
if(!fork()){
close(pipeleft[1]);
dup2(pipeleft[0], 0);
dup2(outfd, 1);
execvp(c.name, c.argv);
}
close(pipeleft[0]);
return pipeleft[1];
}
int mktree(char *cmd, int ofd0, ...)
{
int piperight[2];
pipe(piperight);
int cmdin = mkproc(cmd, piperight[1]);
close(piperight[1]);
if(!fork()){
uchar buf[4096];
int n;
while((n=read(piperight[0], buf, sizeof buf))>0){
va_list ap;
int fd;
va_start(ap, ofd0);
for(fd=ofd0; fd!=-1; fd=va_arg(ap, int)){
write(fd, buf, n);
}
va_end(ap);
}
}
return cmdin;
}
int main(int argc, char* argv[]) {
// THIS WORK
int chain_in = mkproc("cat foo.txt", mkproc("sort", mkproc("wc -l", 1)));
// THIS WORK
int tree_in1 = mktree("cat /tmp/test.log", mkproc("grep a", 1), mkproc("wc -l", 2), -1);
// NOT WORK -> HANG!
int tree_in2 = mktree("cat /tmp/test.log",
mktree("grep test",
mkproc("uniq", mkproc("wc -l", 1)),
mkproc("wc -l", 2), -1),
mkproc("sort", 2), -1);
}
when running strace on the sub processes, it's stuck on read from pipe,
when running starce on the main process, it's also stuck on read...
The pipe buffer is 64K and I am writing only 4k at once for each pipe
WHAT'S GOING ON?!
THANKS!!!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我可以看到您的代码至少有两个问题:
您需要为
0
终止符分配比cmd
长度多一个的值。由于sizeof(char)
根据定义为 1,我会将上面的内容写为:另外,对于:
您需要根据需要为尽可能多的参数分配空间:
其中
n
是参数的数量。I can see at least two problems with your code:
You need to allocate one more than the length of
cmd
, for the0
terminator. Sincesizeof(char)
is 1 by definition, I would write the above as:Also, for:
You need to allocate space for as many arguments as needed:
where
n
is the number of arguments.您没有为程序参数分配足够的内存。在
parsecmd
中,您仅为char **args = malloc(sizeof(char*))
中的单个指针分配空间,并且随后存储了超过其中一个指针而不重新分配它,导致缓冲区溢出。同样,您在 char* buf = malloc(sizeof(char) * strlen(cmd)) 中分配的字节数比应有的字节数少了 1 个字节,您需要在其中添加 1,以便有空间字符串以 NUL 结尾。此外,C 标准保证 sizeof(char) 为 1,因此无需将其放入对 malloc 的调用中。您的代码的其他问题:
malloc
的所有调用都需要对free
进行相应的调用,以避免内存泄漏。strtok
在多线程代码中使用不安全,因为它使用共享全局状态。如果此代码需要成为线程安全的,请考虑将其替换为strtok_r(3)< /code>
(如果可用)或其他替代品。
fork
、execvp
或pipe
失败,则说明您无法处理错误。修复这些问题,看看是否能解决您的挂起问题。
You're not allocating enough memory for your program arguments. In
parsecmd
, you're only allocating space for a single pointer inchar **args = malloc(sizeof(char*))
, and you're subsequently storing more than one pointer in it without reallocating it, resulting in a buffer overrun. Similarly, you're allocating one byte less than you should inchar* buf = malloc(sizeof(char) * strlen(cmd))
—you need to add one to that in order to have space for the string's terminating NUL. Also,sizeof(char)
is guaranteed to be 1 by the C standard, so there's no need to put that in the call tomalloc
.Other problems with your code:
malloc
need a corresponding call tofree
to avoid leaking memory.strtok
is not safe to use in multithreaded code, since it uses shared global state. If this code every needs to become thread-safe, consider replacing it withstrtok_r(3)
if available, or some other replacement.fork
,execvp
, orpipe
failsFix these problems and see if that solves your hang.