如何正确获取块设备的大小?

时间:2017-10-04 07:00:24

标签: go

编辑:正如@a​​bhink指出的那样,没有调用Size()

我尝试了两种不同的go方法,然后与df进行了比较。当然,所有3个都有不同的结果:

package main

import (
    "os"
    "syscall"
    "fmt"
)

func main() {
    disk := "/dev/sda1"
    statout, err := os.Stat(disk)
    if err != nil {
        fmt.Errorf("Error %x", err)
        os.Exit(1)
    }
    println("os.Stat Size   : ", statout.Size())

    var stat syscall.Statfs_t
    syscall.Statfs(disk, &stat)
    println("syscall.Statfs_t Type: ",  stat.Type)
    println("syscall.Statfs_t Bsize: ",  stat.Bsize)
    println("syscall.Statfs_t Blocks: ",  stat.Blocks)
}

运行程序:

$ main
os.Stat Size   :  0
syscall.Statfs_t Type: 16914836
syscall.Statfs_t Bsize: 4096
syscall.Statfs_t Blocks: 2560

并且df:

$ df /dev/sda1
Filesystem           1K-blocks      Used Available Use% Mounted on
/dev/sda1             65792556  43694068  18726712  70% /var

网:

  • os.Stat()提供0但不是,但可能是操作系统问题。
  • syscall.Statfs()提供2560个块* 4096块大小= 10,485,760
  • 更现实,但仍然不正确
  • df给出65792556 1K块* 1024字节/ K = 67,371,577,344

如何在不安装块设备的情况下可靠地获得块设备的大小?

基本上,我正在寻找设备上ioctl调用的等价物。

ioctl(fd,BLKGETSIZE64,&size)

2 个答案:

答案 0 :(得分:5)

致电syscall.Statfs()时,您必须通过路径才能安装设备,例如/,而不是设备文件(不是/dev/sda1)。在您的情况下,这是/var

您将获得类型为syscall.Statfs_t的值的结果。解释:

var stat syscall.Statfs_t
if err := syscall.Statfs("/", &stat); err != nil {
    panic(err)
}

size := stat.Blocks * uint64(stat.Bsize)
free := stat.Bfree * uint64(stat.Bsize)
avail := stat.Bavail * uint64(stat.Bsize)
fmt.Println("Size:", size)
fmt.Println("Free:", free)
fmt.Println("Available:", avail)
fmt.Println("Used:", size-free)

请参阅此可能重复:Get amount of free disk space using Go

答案 1 :(得分:1)

OP询问如何获取块设备的大小。要获取块设备(或任何文件)的大小,可以使用io.SeekEnd将File.Seek移至文件末尾并读取返回的位置。将pythonC归功于其他人。

运行下面的示例getsize.go显示:

$ sudo go run getsize.go /dev/sda
/dev/sda is 256060514304 bytes.

lsblk --bytes /dev/device将为您提供相同的信息。那就是块设备可以存储多少数据。

Statfs_t路径和df /path/to/mounted/filesystem将为您提供有关在提供的路径处安装的文件系统中可以存储多少数据的信息。文件系统的开销取决于文件系统的详细信息,可能在2-5%的范围内,并且还要跟踪FreeUsed有多少空间。

据我所知,没有任何api可以提供有关块设备上已卸载文件系统的信息。 dumpe2fs可以为您提供ext {2,3,4}文件系统的信息。可能存在用于其他文件系统的工具。这样的工具是特定于文件系统的。挂载文件系统时,Linux内核的文件系统驱动程序将公开由df返回的信息。

代码:

// getsize.go: get the size of a block device or file
package main

import (
    "fmt"
    "io"
    "os"
)

func main() {
    var path string
    if len(os.Args) < 2 {
        fmt.Println("Give path to file/disk")
        os.Exit(1)
    }
    path = os.Args[1]
    file, err := os.Open(path)
    if err != nil {
        fmt.Printf("error opening %s: %s\n", path, err)
        os.Exit(1)
    }
    pos, err := file.Seek(0, io.SeekEnd)
    if err != nil {
        fmt.Printf("error seeking to end of %s: %s\n", path, err)
        os.Exit(1)
    }
    fmt.Printf("%s is %d bytes.\n", path, pos)
}