如何让tcsetpgrp()在C中工作?

我正在尝试给孩子进程(通过fork() )前台访问终端。

fork() ,我在子进程中运行以下代码:

 setpgid(0, 0); 

和:

 setpgid(child, child); 

在父进程中。

这为孩子提供了自己的过程组。 对setpgid()的调用正常。

现在我想让孩子访问终端。

setpgid()调用之后,我向子setpgid()添加了以下内容:

 if (!tcsetpgrp(STDIN_FILENO, getpid())) { perror("tcsetpgrp failed"); } 

之后,有一个execv()命令来生成/usr/bin/nano

然而,没有nano出现,没有任何反应,终端看起来好像它期待用户输入。

此外,在tcsetpgrp()调用之后似乎没有代码执行。

我在某处读到了我需要向子进程发送SIGCONT信号以使其工作。 如果该过程停止,我该怎么办? 父母是否必须发送信号?

如果这是解决方案,我该如何发送SIGCONT信号?

 raise(SIGCONT); 

此外,我不确定这是否有帮助,但代码工作正常,如果我运行我的程序,则生成nano

 exec ./program 

代替:

 ./program 

有任何想法吗? 非常感谢!

man 3 tcsetpgrp说:

如果tcsetpgrp()在其会话中由后台进程组的成员调用,并且调用进程未阻止或忽略SIGTTOU,则会向此后台进程组的所有成员发送SIGTTOU信号。

您需要在父进程中调用tcsetpgrp()而不是在子进程中。 但是,如果您的父进程已启动并移至后台,则它将收到SIGTTOU并将被停止。

弄清楚了。 我必须忽略任何SIGTTOU信号。

我这样做是通过添加:

 signal(SIGTTOU, SIG_IGN); 

tcsetpgrp()调用之前。

应该调用tcsetpgrp()是父母而不是孩子。 在setpgid()调用之后,子进程成为后台进程。 有效的情况是前景组放弃其权限,让另一个背景组成为前景和自身背景。 后台组中的进程无法获取控制终端。 示例代码可能如下所示:

 /* perror_act.h */ #ifndef PERROR_ACT_H #define PERROR_ACT_H #define PERROR_ACT(rtn, act) do { \ perror(rtn);\ act; \ } while (0) #define PERROR_EXIT1(rtn) PERROR_ACT(rtn, exit(1)) #define PERROR_RETN1(rtn) PERROR_ACT(rtn, return -1) #endif /* invnano.c */ #include  #include  #include  #include  #include "perror_act.h" void sig_chld(int chld) { exit(0); } int main(void) { pid_t child; int p2c[2]; struct sigaction sa = {.sa_handler = sig_chld}; if (sigaction(SIGCHLD, &sa, NULL)) PERROR_EXIT1("sigaction"); if (pipe(p2c)) PERROR_EXIT1("pipe"); if ((child = fork()) < 0) PERROR_EXIT1("fork"); if (child == 0) { char buff; size_t nread; if (close(p2c[1])) /* We must make sure this fd is closed. The reason is explained in following comments. */ PERROR_EXIT1("close"); if ((nread = read(p2c[0], &buff, 1)) < 0) /* Just to receive a message from parent indicating its work is done. Content is not important. */ PERROR_EXIT1("read"); if (nread == 0) /* When all the write ends of a pipe are closed, a read() to the read end of this pipe will get a return value of 0. We've closed the child's write end so if 0 as returned, we can sure the parent have exited because of error. */ exit(1); close(p2c[0]); execlp("nano", "nano", (char *) 0); PERROR_EXIT1("execlp"); } else { if (close(p2c[0])) PERROR_EXIT1("close"); if (setpgid(child, child)) PERROR_EXIT1("setpgid"); if (tcsetpgrp(STDIN_FILENO, child)) PERROR_EXIT1("tcsetpgrp"); if (write(p2c[1], &child, 1) != 1) /* If all the read ends of a pipe are close, a write() to the write end of this pipe will let the calling process receive a SIGPIPE whose default deposition is to terminate. */ PERROR_EXIT1("write"); while (1) /* If parent exit here, login shell will see the news and grab the controlling terminal */ pause(); } return 0; }