c - 如何编写一个 C 程序,在调用时运行另一个给定程序并尝试控制子进程的行为

标签 c linux

下午好,我的目标是编写一个 C 程序,在调用时运行另一个给定程序并尝试控制子进程的行为。

如果子进程打开任何文件(除了预先打开的文件 stdin、stdout、stderr 之外),应防止这种情况发生并终止程序。

我编写了以下程序来实现上述程序要求。好消息是,只有当我从 KITTY session 重新启动 LINUX 操作系统后运行我的程序时,我的程序才会始终拦截子程序打开任何文件(除了预先打开的文件 stdin、stdout、stderr 之外)时生成的 SIGIO 信号。 问题是,我的程序第一次成功运行后,后续尝试拦截 SIGIO 信号时会失败。请告诉我我的程序中做错了什么以及如何修复它。

#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/shm.h>
#include <sys/mman.h>
#include <errno.h>
#include <semaphore.h>
#include <sys/sysinfo.h>
#include <pthread.h>
#include <sys/ptrace.h>

#define MAXLINE 256
#define MAXARGS 128
#define SHELL   "/h/fchang03" 
#define READ 0
#define WRITE 1

pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;
int fd[2];
pthread_spinlock_t spinlock;

struct statStuff {
    int pid;                    // %d 
    char comm[256];             // %s
    char state;                 // %c
    int ppid;                   // %d
    int pgrp;                   // %d
    int session;                // %d
    int tty_nr;                 // %d
    int tpgid;                  // %d
    unsigned long flags;        // %lu
    unsigned long minflt;       // %lu
    unsigned long cminflt;      // %lu
    unsigned long majflt;       // %lu
    unsigned long cmajflt;      // %lu
    unsigned long utime;        // %lu
    unsigned long stime;        // %lu
    long cutime;                // %ld
    long cstime;                // %ld
    long priority;              // %ld
    long nice;                  // %ld
    long num_threads;           // %ld
    long itrealvalue;           // %ld
    unsigned long starttime;    // %lu
    unsigned long vsize;        // %lu
    long rss;                   // %ld
    unsigned long rlim;         // %lu
    unsigned long startcode;    // %lu
    unsigned long endcode;      // %lu
    unsigned long startstack;   // %lu
    unsigned long kstkesp;      // %lu
    unsigned long kstkeip;      // %lu
    unsigned long signal;       // %lu
    unsigned long blocked;      // %lu
    unsigned long sigignore;    // %lu
    unsigned long sigcatch;     // %lu
    unsigned long wchan;        // %lu
    unsigned long nswap;        // %lu
    unsigned long cnswap;       // %lu
    int exit_signal;            // %d
    int processor;              // %d
    unsigned long rt_priority;  // %lu 
    unsigned long policy;       // %lu 
    unsigned long long delayacct_blkio_ticks;   // %llu 
} ;

static int readStat(int pid, struct statStuff *s) {

    const char *format = "%d %s %c %d %d %d %d %d %lu %lu %lu %lu %lu %lu %lu %ld %ld %ld %ld %ld %ld %lu %lu %ld %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %d %d %lu %lu %llu";

    char buf[256];
    FILE *proc;
    sprintf(buf,"/proc/%d/stat",pid);
    proc = fopen(buf,"r");
    if (proc) {
        if (42==fscanf(proc, format,
            &s->pid,
            s->comm,
            &s->state,
            &s->ppid,
            &s->pgrp,
            &s->session,
            &s->tty_nr,
            &s->tpgid,
            &s->flags,
            &s->minflt,
            &s->cminflt,
            &s->majflt,
            &s->cmajflt,
            &s->utime,
            &s->stime,
            &s->cutime,
            &s->cstime,
            &s->priority,
            &s->nice,
            &s->num_threads,
            &s->itrealvalue,
            &s->starttime,
            &s->vsize,
            &s->rss,
            &s->rlim,
            &s->startcode,
            &s->endcode,
            &s->startstack,
            &s->kstkesp,
            &s->kstkeip,
            &s->signal,
            &s->blocked,
            &s->sigignore,
            &s->sigcatch,
            &s->wchan,
            &s->nswap,
            &s->cnswap,
            &s->exit_signal,
            &s->processor,
            &s->rt_priority,
            &s->policy,
            &s->delayacct_blkio_ticks
        )) {
       printf("Group Number = %d\n",s->session);
       printf("Stack start = %x\n",s->startstack);
       printf("Stack end = %x\n",s->kstkesp);   
           fclose(proc);
           return s->session;
        } else {
           fclose(proc);
           return 0;
        }
     } else {
        return 0;
     }
}



int eval(const char *cmdline)
{
    char *argv[MAXARGS];
        int bg;
        pid_t pid;
        int status;
        struct statStuff test;
    int value;
    FILE* fp; 
        struct rusage usage; 

        pid = fork();
        if (pid > 0){ 
              /* This is the child process. */
              char* p;
              int num_procs;
              int n_bytes = 256;
              int bytes_read;
              char buffer[1024];    
              char stuff[256];          
              char* ptr;
                  struct rlimit rl;
              int x;

                      sscanf(cmdline,"%s %d",stuff,&x); 
              rl.rlim_cur = 15; 
              rl.rlim_max = 15;
                  setrlimit(RLIMIT_NPROC,&rl);      
                  ptr = 0;          
              if (x == 0){
                        sprintf(buffer,"/proc/%d/stat",pid); 
              }
              else{
            sprintf(buffer,"/proc/%d/stat",x);
                  }
              int fd  = open(buffer,O_RDONLY);
              while (read(fd,buffer,256) > 0){
                sprintf(cmdline,"%s %d",stuff,readStat(x,&test));
                printf("CMDLINE = %s\n",cmdline);
                eval(cmdline);
                            lseek(fd,256,SEEK_CUR);

              }   
                      close(fd);                      
                      wait3(&status,0,&usage);
              exit(1);  
          }
          else if (pid < 0){
              /* The fork failed. Report failure. */
              status = -1;  
          }
          else{
                      close(fd[READ]); 
                      close(fileno(stdout)); 
                  dup(fd[WRITE]);
                      fcntl(0,F_SETFL,O_ASYNC);
                      fcntl(1,F_SETFL,O_ASYNC);
                      fcntl(2,F_SETFL,O_ASYNC);
                      fcntl(3,F_SETFL,O_ASYNC);
              execl("/h/fchang03/five","five",0);
              perror("execl");             
              }
       return 0;    
}

void *reader(int signal)
{
    pid_t pid1,pid2;
    int status; 
    int fd[2];
    char buf[256];
    char buffer[256];   
    char filename[256];
    char dbgfilename[256];
    int myfd;
    int length;
    struct rusage usage;        

//    printf("SIGNAl  %d received\n",signal);
    printf("%s","                   ");

    length = 256;
    if (signal == 0){
    return NULL;
    }   

    pipe(fd);
    if ((pid1 = fork())) { /* child subprocess */ 
        pthread_spin_lock(&spinlock);
        sprintf(filename,"/proc/%d/fdinfo/1",pid1);
        myfd = open(filename,O_RDONLY);
        pthread_spin_unlock(&spinlock);
        if (myfd == -1){
                    printf("myfd = %d filename = %s\n",myfd,filename);
                        perror("myerror");
            exit(1);
        }
        fcntl(0,F_SETOWN,getpid());
                fcntl(1,F_SETOWN,getpid());
                fcntl(2,F_SETOWN,getpid());
        fcntl(3,F_SETOWN,getpid());
        if (signal == SIGIO){
            printf("SIGNAL SIGIO RECEIVED");
            kill(pid1,SIGKILL); 
        }
                close(myfd);
        close(fd[WRITE]);
            FILE *read = fdopen(fd[READ],"r");
            while (!feof(read)) {
                fgets(buf,256,read);
            }
        close(fd[READ]);
            pid2 = wait3(&status,0, &usage);
        if (signal == SIGKILL){
            exit(1);
        }
   }
   else {
        close(fd[READ]);
            close(fileno(stdout));
            dup(fd[WRITE]);
                //  child only unblock mask

                fcntl(0, F_SETFL, O_ASYNC);
        fcntl(1, F_SETFL, O_ASYNC);
        fcntl(2, F_SETFL, O_ASYNC);
        fcntl(3, F_SETFL, O_ASYNC);

                execl("/h/fchang03/five","five",NULL);

  }

}

int main(void)
{
     pthread_t tid1,tid2;
     char cmdline[MAXLINE];
     char temp[MAXLINE];    
     int start;

     struct sigaction set,myset;

     pthread_t thread;
     pthread_t thread2;

     sigemptyset(&set);
     sigemptyset(&myset);   
     memset(&set,0,sizeof(struct sigaction));
     memset(&myset,0,sizeof(struct sigaction));
     sigaddset(&set.sa_mask, SIGINT);
     sigaddset(&set.sa_mask, SIGCHLD);
     sigaddset(&set.sa_mask, SIGIO); 
     set.sa_flags = SA_RESTART | SA_NOCLDSTOP | SA_SIGINFO;
     set.sa_handler = reader;  

     sigaddset(&myset.sa_mask, SIGIO);       
     myset.sa_flags = SA_RESTART | SA_NOCLDSTOP | SA_SIGINFO;
     myset.sa_handler  = reader;  

     sigprocmask(SIG_UNBLOCK, &myset, &set); // later explicitly just unblock SIGIO 
     sigaction(SIGCHLD,&myset,&set);    
     sigaction(SIGIO,&myset,&set);

     pthread_spin_init(&spinlock, 0);
     pthread_create(&tid1,NULL,reader,NULL);
     pthread_create(&tid2,NULL,reader,NULL);

     pthread_join(tid1,NULL);
     pthread_join(tid2,NULL);


     start = 0; 
     while (1){
          printf("> ");
          fgets(temp, MAXLINE, stdin);
          sprintf(cmdline,"./%s %d",temp,start);
              if (feof(stdin)){
                 exit(0);   
              }
          if (eval(cmdline) == -1){
              break;
          }     
     }  

}

最佳答案

当我修改信号处理程序和线程仿函数函数时,读者,我现在每次都可以拦截 SIGIO 和关联的 SIGCHLD 信号。谢谢,弗兰克

void *reader(int signal)
{
    pid_t pid1,pid2;
    int status;
    int fd[2];
    char buf[256];
    char buffer[256];
    char filename[256];
    char dbgfilename[256];
    int myfd;
    int length;
    struct rusage usage;

//    printf("SIGNAl  %d received\n",signal);
    printf("%s","                   ");

    length = 256;
    if (signal == 0){
        return NULL;
    }

    pipe(fd);
    if ((pid1 = fork())) { /* child subprocess */
                pthread_spin_lock(&spinlock);
                sprintf(filename,"/proc/%d/fdinfo/1",pid1);
                myfd = open(filename,O_RDONLY);
                pthread_spin_unlock(&spinlock);
                if (myfd == -1){
                        printf("myfd = %d filename = %s\n",myfd,filename);
                        perror("myerror");
                        exit(1);
                }
                fcntl(0,F_SETOWN,getpid());
                fcntl(1,F_SETOWN,getpid());
                fcntl(2,F_SETOWN,getpid());
                fcntl(3,F_SETOWN,getpid());
                if (signal == SIGIO || signal == SIGCHLD){
                        printf("SIGNAL SIGIO RECEIVED");
                        kill(pid1,SIGKILL);
                }
                close(myfd);
      close(fd[WRITE]);
                FILE *read = fdopen(fd[READ],"r");
                while (!feof(read)) {
                        fgets(buf,256,read);
                }
                close(fd[READ]);
                pid2 = wait3(&status,0, &usage);
                exit(1);
   }
   else {
                close(fd[READ]);
                close(fileno(stdout));
                dup(fd[WRITE]);
                //  child only unblock mask

                fcntl(0, F_SETFL, O_ASYNC);
                fcntl(1, F_SETFL, O_ASYNC);
                fcntl(2, F_SETFL, O_ASYNC);
                fcntl(3, F_SETFL, O_ASYNC);

                execl("/h/fchang03/five","five",NULL);

  }
}

关于c - 如何编写一个 C 程序,在调用时运行另一个给定程序并尝试控制子进程的行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19643699/

相关文章:

c - 如何计算 OS X 上 Go 程序中的系统调用?

c - char 字符串数组元素的大小是多少?

c - C中的图遍历

JAVA 运行时错误 :Unsupported major. 次要版本 51.0

c - 在未设置 _POSIX_SAVED_IDS 的情况下使用 setreuid()

c - tid状态变化时获取信号

php - 如何使用 semanage 递归地获取持久化特定文件类型

linux - 无法使用本地 IP 从本地计算机访问 Eclipse Orion 服务器

linux - 两个表如何使用存储库加入 symfony 2.8

linux - CSV 文件 bash 脚本中的平均值