как написать функцию cp (в linux оболочке) в c ++, которая работает в фоновом режиме? - PullRequest
0 голосов
/ 05 мая 2020

Я пытаюсь написать свою собственную небольшую linux оболочку, и я хочу написать функцию cp, формат функции такой:

cp <old-file-path> <new-file-path>

Копирует первый файл во второй файл (перезаписывая его), и если второй файл не существует, он создаст новый. Если файлы не открываются или какой-либо системный вызов завершился неудачно, будет выведено сообщение об ошибке. Однако иногда мне нужно скопировать большие файлы, поэтому я хочу запустить эту команду cp в фоновом режиме (используя fork, не дожидаясь завершения sh).

Моя проблема: как можно Я использую fork и не жду завершения процесса sh? В настоящее время дочерний процесс становится процессом зомб ie.

Вот мой код:

// num_args contains the number of arguments sent to cp
class CopyCommand : public BuiltInCommand {
 public:
  CopyCommand(const char* cmd_line) : BuiltInCommand(cmd_line){}
  virtual ~CopyCommand() {}
  void execute() override{
      if(this->num_args < 1){  // if no arguments were send to cp
          perror("invalid arguments");
          return;
      }
      char* buff;
      int fd1 = open(args[1], O_RDONLY);   
      if(fd1 == -1){
            perror("open failed");
            return;
      }
      if(this->num_args==2){          // copy file1 into file2 (overrite file 1)
          int fd2 = open(args[2], O_TRUNC);
            if (fd2 == -1) {                // if we couldn't open the file then create a new one (not sure if we supposed to this ?)
                fd2 = open(args[2], O_CREAT, 0666);
                if (fd2 == -1) {
                    perror("open failed");
                    return;
                }
            }
          pid_t PID = fork();
          if(PID == -1){
              perror("fork failed");
              return;
          }
          else if(PID == 0){

             // i need to use fork here :( before i start to write
            int read_res = read(fd1, &buff, 1);  /// read from the file fd1 into fd2
            while (read_res != -1) {
                if (!read_res) {
                    break;
                }
                if (write(fd2, buff, 1) == -1) {
                    perror("write failed");
                }
                read_res = read(fd1, buff, 1);
            }
            if (read_res == -1) {
                perror("read failed");
            }     
}   
      }
      else if(this->num_args==1){               // create file2 and copy file1 into file2

          // don't know how to do this yet 
          // i need to use fork here :(

      }
  }
};

1 Ответ

0 голосов
/ 06 мая 2020

Для начала немного переписал ваш код. В частности, обратите внимание, что дочерняя ветвь (PID == 0) завершается после завершения. Родитель закрывает переданные дескрипторы файлов после разветвления и в случае ошибки.

if (this->num_args == 2) {
    int fd1 = open(args[1], O_RDONLY);
    if (fd1 == -1) {
        perror("open failed");
        return;
    }

  int fd2 = open(args[2], O_TRUNC);
  if (fd2 == -1) {
    fd2 = open(args[2], O_CREAT, 0666);
    if (fd2 == -1) {
      perror("open failed");
      close(fd1);
      return;
    }
  }

  pid_t PID = fork();
  if (PID == -1) {
    perror("fork failed");
  } else if (PID == 0) {
    char buff[1024];
    int read_res = read(fd1, &buff, 1024); /// read from the file fd1 into fd2
    while (read_res != -1) {
      if (!read_res) {
        break;
      }
      if (write(fd2, buff, read_res) == -1) {
        perror("write failed");
      }
      read_res = read(fd1, buff, 1024);
    }
    if (read_res == -1) {
      perror("read failed");
    }
    exit(0);
  } else {
    printf("Copy running in background (pid: %d)\n", PID);
  }

  close(fd1);
  close(fd2);
  return
}

Когда дочерний процесс вызывает exit, процесс остается в состоянии «Zomb ie». Это состояние позволяет родительскому процессу (вам) вызывать wait или waitpid для получения кода выхода.

В качестве вторичного эффекта завершения процесса ядро ​​отправит SIGCHLD вашему процессу , чтобы вы знали, что вы действительно можете позвонить по номеру wait без блокировки. В вашей ситуации вам не важен код выхода, поэтому вы можете настроить обработчик сигнала «безразлично» в начале своей программы и позволить ядру очистить процесс:

signal(SIGCHLD, SIG_IGN);

Это задокументировано в signal (2):

Если процесс явно указывает SIG_IGN как действие для сигнала SIGCHLD, система не будет создавать процессы-зомбы ie при выходе дочерних процессов вызывающего процесса . Как следствие, система отбросит статус выхода из дочерних процессов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...