mmap 无效参数 - 从命令行读取多个文件并写入一个输出文件

mmap invalid argument - reading multiple files from command line and writing to one output file

我正在编写一个 C 程序,它从命令行获取多个文件并将它们组合成一个输出文件。如果未给出输出文件,则创建它。我使用 mmap 复制文件内容。

但是,当我 运行 以下代码时,我得到“mmap:无效参数”,我不确定为什么。

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

int main(int argc, char *argv[])
{
  int opt, output=0, len; 
  int fd_o, fd_i;
  char *addr=NULL;
  struct stat stat_input;
  const char *errmsg="Invalid argument:\n";
  const char *usage=
      "combine to one\n";

  while((opt = getopt(argc, argv, "o"))!= -1) {
      switch(opt){
      case 'o': 
        output=1;
        fd_o=open(argv[argc-1], O_WRONLY|O_CREAT|O_TRUNC, 0644);
        if (fd_o == -1){
          perror("open");
          exit(1);
        }
        break;
      case '?':
        write(2, errmsg, strlen(errmsg));
        write(2, usage, strlen(usage));
        exit(1);
    }
  }

  if (output==0){
    write(2, errmsg, strlen(errmsg));
    write(2, usage, strlen(usage));
    exit(1);
  }
 
  for(; optind < argc; optind++){
    fd_i=open(argv[optind], O_RDONLY);
    if (fd_i == -1){
      perror("open");
      exit(1);
}

    fstat(fd_i, &stat_input);
    len=stat_input.st_size;
    addr=mmap(0, len, PROT_READ, MAP_SHARED, fd_i, 0);
    if (addr == MAP_FAILED) {
      close(fd_i);
      perror("mmap");
      exit(1);
    }
    write(fd_o, *addr, len);
    close(fd_i);
    munmap(addr,len);
  }
  close(fd_o);
}

我认为问题实际上是您的选项解析。就目前而言,如果完全指定了 -o,则始终使用最后一个参数作为输出文件。因此,如果您 运行 ./myprog f1 f2 -o out,那么所有 f1, f2, out 都将用作输入文件。如果你 运行 ./myprog -o out f1 f2 那么所有 out, f1, f2 都将是输入,输出将转到 f2.

我假设您不希望使用输出文件作为输入,如果它是空的,您将尝试创建一个长度为 0 的映射,这将因“无效参数”而失败。我猜这是你的问题的原因。

使用getopt处理带参数的选项的正确方法是使用"o:"作为选项字符串,然后当getopt returns 'o',变量optarg将指向选项的参数;这就是您应该用作输出文件名而不是 argv[argc-1].

其他几个错误:

  • write(fd_o, *addr, len); 应该是 write(fd_o, addr, len); 因为 write 需要一个指向其数据的指针。你应该得到一个关于这个的编译器警告。

  • 您需要在调用 mmap 之前测试 len != 0 以防有人真的 运行 在空输入文件上执行该程序。

  • 我不确定您为什么使用 write() 而不是 fprintf(stderr, ...) 作为您的用法消息。如果由于某种原因 stdio 函数不可接受(即使您似乎对其他地方的 perror() 没有问题),那么标准函数 dprintf 可能会让您的生活更轻松一些。

来自手册页 mmap()

void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);

EINVAL(无效参数错误)的可能原因:

    1) We don't like addr, length, or offset (e.g., they are too large, or not aligned on a page boundary).

    2) (since Linux 2.6.12) length was 0.

    3) flags contained none of MAP_PRIVATE, MAP_SHARED or MAP_SHARED_VALIDATE.

我认为 len = stat_input.st_size; 中的 len 为零。这可能是原因。