Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/62.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
有没有一种方法可以确定;“孙子”;“生成的进程的pid”;sh-c“什么;?_C_Linux_Process_Popen_Child Process - Fatal编程技术网

有没有一种方法可以确定;“孙子”;“生成的进程的pid”;sh-c“什么;?

有没有一种方法可以确定;“孙子”;“生成的进程的pid”;sh-c“什么;?,c,linux,process,popen,child-process,C,Linux,Process,Popen,Child Process,这个问题源自和 为了加深我对派生进程和重定向管道的理解,我编写了下面类似函数的popen,它返回派生子进程的pid\t 注意:popen2() 底部的代码不是很长,但要切中要害:a.out生成child.out以及ps aux | grep child,以便在打印出它认为是child.out的pid之前获得子进程统计数据的视觉确认 上的一位评论员指出,通过sh-c生成的进程可能最终成为子进程或孙进程,这取决于sh是什么。 我无意中验证了这一点,因为我发现在我的主机上,sh解析为/bin/bash

这个问题源自和

为了加深我对派生进程和重定向管道的理解,我编写了下面类似函数的
popen
,它返回派生子进程的
pid\t

注意:
popen2()

底部的代码不是很长,但要切中要害:
a.out
生成
child.out
以及
ps aux | grep child
,以便在打印出它认为是
child.out
的pid之前获得子进程统计数据的视觉确认

上的一位评论员指出,通过
sh-c
生成的进程可能最终成为子进程或孙进程,这取决于
sh
是什么。
我无意中验证了这一点,因为我发现在我的主机上,
sh
解析为
/bin/bash
,运行
a.out
显示
child.out
作为子进程运行:

$ g++ --version && gcc -Wall -Wextra -pedantic -Werror ./main.c && ./a.out
g++ (Debian 6.3.0-18+deb9u1) 6.3.0 20170516
Copyright (C) 2016 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

p2 stdout:
user     3004534  0.0  0.0   4028   732 pts/14   S+   17:51   0:00 ./child.out
user     3004535  0.0  0.0  11176  2932 pts/14   S+   17:51   0:00 sh -c ps aux | grep child
user     3004537  0.0  0.0  12780   968 pts/14   S+   17:51   0:00 grep child

p.pid[3004534]
Step 63/63 : RUN ./a.out
 ---> Running in 7a355740577b
p2 stdout:
root           7  0.0  0.0   2384   760 ?        S    00:55   0:00 sh -c ./child.out
root           8  0.0  0.0   2384   760 ?        S    00:55   0:00 sh -c ps aux | grep child
root           9  0.0  0.0   2132   680 ?        S    00:55   0:00 ./child.out
root          11  0.0  0.0   3080   880 ?        S    00:55   0:00 grep child

p.pid[7]
…而在同一主机上的docker容器中,
sh
解析为
/bin/dash
,运行
a.out
表明
子.out
作为孙进程运行:

$ g++ --version && gcc -Wall -Wextra -pedantic -Werror ./main.c && ./a.out
g++ (Debian 6.3.0-18+deb9u1) 6.3.0 20170516
Copyright (C) 2016 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

p2 stdout:
user     3004534  0.0  0.0   4028   732 pts/14   S+   17:51   0:00 ./child.out
user     3004535  0.0  0.0  11176  2932 pts/14   S+   17:51   0:00 sh -c ps aux | grep child
user     3004537  0.0  0.0  12780   968 pts/14   S+   17:51   0:00 grep child

p.pid[3004534]
Step 63/63 : RUN ./a.out
 ---> Running in 7a355740577b
p2 stdout:
root           7  0.0  0.0   2384   760 ?        S    00:55   0:00 sh -c ./child.out
root           8  0.0  0.0   2384   760 ?        S    00:55   0:00 sh -c ps aux | grep child
root           9  0.0  0.0   2132   680 ?        S    00:55   0:00 ./child.out
root          11  0.0  0.0   3080   880 ?        S    00:55   0:00 grep child

p.pid[7]
我的问题是:在
a.out
的代码中,是否有一种方法可以提取执行命令的
pid\t
,从而抽象出实际命令是子进程还是子进程?

给出一些上下文:我希望能够杀死
child.out
。通过观察,在my
popen2()
生成子进程和孙进程的环境中,发送子进程a
SIGTERM
只杀死子进程,即sh-c child.out
,而不杀死孙进程,即
child.out
,这正是我真正想要杀死的


守则:

// main.c
#include <pthread.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

#define INVALID_FD (-1)
#define INVALID_PID (-1)

typedef enum PipeEnd {
  READ_END  = 0,
  WRITE_END = 1
} PipeEnd;

typedef int Pipe[2];

/** Encapsulates information about a created child process. */
typedef struct popen2_t {
  bool  success;  ///< true if the child process was spawned.
  Pipe  stdin;    ///< parent -> stdin[WRITE_END] -> child's stdin
  Pipe  stdout;   ///< child -> stdout[WRITE_END] -> parent reads stdout[READ_END]
  Pipe  stderr;   ///< child -> stderr[WRITE_END] -> parent reads stderr[READ_END]
  pid_t pid;      ///< child process' pid
} popen2_t;

/** dup2( p[pe] ) then close and invalidate both ends of p */
static void dupFd( Pipe p, const PipeEnd pe, const int fd ) {
  dup2( p[pe], fd);
  close( p[READ_END] );
  close( p[WRITE_END] );
  p[READ_END] = INVALID_FD;
  p[WRITE_END] = INVALID_FD;
}

/**
 * Redirect a parent-accessible pipe to the child's stdin, and redirect the
 * child's stdout and stderr to parent-accesible pipes.
 */
popen2_t popen2( const char* cmd ) {
  popen2_t r = { false,
    { INVALID_FD, INVALID_FD },
    { INVALID_FD, INVALID_FD },
    { INVALID_FD, INVALID_FD },
    INVALID_PID };

  if ( -1 == pipe( r.stdin ) ) { goto end; }
  if ( -1 == pipe( r.stdout ) ) { goto end; }
  if ( -1 == pipe( r.stderr ) ) { goto end; }

  switch ( (r.pid = fork()) ) {
    case -1: // Error
      goto end;

    case 0: // Child process
      dupFd( r.stdin, READ_END, STDIN_FILENO );
      dupFd( r.stdout, WRITE_END, STDOUT_FILENO );
      dupFd( r.stderr, WRITE_END, STDERR_FILENO );

      {
        char* argv[] = { (char*)"sh", (char*)"-c", (char*)cmd, NULL };

        if ( -1 == execvp( argv[0], argv ) ) { exit(0); }
      }
  }

  // Parent process
  close( r.stdin[READ_END] );
  r.stdin[READ_END] = INVALID_FD;
  close( r.stdout[WRITE_END] );
  r.stdout[WRITE_END] = INVALID_FD;
  close( r.stderr[WRITE_END] );
  r.stderr[WRITE_END] = INVALID_FD;
  r.success = true;

end:
  if ( ! r.success ) {
    if ( INVALID_FD != r.stdin[READ_END] ) { close( r.stdin[READ_END] ); }
    if ( INVALID_FD != r.stdin[WRITE_END] ) { close( r.stdin[WRITE_END] ); }
    if ( INVALID_FD != r.stdout[READ_END] ) { close( r.stdout[READ_END] ); }
    if ( INVALID_FD != r.stdout[WRITE_END] ) { close( r.stdout[WRITE_END] ); }
    if ( INVALID_FD != r.stderr[READ_END] ) { close( r.stderr[READ_END] ); }
    if ( INVALID_FD != r.stderr[WRITE_END] ) { close( r.stderr[WRITE_END] ); }

    r.stdin[READ_END] = r.stdin[WRITE_END] =
      r.stdout[READ_END] = r.stdout[WRITE_END] =
      r.stderr[READ_END] = r.stderr[WRITE_END] = INVALID_FD;
  }

  return r;
}

int main( int argc, char* argv[] ) {
  (void)argc;
  (void)argv;
  popen2_t p = popen2( "./child.out" );
  int status = 0;

  {
    char buf[4096] = { '\0' };
    popen2_t p2 = popen2( "ps aux | grep child" );
    waitpid( p2.pid, &status, 0 );

    read( p2.stdout[READ_END], buf, sizeof buf );
    printf( "p2 stdout:\n%s\n", buf );
  }

  printf( "p.pid[%d]\n", p.pid );

  {
    pid_t wpid = waitpid( p.pid, &status, 0 );

    return wpid == p.pid && WIFEXITED( status ) ? WEXITSTATUS( status ) : -1;
  }
}
//main.c
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#定义无效的\u FD(-1)
#定义无效的\u PID(-1)
typedef枚举管道端{
READ_END=0,
写入_END=1
}管道端;
类型定义内部管道[2];
/**封装有关已创建子进程的信息*/
typedef结构popen2\u t{
bool success;//<如果生成了子进程,则为true。
管道stdin;//stdin[WRITE_END]->子级的stdin
管道标准输出;//stdout[WRITE\u END]->父读取标准输出[READ\u END]
管道stderr;//stderr[WRITE\u END]->父读取stderr[READ\u END]
pid\u t pid;//<子进程'pid
}popen2_t;
/**dup2(p[pe]),然后关闭并使p的两端无效*/
静态空隙dupFd(管道p、常数管端pe、常数管端fd){
dup2(p[pe],fd);
关闭(p[READ_END]);
关闭(p[WRITE_END]);
p[READ\u END]=无效的\u FD;
p[WRITE\u END]=无效的\u FD;
}
/**
*将父级可访问管道重定向到子级的stdin,并重定向
*子级的标准输出和标准输出到父级可访问管道。
*/
popen2\u t popen2(const char*cmd){
popen2_t r={false,
{INVALID_FD,INVALID_FD},
{INVALID_FD,INVALID_FD},
{INVALID_FD,INVALID_FD},
无效的_-PID};
如果(-1==管道(r.stdin)){goto end;}
如果(-1==管道(r.stdout)){goto end;}
如果(-1==管道(r.stderr)){goto end;}
开关((r.pid=fork()){
案例1://错误
转到终点;
案例0://子进程
dupFd(r.stdin,READ_END,stdin_FILENO);
dupFd(r.stdout,WRITE_END,stdout_FILENO);
dupFd(r.stderr,WRITE_END,stderr_FILENO);
{
char*argv[]={(char*)“sh”,(char*)“-c”,(char*)cmd,NULL};
如果(-1==execvp(argv[0],argv)){exit(0);}
}
}
//父进程
关闭(r.stdin[READ_END]);
r、 stdin[READ\u END]=无效的\u FD;
关闭(r.stdout[WRITE_END]);
r、 stdout[WRITE\u END]=无效的\u FD;
关闭(r.stderr[WRITE_END]);
r、 stderr[WRITE\u END]=无效的\u FD;
r、 成功=真实;
完:
如果(!r.success){
if(INVALID_FD!=r.stdin[READ_END]){close(r.stdin[READ_END])}
if(INVALID_FD!=r.stdin[WRITE_END]){close(r.stdin[WRITE_END])}
if(INVALID_FD!=r.stdout[READ_END]){close(r.stdout[READ_END])}
if(INVALID_FD!=r.stdout[WRITE_END]){close(r.stdout[WRITE_END])}
if(INVALID_FD!=r.stderr[READ_END]){close(r.stderr[READ_END])}
if(INVALID_FD!=r.stderr[WRITE_END]){close(r.stderr[WRITE_END])}
r、 stdin[READ\u END]=r.stdin[WRITE\u END]=
r、 stdout[READ\u END]=r.stdout[WRITE\u END]=
r、 stderr[READ_END]=r.stderr[WRITE_END]=INVALID_FD;
}
返回r;
}
int main(int argc,char*argv[]){
(无效)argc;
(无效)argv;
popen2_t p=popen2(“/child.out”);
int status=0;
{
char buf[4096]={'\0'};
popen2_t p2=popen2(“ps aux|grep child”);
waitpid(p2.pid和status,0);
读取(p2.stdout[read_END],buf,sizeof buf);
printf(“p2标准输出:\n%s\n”,buf);
}
printf(“p.pid[%d]\n”,p.pid);
{
pid_t wpid=waitpid(p.pid和status,0);
返回wpid==p.pid&&WIFEXITED(状态)?WEXITSTATUS(状态):-1;
}
}
//child.c
#包括
#包括
#包括
int main(int argc,char*argv[]){
char buf[128]={'\0'};
snprintf(buf,sizeof buf,“%s:%d\n”、\uuuuuu文件、\uuuu行);
写入(标准文件号、buf、strlen(buf));
睡眠(1);
snprintf(buf,sizeof buf,“%s:%d\n”、\uuuuuu文件、\uuuu行);
写入(标准文件号、buf、strlen(buf));
睡眠(1);
snprintf(buf,sizeof buf,“%s:%d\n”、\uuuuuu文件、\uuuu行);
写入(标准文件号、buf、strlen(buf));
睡眠(1);
snprintf(buf,sizeof buf,“%s:%d\n”、\uuuuuu文件、\uuuu行);
写入(标准文件号、buf、strlen(buf));
睡眠(1);
返回0;
}

这是一个小问题