【问题标题】:How "rm" command in Linux works?Linux中的“rm”命令如何工作?
【发布时间】:2015-12-18 11:30:33
【问题描述】:

我想知道rm 命令在Linux 中是如何工作的。它调用了哪些系统调用?执行该命令使用了哪些文件操作?

对不起,如果我的问题看起来微不足道,但我是 Linux 文件系统的新手。

【问题讨论】:

    标签: linux file command


    【解决方案1】:

    扩展 ignacio 的答案 unlink(2) 是它实际删除文件和 rmdir(2) 删除目录的主要系统调用,但它还进行其他系统调用,包括:

    有关 OpenBSD 中实现的完整源代码,请参阅http://bxr.su/openbsd/bin/rm/rm.c

    【讨论】:

      【解决方案2】:

      【讨论】:

        【解决方案3】:

        您可能知道,rm 工具是开源的,它是core-utils 软件包的一部分。此后,您可以阅读rm 的实现,例如GitHub mirrorhere

        【讨论】:

          【解决方案4】:

          rm 命令由coreutils 提供。 rm.cdriver 程序的来源。 remove.c 做实际工作。特别是,excise 是您要查找的内容:

          /* Remove the file system object specified by ENT.  IS_DIR specifies
             whether it is expected to be a directory or non-directory.
             Return RM_OK upon success, else RM_ERROR.  */
          static enum RM_status
          excise (FTS *fts, FTSENT *ent, struct rm_options const *x, bool is_dir)
          {
            int flag = is_dir ? AT_REMOVEDIR : 0;
            if (unlinkat (fts->fts_cwd_fd, ent->fts_accpath, flag) == 0)
              {
                if (x->verbose)
                  {
                    printf ((is_dir
                             ? _("removed directory: %s\n")
                             : _("removed %s\n")), quote (ent->fts_path));
                  }
                return RM_OK;
              }
          
            /* The unlinkat from kernels like linux-2.6.32 reports EROFS even for
               nonexistent files.  When the file is indeed missing, map that to ENOENT,
               so that rm -f ignores it, as required.  Even without -f, this is useful
               because it makes rm print the more precise diagnostic.  */
            if (errno == EROFS)
              {
                struct stat st;
                if ( ! (lstatat (fts->fts_cwd_fd, ent->fts_accpath, &st)
                                 && errno == ENOENT))
                  errno = EROFS;
              }
          
            if (ignorable_missing (x, errno))
              return RM_OK;
          
            /* When failing to rmdir an unreadable directory, the typical
               errno value is EISDIR, but that is not as useful to the user
               as the errno value from the failed open (probably EPERM).
               Use the earlier, more descriptive errno value.  */
            if (ent->fts_info == FTS_DNR)
              errno = ent->fts_errno;
            error (0, errno, _("cannot remove %s"), quote (ent->fts_path));
            mark_ancestor_dirs (ent);
            return RM_ERROR;
          }
          

          如您所见,它使用unlinkat 系统调用。

          【讨论】:

            【解决方案5】:

            strace(1) 应该可以轻松回答此类问题:

            $ touch test
            $ strace rm test
            execve("/usr/bin/rm", ["rm", "test"], [/* 26 vars */]) = 0
            brk(0)                                  = 0xb86000
            mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fabf8423000
            access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
            open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
            fstat(3, {st_mode=S_IFREG|0644, st_size=45618, ...}) = 0
            mmap(NULL, 45618, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7fabf8417000
            close(3)                                = 0
            open("/lib64/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
            read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\0\34\2\0\0\0\0\0"..., 832) = 832
            fstat(3, {st_mode=S_IFREG|0755, st_size=2107760, ...}) = 0
            mmap(NULL, 3932736, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fabf7e42000
            mprotect(0x7fabf7ff8000, 2097152, PROT_NONE) = 0
            mmap(0x7fabf81f8000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1b6000) = 0x7fabf81f8000
            mmap(0x7fabf81fe000, 16960, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7fabf81fe000
            close(3)                                = 0
            mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fabf8416000
            mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fabf8414000
            arch_prctl(ARCH_SET_FS, 0x7fabf8414740) = 0
            mprotect(0x7fabf81f8000, 16384, PROT_READ) = 0
            mprotect(0x60d000, 4096, PROT_READ)     = 0
            mprotect(0x7fabf8424000, 4096, PROT_READ) = 0
            munmap(0x7fabf8417000, 45618)           = 0
            brk(0)                                  = 0xb86000
            brk(0xba7000)                           = 0xba7000
            brk(0)                                  = 0xba7000
            open("/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3
            fstat(3, {st_mode=S_IFREG|0644, st_size=106065056, ...}) = 0
            mmap(NULL, 106065056, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7fabf191b000
            close(3)                                = 0
            open("/usr/share/locale/locale.alias", O_RDONLY|O_CLOEXEC) = 3
            fstat(3, {st_mode=S_IFREG|0644, st_size=2502, ...}) = 0
            mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fabf8422000
            read(3, "# Locale name alias data base.\n#"..., 4096) = 2502
            read(3, "", 4096)                       = 0
            close(3)                                = 0
            munmap(0x7fabf8422000, 4096)            = 0
            open("/usr/lib/locale/UTF-8/LC_CTYPE", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
            ioctl(0, SNDCTL_TMR_TIMEBASE or SNDRV_TIMER_IOCTL_NEXT_DEVICE or TCGETS, {B38400 opost isig icanon echo ...}) = 0
            newfstatat(AT_FDCWD, "test", {st_mode=S_IFREG|0664, st_size=0, ...}, AT_SYMLINK_NOFOLLOW) = 0
            geteuid()                               = 7026
            newfstatat(AT_FDCWD, "test", {st_mode=S_IFREG|0664, st_size=0, ...}, AT_SYMLINK_NOFOLLOW) = 0
            faccessat(AT_FDCWD, "test", W_OK)       = 0
            unlinkat(AT_FDCWD, "test", 0)           = 0
            lseek(0, 0, SEEK_CUR)                   = -1 ESPIPE (Illegal seek)
            close(0)                                = 0
            close(1)                                = 0
            close(2)                                = 0
            exit_group(0)                           = ?
            +++ exited with 0 +++
            

            就我而言,决定性的调用是unlinkat(AT_FDCWD, "test", 0),但具体情况可能取决于系统架构和rm 版本。

            【讨论】:

            • 谢谢。这很有帮助。我真的很感激:)
            【解决方案6】:

            它调用unlink(2) 来删除文件系统对象。从那里发生的任何事情都委托给文件系统驱动程序。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2015-08-17
              • 2010-09-17
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2011-06-02
              • 2012-05-13
              相关资源
              最近更新 更多