• 售前

  • 售后

热门帖子
入门百科

busybox df命令详细分析

[复制链接]
粘瓜莱 显示全部楼层 发表于 2022-1-12 13:08:09 |阅读模式 打印 上一主题 下一主题
本文基于busybox1.34.0版本 对df命令分析
下面是df命令用法

源码分析
  1. #include <mntent.h>
  2. #include <sys/statvfs.h>
  3. #include "libbb.h"
  4. #include "unicode.h"
  5. #if !ENABLE_FEATURE_HUMAN_READABLE
  6. static unsigned long kscale(unsigned long b, unsigned long bs)
  7. {
  8.         return (b * (unsigned long long) bs + 1024/2) / 1024;
  9. }
  10. #endif
  11. int df_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
  12. int df_main(int argc UNUSED_PARAM, char **argv)
  13. {
  14.         unsigned long df_disp_hr = 1024;//默认情况下,磁盘空间以1K块显示。
  15.         int status = EXIT_SUCCESS;
  16.         unsigned opt;//保存标志值
  17.         FILE *mount_table;//挂载文件
  18.         struct mntent *mount_entry;//挂载入口(挂载表条目结构体)
  19.         /*描述装载表条目的结构*/
  20.         //struct mntent
  21.         //{
  22.         //        char *mnt_fsname;   /* 挂载文件系统的名称  */
  23.         //        char *mnt_dir;      /*文件系统路径前缀  */
  24.         //        char *mnt_type;     /* 挂载的文件系统类型: ufs, nfs等  */
  25.         //        char *mnt_opts;     /*挂载选项  */
  26.         //        int mnt_freq;       /* 以天为单位的转存频率  */
  27.         //        int mnt_passno;     /* 并行fsck上的传递数字  */
  28.         //};
  29.         struct statvfs s;
  30.         enum {//定义不同选项,根据输入选项内容解析处标志值与这个定义的选项进行比对进而设置输出内容
  31.                 OPT_KILO   = (1 << 0),//没意义
  32.                 OPT_POSIX  = (1 << 1),//df -P POSIX输出格式显示
  33.                 OPT_FSTYPE = (1 << 2),//df -T显示文件系统类型。
  34.                 OPT_t      = (1 << 3),//df -m 1M字节块显示
  35.                 OPT_ALL    = (1 << 4) * ENABLE_FEATURE_DF_FANCY,//df -a显示所有文件系统
  36.                 OPT_INODE  = (1 << 5) * ENABLE_FEATURE_DF_FANCY,//df -i显示inode信息而非块使用量。
  37.                 OPT_BSIZE  = (1 << 6) * ENABLE_FEATURE_DF_FANCY,//df -B根据用户输入块大小显示
  38.                 OPT_HUMAN  = (1 << (4 + 3*ENABLE_FEATURE_DF_FANCY)) * ENABLE_FEATURE_HUMAN_READABLE,//df -h  以容易理解的格式印出文件系统大小,例如136KB、254MB、21GB。
  39.                 OPT_MEGA   = (1 << (5 + 3*ENABLE_FEATURE_DF_FANCY)) * ENABLE_FEATURE_HUMAN_READABLE,//df -k以1024字节为单位列出磁盘空间使用情况。
  40.         };
  41.         const char *disp_units_hdr = NULL;//要显示选项名称字符指针
  42.         char *chp, *opt_t;
  43.         init_unicode();
  44.         /* From the manpage of df from coreutils-6.10:
  45.          * Disk space is shown in 1K blocks by default, unless the environment
  46.          * variable POSIXLY_CORRECT is set, in which case 512-byte blocks are used.
  47.          */
  48.          /*从coreutils-6.10的df手册页:
  49.           *默认情况下,磁盘空间以1K块显示,除非环境
  50.           *设置变量POSIXLY_CORRECT,在这种情况下使用512字节块。
  51.          */
  52.         if (getenv("POSIXLY_CORRECT")) /* TODO - a new libbb function? */  /*TODO-一个新的libbb函数*/
  53.                 df_disp_hr = 512;//要显示的长度
  54.         opt = getopt32(argv, "^"
  55.                         "kPTt:"
  56.                         IF_FEATURE_DF_FANCY("aiB:")
  57.                         IF_FEATURE_HUMAN_READABLE("hm")
  58.                         "\0"
  59. #if ENABLE_FEATURE_HUMAN_READABLE && ENABLE_FEATURE_DF_FANCY
  60.                         "k-mB:m-Bk:B-km"
  61. #elif ENABLE_FEATURE_HUMAN_READABLE
  62.                         "k-m:m-k"
  63. #endif
  64.                         , &opt_t
  65.                         IF_FEATURE_DF_FANCY(, &chp)
  66.         );//根据输入不同的命令返回一个标志值
  67.         if (opt & OPT_MEGA)//df -k以1024字节为单位列出磁盘空间使用情况。
  68.                 df_disp_hr = 1024*1024;//要显示的长度1024字节
  69.         if (opt & OPT_BSIZE) {//df -B根据用户输入块大小显示
  70.                 /* GNU coreutils 8.25 accepts "-BMiB" form too */
  71.                 /*GNU更正8.25接受“-BMiB”表格所有*/
  72.                 int i;
  73.                 for (i = 0; kmg_i_suffixes[i].suffix[0]; i++) {//解析用户输入值并设置好显示长度
  74.                         if (strcmp(kmg_i_suffixes[i].suffix, chp) == 0) {
  75.                                 df_disp_hr = kmg_i_suffixes[i].mult;
  76.                                 goto got_it;
  77.                         }
  78.                 }
  79.                 /* Range used to disallow 0 */
  80.                 /*用于禁止0的范围*/
  81.                 df_disp_hr = xatoul_range_sfx(chp, 1, ULONG_MAX, kmg_i_suffixes);
  82. got_it: ;
  83.         }
  84.         if (opt & OPT_HUMAN) {//df -h  以容易理解的格式印出文件系统大小,例如136KB、254MB、21GB。
  85.                 df_disp_hr = 0;//这种方式不需要调整输出长度(每块的大小)
  86.                 disp_units_hdr = "     Size";
  87.         }
  88.         if (opt & OPT_INODE)//df -i显示inode信息而非块使用量。
  89.                 disp_units_hdr = "   Inodes";
  90.         if (disp_units_hdr == NULL) {//df 如果要显示的类型未定义,选项也没有设置,那么显示原始类型块使用量
  91. #if ENABLE_FEATURE_HUMAN_READABLE
  92.                 disp_units_hdr = xasprintf("%s-blocks",
  93.                         /* print df_disp_hr, show no fractionals,
  94.                          * use suffixes if OPT_POSIX is set in opt */
  95.                          /*打印df_disp_hr,不显示分数,
  96.                           *如果在OPT中设置了OPT_POSIX,则使用后缀*/
  97.                         make_human_readable_str(df_disp_hr, 0, !!(opt & OPT_POSIX))
  98.                 );
  99. #else
  100.                 disp_units_hdr = xasprintf("%lu-blocks", df_disp_hr);//按照1024k/块显示
  101. #endif
  102.         }
  103.         printf("Filesystem           %s%-15sUsed Available %s Mounted on\n",
  104.                         (opt & OPT_FSTYPE) ? "Type       " : "",//df -T显示文件系统类型。
  105.                         disp_units_hdr,
  106.                         (opt & OPT_POSIX) ? "Capacity" : "Use%");//df -P POSIX输出格式显示
  107.         mount_table = NULL;
  108.         argv += optind;
  109.         if (!argv[0]) {//如果没有设置参数
  110.                 mount_table = setmntent(bb_path_mtab_file, "r");//Busybox装载使用/proc/mounts或/etc/mtab获取当前装入的文件系统的列表
  111.                 if (!mount_table)
  112.                         bb_simple_perror_msg_and_die(bb_path_mtab_file);//没获取到mount_table,把错误信息写到perror并退出
  113.         }
  114.         while (1) {
  115.                 const char *device;
  116.                 const char *mount_point;
  117.                 const char *fs_type;
  118.                 if (mount_table) {//如果没有设置参数//所以mount_table不为空
  119.                         mount_entry = getmntent(mount_table);//从文件系统列表中解析挂载入口
  120.                         //得到mount_entry(挂载表条目信息)
  121.                         if (!mount_entry) {//解析失败
  122.                                 endmntent(mount_table);//关闭流和与其相关联的文件系统描述文件
  123.                                 break;
  124.                         }
  125.                 } else {
  126.                         mount_point = *argv++;//解析成功根据用户输入的位置解析挂载点得到挂载入口
  127.                         if (!mount_point)
  128.                                 break;
  129.                         mount_entry = find_mount_point(mount_point, 1);
  130.                         if (!mount_entry) {
  131.                                 bb_error_msg("%s: can't find mount point", mount_point);
  132. set_error:
  133.                                 status = EXIT_FAILURE;
  134.                                 continue;
  135.                         }
  136.                 }
  137.                 device = mount_entry->mnt_fsname;//device挂载文件系统的名称
  138.                 /* GNU coreutils 6.10 skips certain mounts, try to be compatible */
  139.                 /*GNU coreutils 6.10跳过某些挂载,尝试兼容*/
  140.                 if (ENABLE_FEATURE_SKIP_ROOTFS && strcmp(device, "rootfs") == 0)
  141.                         continue;
  142.                 mount_point = mount_entry->mnt_dir;//mount_point文件系统路径前缀
  143.                 fs_type = mount_entry->mnt_type;//fs_type挂载的文件系统类型: ufs, nfs等  
  144.                 if (opt & OPT_t) {//df -m 1M字节块显示
  145.                         if (strcmp(fs_type, opt_t) != 0)
  146.                                 continue;
  147.                 }
  148.                 if (statvfs(mount_point, &s) != 0) {//得到mount_point路径下文件目录的大小存到s结构体中,用于计算总/可用/使用/有效容量
  149.                         bb_simple_perror_msg(mount_point);
  150.                         goto set_error;
  151.                 }
  152.                 /* Some uclibc versions were seen to lose f_frsize
  153.                  * (kernel does return it, but then uclibc does not copy it)
  154.                  */
  155.                  /*一些uclibc版本被视为丢失了f_frsize大小
  156.                   *(内核会返回它,但uclibc不会复制它)
  157.                   */
  158.                 if (s.f_frsize == 0)
  159.                         s.f_frsize = s.f_bsize;//获取一个block的大小
  160.                 if ((s.f_blocks > 0) || !mount_table || (opt & OPT_ALL)) {//df -a显示所有文件系统
  161.                         unsigned long long blocks_used;
  162.                         unsigned long long blocks_total;
  163.                         unsigned blocks_percent_used;
  164.                         if (opt & OPT_INODE) {//df -i显示inode信息而非块使用量。
  165.                                 s.f_blocks = s.f_files;
  166.                                 s.f_bavail = s.f_bfree = s.f_ffree;//可用容量
  167.                                 s.f_frsize = 1;
  168.                                 if (df_disp_hr)
  169.                                         df_disp_hr = 1;
  170.                         }
  171.                         blocks_used = s.f_blocks - s.f_bfree;//获取使用容量
  172.                         blocks_total = blocks_used + s.f_bavail;//获取总容量(可用+已用)
  173.                         blocks_percent_used = blocks_total; // 0% if blocks_total == 0, else... 使用率初始化
  174.                         if (blocks_total != 0) {
  175.                                 /* Downscale sizes for narrower division */
  176.                                 /*缩小尺寸以缩小划分范围*/
  177.                                 unsigned u;
  178.                                 while (blocks_total >= INT_MAX / 101) {
  179.                                         blocks_total >>= 1;
  180.                                         blocks_used >>= 1;
  181.                                 }
  182.                                 u = (unsigned)blocks_used * 100u + (unsigned)blocks_total / 2;
  183.                                 blocks_percent_used = u / (unsigned)blocks_total;//获取使用率
  184.                         }
  185. //WHY_WE_DO_IT_FOR_DEV_ROOT_ONLY为什么我们只为开发者而做
  186. #ifdef WHY_WE_DO_IT_FOR_DEV_ROOT_ONLY
  187.                         if (strcmp(device, "/dev/root") == 0) {
  188.                                 /* Adjusts device to be the real root device,
  189.                                  * or leaves device alone if it can't find it */
  190.                                  /*将设备调整为实际根设备,
  191.                                         或者,如果设备找不到它,
  192.                                         就让它单独呆着*/
  193.                                 device = find_block_device("/");
  194.                                 if (!device) {
  195.                                         goto set_error;
  196.                                 }
  197.                         }
  198. #endif
  199. //启用UNICODE支持
  200. #if ENABLE_UNICODE_SUPPORT
  201.                         {
  202.                                 uni_stat_t uni_stat;
  203.                                 char *uni_dev = unicode_conv_to_printable(&uni_stat, device);//转换成unicode形式
  204.                                 if (uni_stat.unicode_width > 20 && !(opt & OPT_POSIX)) {
  205.                                         printf("%s\n%20s", uni_dev, "");
  206.                                 } else {
  207.                                         printf("%s%*s", uni_dev, 20 - (int)uni_stat.unicode_width, "");//打印挂载文件系统的名称(unicode)
  208.                                 }
  209.                                 free(uni_dev);
  210.                                 if (opt & OPT_FSTYPE) {//df -T显示文件系统类型。
  211.                                         char *uni_type = unicode_conv_to_printable(&uni_stat, fs_type);
  212.                                         if (uni_stat.unicode_width > 10 && !(opt & OPT_POSIX))
  213.                                                 printf(" %s\n%31s", uni_type, "");
  214.                                         else
  215.                                                 printf(" %s%*s", uni_type, 10 - (int)uni_stat.unicode_width, "");//打印fs_type挂载的文件系统类型: ufs, nfs等(unicode)
  216.                                         free(uni_type);
  217.                                 }
  218.                         }
  219. #else
  220.                         if (printf("\n%-20s" + 1, device) > 20 && !(opt & OPT_POSIX))//打印挂载文件系统的名称
  221.                                 printf("\n%-20s", "");
  222.                         if (opt & OPT_FSTYPE) {//df -T显示文件系统类型。
  223.                                 if (printf(" %-10s", fs_type) > 11 && !(opt & OPT_POSIX))//打印fs_type挂载的文件系统类型: ufs, nfs等  
  224.                                         printf("\n%-30s", "");
  225.                         }
  226. #endif
  227. //启用用户可读功能
  228. #if ENABLE_FEATURE_HUMAN_READABLE
  229.                         printf(" %9s ",
  230.                                 /* f_blocks x f_frsize / df_disp_hr, show one fractional,
  231.                                  * use suffixes if df_disp_hr == 0 */
  232.                                 make_human_readable_str(s.f_blocks, s.f_frsize, df_disp_hr));
  233.                         printf(" %9s " + 1,
  234.                                 /* EXPR x f_frsize / df_disp_hr, show one fractional,
  235.                                  * use suffixes if df_disp_hr == 0 */
  236.                                 make_human_readable_str((s.f_blocks - s.f_bfree),
  237.                                                 s.f_frsize, df_disp_hr));
  238.                         printf("%9s %3u%% %s\n",
  239.                                 /* f_bavail x f_frsize / df_disp_hr, show one fractional,
  240.                                  * use suffixes if df_disp_hr == 0 */
  241.                                 make_human_readable_str(s.f_bavail, s.f_frsize, df_disp_hr),
  242.                                 blocks_percent_used, mount_point);
  243. #else
  244.                         printf(" %9lu %9lu %9lu %3u%% %s\n",
  245.                                 kscale(s.f_blocks, s.f_frsize),
  246.                                 kscale(s.f_blocks - s.f_bfree, s.f_frsize),
  247.                                 kscale(s.f_bavail, s.f_frsize),
  248.                                 blocks_percent_used, mount_point);
  249. #endif
  250.                 }
  251.         }
  252.         return status;
  253. }
复制代码
来源:https://blog.caogenba.net/qq_34070495/article/details/122429023
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x

帖子地址: 

回复

使用道具 举报

分享
推广
火星云矿 | 预约S19Pro,享500抵1000!
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

草根技术分享(草根吧)是全球知名中文IT技术交流平台,创建于2021年,包含原创博客、精品问答、职业培训、技术社区、资源下载等产品服务,提供原创、优质、完整内容的专业IT技术开发社区。
  • 官方手机版

  • 微信公众号

  • 商务合作