简体   繁体   English

Linux中的“ rm”命令如何工作?

[英]How “rm” command in Linux works?

I want to know how the rm command works in Linux. 我想知道rm命令在Linux中如何工作。 What system calls does it invoke? 它调用什么系统调用? Which file operations are used to execute this command? 哪些文件操作用于执行此命令?

Sorry if my question looks trivial, but I'm new to Linux file systems. 抱歉,我的问题看似微不足道,但是我是Linux文件系统的新手。

Questions like this should be easily be answerable by strace(1) : 像这样的问题应该可以通过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 +++

The decisive call in my case is unlinkat(AT_FDCWD, "test", 0) but the specifics probably depend on the system architecture and rm version. 在我unlinkat(AT_FDCWD, "test", 0)决定性的调用是unlinkat(AT_FDCWD, "test", 0)但具体细节可能取决于系统架构和rm版本。

Expanding on ignacio's answer unlink(2) is the primary system call that it will make to actually remove files, and rmdir(2) to remove directories, but there are other system calls that it makes as well including: 扩展ignacio的答案unlink(2)是它将实际删除文件的主要系统调用,并使用rmdir(2)删除目录,但是它也进行了其他系统调用,包括:

For the complete source of the implementation in OpenBSD see http://bxr.su/openbsd/bin/rm/rm.c 有关OpenBSD中实施的完整信息,请参见http://bxr.su/openbsd/bin/rm/rm.c。

It invokes unlink(2) to remove the filesystem object. 它调用unlink(2)删除文件系统对象。 Whatever happens from there is delegated to the filesystem driver. 从那里发生的任何事情都委托给文件系统驱动程序。

The rm command is provided by coreutils . rm命令由coreutils提供。 rm.c is the source for the driver program. rm.c驱动程序的源。 remove.c does the actual work. remove.c做实际的工作。 In particular, excise is what you're looking for: 特别是, 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;
}

As you can see, it uses the unlinkat syscall. 如您所见,它使用unlinkat syscall。

As you possbily know, rm tool is open source and it is part of core-utils package. 如您所知, rm工具是开源的,它是core-utils软件包的一部分。 Henceforth, you can read the implementation of rm , for example, on GitHub mirror or here . 从此以后,您可以阅读rm的实现,例如,在GitHub mirrorhere

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM