linux的rm命令源碼
Linux下的rm命令是個(gè)刪除文件命令那么它的源代碼是怎樣的呢?下面由學(xué)習(xí)啦小編為大家整理了linux下rm命令源碼的相關(guān)知識,希望對大家有幫助!
linux的rm命令源碼分析
1.原因
想要在刪除文件前,先覆蓋文件內(nèi)容,防止他人恢復(fù)文件,從而得到文件原內(nèi)容;并且需要支持rm命令原本的參數(shù)選項(xiàng):
NAME rm - remove files or directoriesSYNOPSIS rm [OPTION]... FILE...Remove (unlink) the FILE(s). -f, --force ignore nonexistent files, never prompt -i prompt before every removal -I prompt once before removing more than three files, or when removing recursively. Less intru- sive than -i, while still giving protection against most mistakes ......
想來還是直接修改rm源文件比較方便,因而查看rm命令的源碼文件,在調(diào)用刪除系統(tǒng)調(diào)用前加入覆蓋文件內(nèi)容的操作,從而安全刪除文件,并且支持rm命令的參數(shù)選項(xiàng)。
2.獲取linux命令源碼
可以通過三條命令獲得命令的源代碼網(wǎng)址
which rm //得到文件的絕對路徑
rpm -qf 路徑 //獲取該命令所屬的軟件包名
rpm -qi 包名 //獲取包信息,包含網(wǎng)址URL信息
如下:
[ty@ty ~]$ which rm/bin/rm[ty@ty ~]$ rpm -qf /bin/rmcoreutils-8.4-19.el6.x86_64[ty@ty ~]$ rpm -qi coreutilsName : coreutils Relocations: (not relocatable)Version : 8.4 Vendor: Red Hat, Inc.Release : 19.el6 Build Date: Tue 17 Apr 2012 06:14:13 AM PDTInstall Date: Sun 04 Aug 2013 11:48:59 AM PDT Build Host: hs20-bc2-3.build.redhat.comGroup : System Environment/Base Source RPM: coreutils-8.4-19.el6.src.rpmSize : 12847030 License: GPLv3+Signature : RSA/8, Thu 19 Apr 2012 10:59:38 PM PDT, Key ID 199e2f91fd431d51Packager : Red Hat, Inc. <http://bugzilla.redhat.com/bugzilla>URL : http://www.gnu.org/software/coreutils/Summary : A set of basic GNU tools commonly used in shell scriptsDescription :These are the GNU core utilities. This package is the combination ofthe old GNU fileutils, sh-utils, and textutils packages.
linux的rm命令源碼
rm.c主函數(shù)main
rm命令函數(shù)調(diào)用流程:
man() -> rm() -> rm_fts() -> excise() -> unlinkat()
int main (int argc, char **argv){ bool preserve_root = true; struct rm_options x; bool prompt_once = false; int c; initialize_main (&argc, &argv); //初始化輸入?yún)?shù) set_program_name (argv[0]); //設(shè)置程序名 setlocale (LC_ALL, ""); bindtextdomain (PACKAGE, LOCALEDIR); textdomain (PACKAGE); /* 程序正常結(jié)束前調(diào)用的close_stdin函數(shù),關(guān)閉標(biāo)準(zhǔn)輸入; * 一個(gè)程序最多可以用atexit()注冊32個(gè)處理函數(shù),這些處理函數(shù)的 * 調(diào)用順序與其注冊順序相反。即就是先注冊的最后調(diào)用,最后調(diào)用的最先調(diào)用*/ atexit (close_stdin); rm_option_init (&x); //初始化rm選項(xiàng),即就是rm命令的參數(shù) /* Try to disable the ability to unlink a directory. */ priv_set_remove_linkdir (); /*試圖去禁用刪除目錄的功能,Try to remove priv from the effective set*/ while ((c = getopt_long (argc, argv, "dfirvIR", long_opts, NULL)) != -1) { switch (c) //switch語句主要是根據(jù)輸入?yún)?shù)選項(xiàng)設(shè)置刪除選項(xiàng) { case 'f': x.interactive = RMI_NEVER; x.ignore_missing_files = true; prompt_once = false; break; case 'i': x.interactive = RMI_ALWAYS; x.ignore_missing_files = false; prompt_once = false; break;
case 'r': case 'R': x.recursive = true; break; ...... case_GETOPT_HELP_CHAR; case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); default: diagnose_leading_hyphen (argc, argv); usage (EXIT_FAILURE); } } if (argc <= optind) /*參數(shù)小于等于optind,即就是沒有輸入要?jiǎng)h除的filename*/ { if (x.ignore_missing_files) /*指定了-f選項(xiàng)時(shí),直接退出,否則輸出信息提示用戶為指定操作對象*/ exit (EXIT_SUCCESS); else { error (0, 0, _("missing operand")); usage (EXIT_FAILURE); } } if (x.recursive && preserve_root) { static struct dev_ino dev_ino_buf; x.root_dev_ino = get_root_dev_ino (&dev_ino_buf); if (x.root_dev_ino == NULL) error (EXIT_FAILURE, errno, _("failed to get attributes of %s"), quote ("/")); } size_t n_files = argc - optind; /*n_files存儲命令行指定操作對象個(gè)數(shù),即就是要?jiǎng)h除文件個(gè)數(shù)(目錄視為一個(gè))*/ char **file = argv + optind; /*file存儲操作對象的索引*/ if (prompt_once && (x.recursive || 3 < n_files)) { fprintf (stderr, (x.recursive ? _("%s: remove all arguments recursively? ") : _("%s: remove all arguments? ")), program_name); if (!yesno ()) exit (EXIT_SUCCESS); } enum RM_status status = rm (file, &x); /*刪除文件,返回刪除狀態(tài)*/ assert (VALID_STATUS (status)); exit (status == RM_ERROR ? EXIT_FAILURE : EXIT_SUCCESS);}
rm()函數(shù)
/* Remove FILEs, honoring options specified via X. Return RM_OK if successful. */enum RM_statusrm (char *const *file, struct rm_options const *x){ enum RM_status rm_status = RM_OK; if (*file) { int bit_flags = (FTS_CWDFD | FTS_NOSTAT | FTS_PHYSICAL); if (x->one_file_system) bit_flags |= FTS_XDEV; FTS *fts = xfts_open (file, bit_flags, NULL); //創(chuàng)建并填充FTS結(jié)構(gòu)體部分成員信息,會調(diào)用fts_open函數(shù),失敗返回失敗的診斷信息 while (1) { FTSENT *ent; ent = fts_read (fts); //填充FTSENT結(jié)構(gòu)體成員信息 if (ent == NULL) { if (errno != 0) { error (0, errno, _("fts_read failed")); rm_status = RM_ERROR; } break; } enum RM_status s = rm_fts (fts, ent, x); assert (VALID_STATUS (s)); UPDATE_STATUS (rm_status, s); } if (fts_close (fts) != 0) { error (0, errno, _("fts_close failed")); rm_status = RM_ERROR; } } return rm_status;}
rn_fts()函數(shù)根據(jù)FTSENT結(jié)構(gòu)體成員信息,做一些處理,然后調(diào)用excise()函數(shù)執(zhí)行刪除操作;
excise函數(shù)調(diào)用unlinkat系統(tǒng)函數(shù)
/* 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_statusexcise (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) { /* 使用了-v選項(xiàng)時(shí),輸出詳細(xì)刪除信息,是目錄輸出目錄名,是文件輸出文件名, 輸出的是當(dāng)前目錄到刪除文件的完全路徑(" `/tmp/aa' "或者"`test/bb'") */ if (x->verbose) { printf ((is_dir ? _("removed directory: %s\n") : _("removed %s\n")), quote (ent->fts_path)); /*quote是將輸出用(`')反引號單引號括起來*/ } return RM_OK; } //下邊為unlinkat函數(shù)執(zhí)行失敗,做的一些處理 /* 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;}
添加的覆蓋文件內(nèi)容的操作就是添加在unlinkat函數(shù)前邊,因?yàn)樯蠋撞揭呀?jīng)做好了rm命令選項(xiàng)的操作,使用不同參數(shù)的不同操作,unlinkat函數(shù)是最終執(zhí)行刪除操作的:
int flag = is_dir ? AT_REMOVEDIR : 0;if(flag == 0) //根據(jù)flag標(biāo)志判斷是文件還是目錄,如果是文件才執(zhí)行覆蓋操作,否則不做任何操作{ //覆蓋操作}if (unlinkat (fts->fts_cwd_fd, ent->fts_accpath, flag) == 0)