我想知道{{1}}命令在Linux中是如何工作的。它调用了什么系统调用?使用哪些文件操作来执行此命令?
很抱歉,如果我的问题看起来微不足道,但我是Linux文件系统的新手。
答案 0 :(得分:2)
这样的问题应该很容易被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
版本。
答案 1 :(得分:1)
您可以在此处阅读源代码:
实际删除文件发生在:
答案 2 :(得分:1)
扩展ignacio的回答unlink(2)
是实际删除文件的主要系统调用,rmdir(2)
删除目录,但还有其他系统调用包括:
有关OpenBSD中实现的完整源代码,请参阅http://bxr.su/openbsd/bin/rm/rm.c
答案 3 :(得分:0)
它调用unlink(2)
来删除文件系统对象。无论从那里发生什么都委托给文件系统驱动程序。
答案 4 :(得分:0)
rm
命令由coreutils提供。 rm.c
是驱动程序程序的来源。 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 :(得分:0)
正如您可能知道的那样,rm
工具是开源的,它是core-utils
包的一部分。此后,您可以在GitHub mirror或here上阅读rm
的实施。