【发布时间】:2015-12-18 11:30:33
【问题描述】:
我想知道rm 命令在Linux 中是如何工作的。它调用了哪些系统调用?执行该命令使用了哪些文件操作?
对不起,如果我的问题看起来微不足道,但我是 Linux 文件系统的新手。
【问题讨论】:
我想知道rm 命令在Linux 中是如何工作的。它调用了哪些系统调用?执行该命令使用了哪些文件操作?
对不起,如果我的问题看起来微不足道,但我是 Linux 文件系统的新手。
【问题讨论】:
【讨论】:
您可能知道,rm 工具是开源的,它是core-utils 软件包的一部分。此后,您可以阅读rm 的实现,例如GitHub mirror 或here。
【讨论】:
rm 命令由coreutils 提供。 rm.c 是 driver 程序的来源。 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 系统调用。
【讨论】:
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 版本。
【讨论】:
它调用unlink(2) 来删除文件系统对象。从那里发生的任何事情都委托给文件系统驱动程序。
【讨论】: