github.com/hugelgupf/u-root@v0.0.0-20191023214958-4807c632154c/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  }