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