github.com/zaolin/u-root@v0.0.0-20200428085104-64aaafd46c6d/cmds/core/df/df.go (about) 1 // Copyright 2015-2017 the u-root Authors. All rights reserved 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // df reports details of mounted filesystems 6 // 7 // Synopsis 8 // df [-k] [-m] 9 // 10 // Description 11 // read mount information from /proc/mounts and 12 // statfs syscall and display summary information for all 13 // mount points that have a non-zero block count. 14 // Users can choose to see the diplay in KB or MB. 15 // 16 // Options 17 // -k: display values in KB (default) 18 // -m: dispaly values in MB 19 package main 20 21 import ( 22 "bytes" 23 "flag" 24 "fmt" 25 "io/ioutil" 26 "log" 27 "math" 28 "syscall" 29 ) 30 31 var ( 32 inKB = flag.Bool("k", false, "Express the values in kilobytes (default)") 33 inMB = flag.Bool("m", false, "Express the values in megabytes") 34 units uint64 35 ) 36 37 const procmountsFile = "/proc/mounts" 38 39 const ( 40 // B is Bytes 41 B = 1 42 // KB is kilobytes 43 KB = 1024 * B 44 // MB is megabytes 45 MB = 1024 * KB 46 ) 47 48 // Mount is a structure used to contain mount point data 49 type Mount struct { 50 Device string 51 MountPoint string 52 FileSystemType string 53 Flags string 54 Bsize int64 55 Blocks uint64 56 Total uint64 57 Used uint64 58 Avail uint64 59 PCT uint8 60 } 61 62 type mountinfomap map[string]Mount 63 64 // mountinfo returns a map of mounts representing 65 // the data in /proc/mounts 66 func mountinfo() (mountinfomap, error) { 67 buf, err := ioutil.ReadFile(procmountsFile) 68 if err != nil { 69 return nil, err 70 } 71 return mountinfoFromBytes(buf) 72 } 73 74 // returns a map generated from the bytestream returned 75 // from /proc/mounts 76 // for tidiness, we decide to ignore filesystems of size 0 77 // to exclude cgroup, procfs and sysfs types 78 func mountinfoFromBytes(buf []byte) (mountinfomap, error) { 79 ret := make(mountinfomap) 80 for _, line := range bytes.Split(buf, []byte{'\n'}) { 81 kv := bytes.SplitN(line, []byte{' '}, 6) 82 if len(kv) != 6 { 83 // can't interpret this 84 continue 85 } 86 key := string(kv[1]) 87 var mnt Mount 88 mnt.Device = string(kv[0]) 89 mnt.MountPoint = string(kv[1]) 90 mnt.FileSystemType = string(kv[2]) 91 mnt.Flags = string(kv[3]) 92 DiskUsage(&mnt) 93 if mnt.Blocks == 0 { 94 continue 95 } else { 96 ret[key] = mnt 97 } 98 } 99 return ret, nil 100 } 101 102 // DiskUsage calculates the usage statistics of a mount point 103 // note: arm7 Bsize is int32; all others are int64 104 func DiskUsage(mnt *Mount) { 105 fs := syscall.Statfs_t{} 106 err := syscall.Statfs(mnt.MountPoint, &fs) 107 if err != nil { 108 return 109 } 110 mnt.Blocks = fs.Blocks * uint64(fs.Bsize) / units 111 mnt.Bsize = int64(fs.Bsize) 112 mnt.Total = fs.Blocks * uint64(fs.Bsize) / units 113 mnt.Avail = fs.Bavail * uint64(fs.Bsize) / units 114 mnt.Used = (fs.Blocks - fs.Bfree) * uint64(fs.Bsize) / units 115 pct := float64((fs.Blocks - fs.Bfree)) * 100 / float64(fs.Blocks) 116 mnt.PCT = uint8(math.Ceil(pct)) 117 } 118 119 // SetUnits takes the command line flags and configures 120 // the correct units used to calculate display values 121 func SetUnits() { 122 if *inKB && *inMB { 123 log.Fatal("options -k and -m are mutually exclusive") 124 } 125 if *inMB { 126 units = MB 127 } else { 128 units = KB 129 } 130 } 131 132 func df() { 133 SetUnits() 134 mounts, _ := mountinfo() 135 var blocksize = "1K" 136 if *inMB { 137 blocksize = "1M" 138 } 139 fmt.Printf("Filesystem Type %v-blocks Used Available Use%% Mounted on\n", blocksize) 140 for _, mnt := range mounts { 141 fmt.Printf("%-20v %-9v %12v %10v %12v %4v%% %-13v\n", 142 mnt.Device, 143 mnt.FileSystemType, 144 mnt.Blocks, 145 mnt.Used, 146 mnt.Avail, 147 mnt.PCT, 148 mnt.MountPoint) 149 } 150 } 151 152 func main() { 153 flag.Parse() 154 df() 155 }