📄 df.c
字号:
/*********************************************************************Copyright (c) : free software.*Filename : df.c*Author : gxg*Version : 1.0*History : Create this file . To show files description .*Data : 2008.09.22*Description : *Other : *********************************************************************/#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <mntent.h>#include <sys/vfs.h>#include <stdarg.h>#include <getopt.h>#include <assert.h>#include <linux/stat.h>#include <sys/stat.h>#include <sys/types.h>#include <dirent.h>#include <limits.h>#include <dirent.h>#include "df.h"int bb_default_error_retval = EXIT_FAILURE;//const char bb_path_mtab_file[] = "/etc/mtab";const char bb_path_mtab_file[] = "/proc/mounts";static const struct option bb_default_long_options[] = {/* { "help", 0, NULL, '?' }, */ { 0, 0, 0, 0 }};const struct option *bb_applet_long_options = bb_default_long_options;static const char msg_enomem[] = "memory exhausted";void usage(char *prog){ fprintf(stderr, "Usage: %s [ -q ] [ -o offset ] [ -f frequency ] [ -p timeconstant ] [ -t tick ]\n", prog);}#define bb_show_usage() usage(argv[0])void bb_verror_msg(const char *s, va_list p){ fflush(stdout); //fprintf(stderr, "%s: ", bb_applet_name); vfprintf(stderr, s, p);}void bb_error_msg_and_die(const char *s, ...){ va_list p; va_start(p, s); bb_verror_msg(s, p); va_end(p); putc('\n', stderr); exit(bb_default_error_retval);}char * bb_xstrdup (const char *s){ char *t; if (s == NULL) return NULL; t = strdup (s); if (t == NULL) bb_error_msg_and_die(msg_enomem); return t;}/* inline realization for fast works */static inline void *xmalloc(size_t size){ void *p = malloc(size); if(p == NULL) fprintf(stderr, "%s: ", msg_enomem); return p;}llist_t *llist_add_to(llist_t *old_head, char *new_item){ llist_t *new_head; new_head = xmalloc(sizeof(llist_t)); new_head->data = new_item; new_head->link = old_head; return (new_head);}extern int bb_vfprintf(FILE * __restrict stream, const char * __restrict format, va_list arg){ int rv; if ((rv = vfprintf(stream, format, arg)) < 0) { //SET_FERROR_UNLOCKED(stream); ; } return rv;}int bb_printf(const char * __restrict format, ...){ va_list arg; int rv; va_start(arg, format); rv = bb_vfprintf(stdout, format, arg); va_end(arg); return rv;}//this function had some memory leak, had malloc but no freeunsigned longbb_getopt_ulflags (int argc, char **argv, const char *applet_opts, ...){ unsigned long flags = 0; unsigned long requires = 0; t_complementally complementally[sizeof(flags) * 8 + 1]; int c; const unsigned char *s; t_complementally *on_off; va_list p; const struct option *l_o; unsigned long trigger;#ifdef CONFIG_PS char **pargv = NULL;#endif int min_arg = 0; int max_arg = -1;#define SHOW_USAGE_IF_ERROR 1#define ALL_ARGV_IS_OPTS 2#define FIRST_ARGV_IS_OPT 4#define FREE_FIRST_ARGV_IS_OPT 8 int spec_flgs = 0; va_start (p, applet_opts); c = 0; on_off = complementally; memset(on_off, 0, sizeof(complementally)); /* skip GNU extension */ s = (const unsigned char *)applet_opts; if(*s == '+' || *s == '-') s++; for (; *s; s++) { if(c >= (int)(sizeof(flags)*8)) break; on_off->opt = *s; on_off->switch_on = (1 << c); if (s[1] == ':') { on_off->optarg = va_arg (p, void **); do s++; while (s[1] == ':'); } on_off++; c++; } for(l_o = bb_applet_long_options; l_o->name; l_o++) { if(l_o->flag) continue; for(on_off = complementally; on_off->opt != 0; on_off++) if(on_off->opt == l_o->val) break; if(on_off->opt == 0) { if(c >= (int)(sizeof(flags)*8)) break; on_off->opt = l_o->val; on_off->switch_on = (1 << c); if(l_o->has_arg != no_argument) on_off->optarg = va_arg (p, void **); c++; } } for (s = (const unsigned char *)bb_opt_complementally; s && *s; s++) { t_complementally *pair; unsigned long *pair_switch; if (*s == ':') continue; c = s[1]; if(*s == '?') { if(c < '0' || c > '9') { spec_flgs |= SHOW_USAGE_IF_ERROR; } else { max_arg = c - '0'; s++; } continue; } if(*s == '-') { if(c < '0' || c > '9') { if(c == '-') { spec_flgs |= FIRST_ARGV_IS_OPT; s++; } else spec_flgs |= ALL_ARGV_IS_OPTS; } else { min_arg = c - '0'; s++; } continue; } for (on_off = complementally; on_off->opt; on_off++) if (on_off->opt == *s) break; if(c == ':' && s[2] == ':') { on_off->list_flg++; continue; } if(c == ':' || c == '\0') { requires |= on_off->switch_on; continue; } if(c == '-' && (s[2] == ':' || s[2] == '\0')) { flags |= on_off->switch_on; on_off->incongruously |= on_off->switch_on; s++; continue; } if(c == *s) { on_off->counter = va_arg (p, int *); s++; } pair = on_off; pair_switch = &(pair->switch_on); for(s++; *s && *s != ':'; s++) { if(*s == '?') { pair_switch = &(pair->requires); } else if (*s == '-') { if(pair_switch == &(pair->switch_off)) pair_switch = &(pair->incongruously); else pair_switch = &(pair->switch_off); } else { for (on_off = complementally; on_off->opt; on_off++) if (on_off->opt == *s) { *pair_switch |= on_off->switch_on; break; } } } s--; } va_end (p);#if defined(CONFIG_AR) || defined(CONFIG_TAR) if((spec_flgs & FIRST_ARGV_IS_OPT)) { if(argv[1] && argv[1][0] != '-' && argv[1][0] != '\0') { argv[1] = bb_xasprintf("-%s", argv[1]); if(ENABLE_FEATURE_CLEAN_UP) spec_flgs |= FREE_FIRST_ARGV_IS_OPT; } }#endif while ((c = getopt_long (argc, argv, applet_opts, bb_applet_long_options, NULL)) >= 0) {#ifdef CONFIG_PSloop_arg_is_opt:#endif for (on_off = complementally; on_off->opt != c; on_off++) { /* c==0 if long opt have non NULL flag */ if(on_off->opt == 0 && c != 0) bb_show_usage (); } if(flags & on_off->incongruously) { if((spec_flgs & SHOW_USAGE_IF_ERROR)) bb_show_usage (); flags |= BB_GETOPT_ERROR; } trigger = on_off->switch_on & on_off->switch_off; flags &= ~(on_off->switch_off ^ trigger); flags |= on_off->switch_on ^ trigger; flags ^= trigger; if(on_off->counter) (*(on_off->counter))++; if(on_off->list_flg) { *(llist_t **)(on_off->optarg) = llist_add_to(*(llist_t **)(on_off->optarg), optarg); } else if (on_off->optarg) { *(char **)(on_off->optarg) = optarg; }#ifdef CONFIG_PS if(pargv != NULL) break;#endif }#ifdef CONFIG_PS if((spec_flgs & ALL_ARGV_IS_OPTS)) { /* process argv is option, for example "ps" applet */ if(pargv == NULL) pargv = argv + optind; while(*pargv) { c = **pargv; if(c == '\0') { pargv++; } else { (*pargv)++; goto loop_arg_is_opt; } } }#endif#if (defined(CONFIG_AR) || defined(CONFIG_TAR)) && \ defined(CONFIG_FEATURE_CLEAN_UP) if((spec_flgs & FREE_FIRST_ARGV_IS_OPT)) free(argv[1]);#endif /* check depending requires for given options */ for (on_off = complementally; on_off->opt; on_off++) { if(on_off->requires && (flags & on_off->switch_on) && (flags & on_off->requires) == 0) bb_show_usage (); } if(requires && (flags & requires) == 0) bb_show_usage (); argc -= optind; if(argc < min_arg || (max_arg >= 0 && argc > max_arg)) bb_show_usage (); return flags;}#ifndef CONFIG_FEATURE_HUMAN_READABLEstatic long kscale(long b, long bs){ return ( b * (long long) bs + KILOBYTE/2 ) / KILOBYTE;}#endifstruct mntent *find_mount_point(const char *name, const char *table){ struct stat s; dev_t mountDevice; FILE *mountTable; struct mntent *mountEntry; if (stat(name, &s) != 0) return 0; if ((s.st_mode & S_IFMT) == S_IFBLK) mountDevice = s.st_rdev; else mountDevice = s.st_dev; if ((mountTable = setmntent(table ? table : bb_path_mtab_file, "r")) == 0) return 0; while ((mountEntry = getmntent(mountTable)) != 0) { if(strcmp(name, mountEntry->mnt_dir) == 0 || strcmp(name, mountEntry->mnt_fsname) == 0) /* String match. */ break; if (stat(mountEntry->mnt_fsname, &s) == 0 && s.st_rdev == mountDevice) /* Match the device. */ break; if (stat(mountEntry->mnt_dir, &s) == 0 && s.st_dev == mountDevice) /* Match the directory's mount point. */ break; } endmntent(mountTable); return mountEntry;}char *find_block_device(char *path){ DIR *dir; struct dirent *entry; struct stat st; dev_t dev; char *retpath=NULL; if(stat(path, &st) || !(dir = opendir("/dev"))) return NULL; dev = (st.st_mode & S_IFMT) == S_IFBLK ? st.st_rdev : st.st_dev; while((entry = readdir(dir)) != NULL) { char devpath[PATH_MAX]; sprintf(devpath,"/dev/%s", entry->d_name); if(!stat(devpath, &st) && S_ISBLK(st.st_mode) && st.st_rdev == dev) { retpath = bb_xstrdup(devpath); break; } } closedir(dir); return retpath;}#ifdef CONFIG_FEATURE_HUMAN_READABLEconst char *make_human_readable_str(unsigned long long size, unsigned long block_size, unsigned long display_unit){ /* The code will adjust for additional (appended) units. */ static const char zero_and_units[] = { '0', 0, 'k', 'M', 'G', 'T' }; static const char fmt[] = "%Lu"; static const char fmt_tenths[] = "%Lu.%d%c"; static char str[21]; /* Sufficient for 64 bit unsigned integers. */ unsigned long long val; int frac; const char *u; const char *f; u = zero_and_units; f = fmt; frac = 0; val = size * block_size; if (val == 0) { return u; } if (display_unit) { val += display_unit/2; /* Deal with rounding. */ val /= display_unit; /* Don't combine with the line above!!! */ } else { ++u; while ((val >= KILOBYTE) && (u < zero_and_units + sizeof(zero_and_units) - 1)) { f = fmt_tenths; ++u; frac = ((((int)(val % KILOBYTE)) * 10) + (KILOBYTE/2)) / KILOBYTE; val /= KILOBYTE; } if (frac >= 10) { /* We need to round up here. */ ++val; frac = 0; }#if 0 /* Sample code to omit decimal point and tenths digit. */ if ( /* no_tenths */ 1 ) { if ( frac >= 5 ) { ++val; } f = "%Lu%*c" /* fmt_no_tenths */ ; frac = 1; }#endif } /* If f==fmt then 'frac' and 'u' are ignored. */ snprintf(str, sizeof(str), f, val, frac, *u); return str;}#endifint df_proc(int argc, char **argv){ long blocks_used; long blocks_percent_used; char *pfree = NULL; //用于释放strdup分配的空间,以免造成内存泄露#ifdef CONFIG_FEATURE_HUMAN_READABLE unsigned long df_disp_hr = KILOBYTE;#endif int status = EXIT_SUCCESS; unsigned long opt; FILE *mount_table; struct mntent *mount_entry; struct statfs s; static const char hdr_1k[] = "1k-blocks"; /* default display is kilobytes */ const char *disp_units_hdr = hdr_1k;#ifdef CONFIG_FEATURE_HUMAN_READABLE bb_opt_complementally = "h-km:k-hm:m-hk"; //opt = bb_getopt_ulflags(argc, argv, "hmk"); //this function had some memory leak ,comment by gxg opt = 1; //add by gxg if(opt & 1) { df_disp_hr = 0; disp_units_hdr = " Size"; } if(opt & 2) { df_disp_hr = MEGABYTE; disp_units_hdr = "1M-blocks"; }#else opt = bb_getopt_ulflags(argc, argv, "k");#endif printf("Filesystem%11s%-15sUsed Available Use%% Mounted on\n", "", disp_units_hdr); optind = 2; //add by gxg mount_table = NULL; argv += optind; if (optind >= argc) { if (!(mount_table = setmntent(bb_path_mtab_file, "r"))) { fflush(stdout); fprintf(stderr, "%s: ", bb_path_mtab_file); } } do { const char *device; const char *mount_point; if(NULL != pfree) { free(pfree); pfree = NULL; } if (mount_table) { if (!(mount_entry = getmntent(mount_table))) { endmntent(mount_table); break; } } else { if (!(mount_point = *argv++)) { break; } if (!(mount_entry = find_mount_point((char *)mount_point, bb_path_mtab_file))) { printf("%p: can't find mount point.", mount_point); SET_ERROR: status = EXIT_FAILURE; continue; } } device = mount_entry->mnt_fsname; mount_point = mount_entry->mnt_dir; if (statfs(mount_point, &s) != 0) { //bb_perror_msg("%s", mount_point); goto SET_ERROR; } if ((s.f_blocks > 0) || !mount_table){ blocks_used = s.f_blocks - s.f_bfree; blocks_percent_used = 0; if (blocks_used + s.f_bavail) { blocks_percent_used = (((long long) blocks_used) * 100 + (blocks_used + s.f_bavail)/2 ) / (blocks_used + s.f_bavail); } if (strcmp(device, "rootfs") == 0) { continue; } else if (strcmp(device, "/dev/root") == 0) { /* Adjusts device to be the real root device, * or leaves device alone if it can't find it */ if ((device = find_block_device("/")) == NULL) { goto SET_ERROR; }else pfree = device; }#ifdef CONFIG_FEATURE_HUMAN_READABLE bb_printf("%-20s %9s ", device, make_human_readable_str(s.f_blocks, s.f_bsize, df_disp_hr)); bb_printf("%9s ", make_human_readable_str( (s.f_blocks - s.f_bfree), s.f_bsize, df_disp_hr)); bb_printf("%9s %3ld%% %s\n", make_human_readable_str(s.f_bavail, s.f_bsize, df_disp_hr), blocks_percent_used, mount_point);#else bb_printf("%-20s %9ld %9ld %9ld %3ld%% %s\n", device, kscale(s.f_blocks, s.f_bsize), kscale(s.f_blocks-s.f_bfree, s.f_bsize), kscale(s.f_bavail, s.f_bsize), blocks_percent_used, mount_point);#endif } } while (1); //flush stdout and exit if (fflush(stdout)) { status = bb_default_error_retval; } return (status); }int main(int argc, char * * argv){#if 0 int iCount; char flag = 0; printf("%d\n",argc); for(iCount = 0; iCount <64; iCount ++){ if(argv[iCount] == NULL) { if(flag == 0) { flag = 1; continue; }else break; } printf("%s:\n",argv[iCount]); }#endif df_proc(argc, argv); return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -