0

我对 c 中的 execlp() 有疑问。

我有以下程序:

#include <stdio.h>
#include <unistd.h>
#include <sys/unistd.h>
#include <sys/types.h>
#include <pwd.h>
#include <stdlib.h>
#include <limits.h>
#include <signal.h>

void INThandler(int);

int main(int argc, char* argv[]) {

  struct passwd *pwd;
  char *lgn;
  char *cwd;
  char buff[PATH_MAX + 1];
  char  s1[10], s2[10];

  /*Um den Namen zu bekommen*/
  lgn = getlogin();
  pwd = getpwnam(lgn);

  /*Um den Hostnamen zu bekommen*/
  char hostname[128];
  gethostname(hostname, sizeof hostname);

  /*Um das Arbeitsverzeichnis zu bekommen*/
  cwd = getcwd(buff, PATH_MAX + 1);
  if((cwd!=NULL)&& hostname!=NULL  && ((lgn=getlogin())!=NULL ||
(pwd!=NULL)))
    {
      signal(SIGINT, INThandler);
      while(1)
        {
          printf("%s@%s %s$", pwd->pw_name, hostname, cwd);
          if(scanf("%s %s",s1, s2)<1)
            return 1;
          printf("Befehl: %s\nArgument: %s\n",s1,s2);
          execlp(s1, s1, NULL);
          printf("Zhopa");
          return 1;
        }

    }
  return 0;
}

void INThandler(int sig) {
  char c;

  signal(sig, SIG_IGN);
  printf("Wollen Sie Program Verlassen? [y/n]");

  c = getchar();
  if(c == 'y' || c=='Y')
    exit(0);
  else
    signal(SIGINT, INThandler);
  getchar();
}

它应该打印用户名@hostname 文件夹$,然后将 linux 命令作为参数“ls -al”,然后它应该使用 execlp() 启动它,但它不像我认为的那样工作。

我在这里阅读了有关此命令的所有文章,但我想,我仍然不明白如何使用它。

我会很感激有人的帮助。

4

2 回答 2

1

您的信号处理程序调用未定义的行为。

您只能从信号处理程序中调用异步信号安全函数。 根据 POSIX 标准

...行为未定义...如果信号处理程序调用本标准中定义的任何函数,而不是下表中列出的函数之一。

下表定义了一组异步信号安全的功能。因此,应用程序可以不受限制地从信号捕获函数中调用它们。...

[异步信号安全功能表]

上表中没有的任何功能都可能对信号不安全。...

此信号处理程序

void INThandler(int sig) {
  char c;

  signal(sig, SIG_IGN);
  printf("Wollen Sie Program Verlassen? [y/n]");

  c = getchar();
  if(c == 'y' || c=='Y')
    exit(0);
  else
    signal(SIGINT, INThandler);
  getchar();
}

其中有多个非异步信号安全功能:

  • printf()
  • getchar()
  • exit()

不能从信号处理程序中安全地调用这些函数。

给定您的代码,调用此信号处理程序的可能位置是当进程被阻止时scanf()- 尝试从stdin. 这可能涉及某种锁或互斥锁。然而,您的信号处理程序调用getchar()也试图从 读取stdin,它可能被锁定或处于某种不确定的状态。如果主线程被阻塞scanf(),信号处理程序中的异步调用getchar()可能会死锁或破坏用于stdin.

于 2017-05-14T11:08:11.910 回答
1

您必须使用 a 创建一个新进程,fork()然后在新进程(子进程)中使用execlp. 这是示例代码。它不处理任何错误,它仅适用于具有恰好 1 个参数的命令,因为这就是我所理解的(例如ls -all

#include <stdio.h>
#include <unistd.h>
#include <sys/unistd.h>
#include <sys/wait.h> /*Lib for waitpid*/
#include <sys/types.h>
#include <pwd.h>
#include <stdlib.h>
#include <limits.h>
#include <signal.h>

void INThandler(int);

int main(int argc, char* argv[]) {

  int pid = 0; /*PROCESS ID*/
  struct passwd *pwd;
  char *lgn;
  char *cwd;
  char buff[PATH_MAX + 1];
  char  s1[10], s2[10];

  /*Um den Namen zu bekommen*/
  lgn = getlogin();
  pwd = getpwnam(lgn);

  /*Um den Hostnamen zu bekommen*/
  char hostname[128];
  gethostname(hostname, sizeof hostname);

  /*Um das Arbeitsverzeichnis zu bekommen*/
  cwd = getcwd(buff, PATH_MAX + 1);
  if((cwd!=NULL)&& hostname!=NULL  && ((lgn=getlogin())!=NULL ||
(pwd!=NULL)))
    {
      signal(SIGINT, INThandler);
      while(1)
        {
          printf("%s@%s %s$", pwd->pw_name, hostname, cwd);
          if(scanf("%s %s",s1, s2)<1)
            return 1;
          printf("Befehl: %s\nArgument: %s\n",s1,s2);
          pid = fork();
          if(pid == 0){ /*Child*/
            execlp(s1, s1, s2,(char*) NULL);
          }else if(pid > 0){ /*Father*/
            /*father waiting for the child*/
            waitpid(pid,NULL,0); 
          }
          printf("Zhopa");
        }

    }
  return 0;
}

void INThandler(int sig) {
  char c;

  signal(sig, SIG_IGN);
  printf("Wollen Sie Program Verlassen? [y/n]");

  c = getchar();
  if(c == 'y' || c=='Y')
    exit(0);
  else
    signal(SIGINT, INThandler);
  getchar();
}
于 2017-05-14T11:01:23.993 回答