Использование системных вызовов для реализации команды unix cat - PullRequest
4 голосов
/ 05 октября 2010

Для моего класса ОС у меня есть назначение реализации команды Unix cat с системными вызовами (без scanf или printf).Вот что я получил до сих пор:

(отредактировано благодаря ответам)

#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>



main(void)
{


   int fd1; 
   int fd2;

   char *buffer1;
   buffer1 = (char *) calloc(100, sizeof(char));


   char *buffer2;
   buffer2 = (char *)calloc(100, sizeof(char));

   fd1 = open("input.in", O_RDONLY);    
   fd2 = open("input2.in", O_RDONLY);


   while(eof1){ //<-lseek condition to add here
   read (fd1, buffer1, /*how much to read here?*/ );
   write(1, buffer1, sizeof(buffer1)-1);     
   }


   while (eof2){ 

    read (fd2,buffer2, /*how much to read here?*/);  
    write(1, buffer2, sizeof(buffer2)-1);

    }

}

Примеры, которые я видел, показывают только чтение с известным числом байтов.Я не знаю, сколько байтов будет у каждого из прочитанных файлов, так как мне указать последний параметр чтения?

Ответы [ 5 ]

4 голосов
/ 05 октября 2010
  • Прежде чем вы сможете read в буфер, вы должны выделить его.В стеке (самый простой) или с mmap.
  • perror - это сложная библиотечная функция, а не системный вызов.
  • exit не является системным вызовом в Linux.Но _exit - это.
  • Не write больше байтов, чем у вас было read до.
  • Или, вообще: прочтите документацию по всем этим системным вызовам.*

Редактировать: Вот мой код, использующий только системные вызовы.Обработка ошибок несколько ограничена, так как я не хотел повторно реализовывать perror.

#include <fcntl.h>
#include <unistd.h>

static int
cat_fd(int fd) {
  char buf[4096];
  ssize_t nread;

  while ((nread = read(fd, buf, sizeof buf)) > 0) {
    ssize_t ntotalwritten = 0;
    while (ntotalwritten < nread) {
      ssize_t nwritten = write(STDOUT_FILENO, buf + ntotalwritten, nread - ntotalwritten);
      if (nwritten < 1)
        return -1;
      ntotalwritten += nwritten;
    }
  }

  return nread == 0 ? 0 : -1;
}

static int
cat(const char *fname) {
  int fd, success;

  if ((fd = open(fname, O_RDONLY)) == -1)
    return -1;

  success = cat_fd(fd);

  if (close(fd) != 0)
    return -1;

  return success;
}


int
main(int argc, char **argv) {
  int i;

  if (argc == 1) {
    if (cat_fd(STDIN_FILENO) != 0)
      goto error;
  } else {
    for (i = 1; i < argc; i++) {
      if (cat(argv[i]) != 0)
        goto error;
    }
  }
  return 0;

error:
  write(STDOUT_FILENO, "error\n", 6);
  return 1;
}
3 голосов
/ 05 октября 2010

Вам нужно прочитать столько байтов, сколько поместится в буфере. Прямо сейчас у вас нет буфера, все, что у вас есть, это указатель на буфер. Это не инициализировано ни к чему. Цыпленок и яйцо, поэтому вы не знаете, сколько байтов прочитать.

Создать буфер.

2 голосов
/ 05 октября 2010

Вы можете использовать open, fstat, mmap, madvise и write, чтобы создать очень эффективную команду cat.

Если вы используете Linux, вы можетеиспользуйте open, fstat, fadvise и splice, чтобы сделать еще более эффективную команду cat.

Вызовы advise должны указать флаги SEQUENTIAL, которые сообщат ядру, чтобы они выполняли агрессивное чтение.вперед по делу.

Если вы хотите быть вежливыми с остальной частью системы и минимизировать использование буферного кэша, вы можете сделать свою копию кусками по 32 мегабайта или около того и использовать флаги advise DONTNEED на деталяхуже прочитано.

Примечание:

Вышеуказанное будет работать, только если источником является файл.Если fstat не может предоставить размер, вы должны использовать выделенный буфер и read, write.Вы также можете использовать splice.

2 голосов
/ 05 октября 2010

Обычно нет необходимости читать весь файл одним глотком.Хороший способ выбрать размер буфера, равный или кратный размеру страницы памяти операционной системы хоста.1 или 2 X размер страницы, вероятно, достаточно хорош.

Использование слишком больших буферов может фактически привести к ухудшению работы вашей программы, поскольку они оказывают давление на систему виртуальной памяти и могут вызывать подкачку.

1 голос
/ 05 октября 2010

Используйте функцию stat , чтобы определить размер ваших файлов, прежде чем читать их. Кроме того, вы можете читать куски, пока не получите EOF.

...