github.com/isyscore/isc-gobase@v1.5.3-0.20231218061332-cbc7451899e9/system/disk/disk_linux.go (about)

     1  //go:build linux
     2  
     3  package disk
     4  
     5  import (
     6  	"bufio"
     7  	"bytes"
     8  	"context"
     9  	"fmt"
    10  	"io/ioutil"
    11  	"os"
    12  	"path/filepath"
    13  	"strconv"
    14  	"strings"
    15  
    16  	"github.com/isyscore/isc-gobase/system/common"
    17  	"golang.org/x/sys/unix"
    18  )
    19  
    20  const (
    21  	SectorSize = 512
    22  )
    23  const (
    24  	// man statfs
    25  	ADFS_SUPER_MAGIC      = 0xadf5
    26  	AFFS_SUPER_MAGIC      = 0xADFF
    27  	BDEVFS_MAGIC          = 0x62646576
    28  	BEFS_SUPER_MAGIC      = 0x42465331
    29  	BFS_MAGIC             = 0x1BADFACE
    30  	BINFMTFS_MAGIC        = 0x42494e4d
    31  	BTRFS_SUPER_MAGIC     = 0x9123683E
    32  	CGROUP_SUPER_MAGIC    = 0x27e0eb
    33  	CIFS_MAGIC_NUMBER     = 0xFF534D42
    34  	CODA_SUPER_MAGIC      = 0x73757245
    35  	COH_SUPER_MAGIC       = 0x012FF7B7
    36  	CRAMFS_MAGIC          = 0x28cd3d45
    37  	DEBUGFS_MAGIC         = 0x64626720
    38  	DEVFS_SUPER_MAGIC     = 0x1373
    39  	DEVPTS_SUPER_MAGIC    = 0x1cd1
    40  	EFIVARFS_MAGIC        = 0xde5e81e4
    41  	EFS_SUPER_MAGIC       = 0x00414A53
    42  	EXT_SUPER_MAGIC       = 0x137D
    43  	EXT2_OLD_SUPER_MAGIC  = 0xEF51
    44  	EXT2_SUPER_MAGIC      = 0xEF53
    45  	EXT3_SUPER_MAGIC      = 0xEF53
    46  	EXT4_SUPER_MAGIC      = 0xEF53
    47  	FUSE_SUPER_MAGIC      = 0x65735546
    48  	FUTEXFS_SUPER_MAGIC   = 0xBAD1DEA
    49  	HFS_SUPER_MAGIC       = 0x4244
    50  	HFSPLUS_SUPER_MAGIC   = 0x482b
    51  	HOSTFS_SUPER_MAGIC    = 0x00c0ffee
    52  	HPFS_SUPER_MAGIC      = 0xF995E849
    53  	HUGETLBFS_MAGIC       = 0x958458f6
    54  	ISOFS_SUPER_MAGIC     = 0x9660
    55  	JFFS2_SUPER_MAGIC     = 0x72b6
    56  	JFS_SUPER_MAGIC       = 0x3153464a
    57  	MINIX_SUPER_MAGIC     = 0x137F /* orig. minix */
    58  	MINIX_SUPER_MAGIC2    = 0x138F /* 30 char minix */
    59  	MINIX2_SUPER_MAGIC    = 0x2468 /* minix V2 */
    60  	MINIX2_SUPER_MAGIC2   = 0x2478 /* minix V2, 30 char names */
    61  	MINIX3_SUPER_MAGIC    = 0x4d5a /* minix V3 fs, 60 char names */
    62  	MQUEUE_MAGIC          = 0x19800202
    63  	MSDOS_SUPER_MAGIC     = 0x4d44
    64  	NCP_SUPER_MAGIC       = 0x564c
    65  	NFS_SUPER_MAGIC       = 0x6969
    66  	NILFS_SUPER_MAGIC     = 0x3434
    67  	NTFS_SB_MAGIC         = 0x5346544e
    68  	OCFS2_SUPER_MAGIC     = 0x7461636f
    69  	OPENPROM_SUPER_MAGIC  = 0x9fa1
    70  	PIPEFS_MAGIC          = 0x50495045
    71  	PROC_SUPER_MAGIC      = 0x9fa0
    72  	PSTOREFS_MAGIC        = 0x6165676C
    73  	QNX4_SUPER_MAGIC      = 0x002f
    74  	QNX6_SUPER_MAGIC      = 0x68191122
    75  	RAMFS_MAGIC           = 0x858458f6
    76  	REISERFS_SUPER_MAGIC  = 0x52654973
    77  	ROMFS_MAGIC           = 0x7275
    78  	SELINUX_MAGIC         = 0xf97cff8c
    79  	SMACK_MAGIC           = 0x43415d53
    80  	SMB_SUPER_MAGIC       = 0x517B
    81  	SOCKFS_MAGIC          = 0x534F434B
    82  	SQUASHFS_MAGIC        = 0x73717368
    83  	SYSFS_MAGIC           = 0x62656572
    84  	SYSV2_SUPER_MAGIC     = 0x012FF7B6
    85  	SYSV4_SUPER_MAGIC     = 0x012FF7B5
    86  	TMPFS_MAGIC           = 0x01021994
    87  	UDF_SUPER_MAGIC       = 0x15013346
    88  	UFS_MAGIC             = 0x00011954
    89  	USBDEVICE_SUPER_MAGIC = 0x9fa2
    90  	V9FS_MAGIC            = 0x01021997
    91  	VXFS_SUPER_MAGIC      = 0xa501FCF5
    92  	XENFS_SUPER_MAGIC     = 0xabba1974
    93  	XENIX_SUPER_MAGIC     = 0x012FF7B4
    94  	XFS_SUPER_MAGIC       = 0x58465342
    95  	_XIAFS_SUPER_MAGIC    = 0x012FD16D
    96  
    97  	AFS_SUPER_MAGIC             = 0x5346414F
    98  	AUFS_SUPER_MAGIC            = 0x61756673
    99  	ANON_INODE_FS_SUPER_MAGIC   = 0x09041934
   100  	CEPH_SUPER_MAGIC            = 0x00C36400
   101  	ECRYPTFS_SUPER_MAGIC        = 0xF15F
   102  	FAT_SUPER_MAGIC             = 0x4006
   103  	FHGFS_SUPER_MAGIC           = 0x19830326
   104  	FUSEBLK_SUPER_MAGIC         = 0x65735546
   105  	FUSECTL_SUPER_MAGIC         = 0x65735543
   106  	GFS_SUPER_MAGIC             = 0x1161970
   107  	GPFS_SUPER_MAGIC            = 0x47504653
   108  	MTD_INODE_FS_SUPER_MAGIC    = 0x11307854
   109  	INOTIFYFS_SUPER_MAGIC       = 0x2BAD1DEA
   110  	ISOFS_R_WIN_SUPER_MAGIC     = 0x4004
   111  	ISOFS_WIN_SUPER_MAGIC       = 0x4000
   112  	JFFS_SUPER_MAGIC            = 0x07C0
   113  	KAFS_SUPER_MAGIC            = 0x6B414653
   114  	LUSTRE_SUPER_MAGIC          = 0x0BD00BD0
   115  	NFSD_SUPER_MAGIC            = 0x6E667364
   116  	PANFS_SUPER_MAGIC           = 0xAAD7AAEA
   117  	RPC_PIPEFS_SUPER_MAGIC      = 0x67596969
   118  	SECURITYFS_SUPER_MAGIC      = 0x73636673
   119  	UFS_BYTESWAPPED_SUPER_MAGIC = 0x54190100
   120  	VMHGFS_SUPER_MAGIC          = 0xBACBACBC
   121  	VZFS_SUPER_MAGIC            = 0x565A4653
   122  	ZFS_SUPER_MAGIC             = 0x2FC12FC1
   123  )
   124  
   125  // coreutils/src/stat.c
   126  var fsTypeMap = map[int64]string{
   127  	ADFS_SUPER_MAGIC:          "adfs",          /* 0xADF5 local */
   128  	AFFS_SUPER_MAGIC:          "affs",          /* 0xADFF local */
   129  	AFS_SUPER_MAGIC:           "afs",           /* 0x5346414F remote */
   130  	ANON_INODE_FS_SUPER_MAGIC: "anon-inode FS", /* 0x09041934 local */
   131  	AUFS_SUPER_MAGIC:          "aufs",          /* 0x61756673 remote */
   132  	//	AUTOFS_SUPER_MAGIC:          "autofs",              /* 0x0187 local */
   133  	BEFS_SUPER_MAGIC:            "befs",                /* 0x42465331 local */
   134  	BDEVFS_MAGIC:                "bdevfs",              /* 0x62646576 local */
   135  	BFS_MAGIC:                   "bfs",                 /* 0x1BADFACE local */
   136  	BINFMTFS_MAGIC:              "binfmt_misc",         /* 0x42494E4D local */
   137  	BTRFS_SUPER_MAGIC:           "btrfs",               /* 0x9123683E local */
   138  	CEPH_SUPER_MAGIC:            "ceph",                /* 0x00C36400 remote */
   139  	CGROUP_SUPER_MAGIC:          "cgroupfs",            /* 0x0027E0EB local */
   140  	CIFS_MAGIC_NUMBER:           "cifs",                /* 0xFF534D42 remote */
   141  	CODA_SUPER_MAGIC:            "coda",                /* 0x73757245 remote */
   142  	COH_SUPER_MAGIC:             "coh",                 /* 0x012FF7B7 local */
   143  	CRAMFS_MAGIC:                "cramfs",              /* 0x28CD3D45 local */
   144  	DEBUGFS_MAGIC:               "debugfs",             /* 0x64626720 local */
   145  	DEVFS_SUPER_MAGIC:           "devfs",               /* 0x1373 local */
   146  	DEVPTS_SUPER_MAGIC:          "devpts",              /* 0x1CD1 local */
   147  	ECRYPTFS_SUPER_MAGIC:        "ecryptfs",            /* 0xF15F local */
   148  	EFS_SUPER_MAGIC:             "efs",                 /* 0x00414A53 local */
   149  	EXT_SUPER_MAGIC:             "ext",                 /* 0x137D local */
   150  	EXT2_SUPER_MAGIC:            "ext2/ext3",           /* 0xEF53 local */
   151  	EXT2_OLD_SUPER_MAGIC:        "ext2",                /* 0xEF51 local */
   152  	FAT_SUPER_MAGIC:             "fat",                 /* 0x4006 local */
   153  	FHGFS_SUPER_MAGIC:           "fhgfs",               /* 0x19830326 remote */
   154  	FUSEBLK_SUPER_MAGIC:         "fuseblk",             /* 0x65735546 remote */
   155  	FUSECTL_SUPER_MAGIC:         "fusectl",             /* 0x65735543 remote */
   156  	FUTEXFS_SUPER_MAGIC:         "futexfs",             /* 0x0BAD1DEA local */
   157  	GFS_SUPER_MAGIC:             "gfs/gfs2",            /* 0x1161970 remote */
   158  	GPFS_SUPER_MAGIC:            "gpfs",                /* 0x47504653 remote */
   159  	HFS_SUPER_MAGIC:             "hfs",                 /* 0x4244 local */
   160  	HFSPLUS_SUPER_MAGIC:         "hfsplus",             /* 0x482b local */
   161  	HPFS_SUPER_MAGIC:            "hpfs",                /* 0xF995E849 local */
   162  	HUGETLBFS_MAGIC:             "hugetlbfs",           /* 0x958458F6 local */
   163  	MTD_INODE_FS_SUPER_MAGIC:    "inodefs",             /* 0x11307854 local */
   164  	INOTIFYFS_SUPER_MAGIC:       "inotifyfs",           /* 0x2BAD1DEA local */
   165  	ISOFS_SUPER_MAGIC:           "isofs",               /* 0x9660 local */
   166  	ISOFS_R_WIN_SUPER_MAGIC:     "isofs",               /* 0x4004 local */
   167  	ISOFS_WIN_SUPER_MAGIC:       "isofs",               /* 0x4000 local */
   168  	JFFS_SUPER_MAGIC:            "jffs",                /* 0x07C0 local */
   169  	JFFS2_SUPER_MAGIC:           "jffs2",               /* 0x72B6 local */
   170  	JFS_SUPER_MAGIC:             "jfs",                 /* 0x3153464A local */
   171  	KAFS_SUPER_MAGIC:            "k-afs",               /* 0x6B414653 remote */
   172  	LUSTRE_SUPER_MAGIC:          "lustre",              /* 0x0BD00BD0 remote */
   173  	MINIX_SUPER_MAGIC:           "minix",               /* 0x137F local */
   174  	MINIX_SUPER_MAGIC2:          "minix (30 char.)",    /* 0x138F local */
   175  	MINIX2_SUPER_MAGIC:          "minix v2",            /* 0x2468 local */
   176  	MINIX2_SUPER_MAGIC2:         "minix v2 (30 char.)", /* 0x2478 local */
   177  	MINIX3_SUPER_MAGIC:          "minix3",              /* 0x4D5A local */
   178  	MQUEUE_MAGIC:                "mqueue",              /* 0x19800202 local */
   179  	MSDOS_SUPER_MAGIC:           "msdos",               /* 0x4D44 local */
   180  	NCP_SUPER_MAGIC:             "novell",              /* 0x564C remote */
   181  	NFS_SUPER_MAGIC:             "nfs",                 /* 0x6969 remote */
   182  	NFSD_SUPER_MAGIC:            "nfsd",                /* 0x6E667364 remote */
   183  	NILFS_SUPER_MAGIC:           "nilfs",               /* 0x3434 local */
   184  	NTFS_SB_MAGIC:               "ntfs",                /* 0x5346544E local */
   185  	OPENPROM_SUPER_MAGIC:        "openprom",            /* 0x9FA1 local */
   186  	OCFS2_SUPER_MAGIC:           "ocfs2",               /* 0x7461636f remote */
   187  	PANFS_SUPER_MAGIC:           "panfs",               /* 0xAAD7AAEA remote */
   188  	PIPEFS_MAGIC:                "pipefs",              /* 0x50495045 remote */
   189  	PROC_SUPER_MAGIC:            "proc",                /* 0x9FA0 local */
   190  	PSTOREFS_MAGIC:              "pstorefs",            /* 0x6165676C local */
   191  	QNX4_SUPER_MAGIC:            "qnx4",                /* 0x002F local */
   192  	QNX6_SUPER_MAGIC:            "qnx6",                /* 0x68191122 local */
   193  	RAMFS_MAGIC:                 "ramfs",               /* 0x858458F6 local */
   194  	REISERFS_SUPER_MAGIC:        "reiserfs",            /* 0x52654973 local */
   195  	ROMFS_MAGIC:                 "romfs",               /* 0x7275 local */
   196  	RPC_PIPEFS_SUPER_MAGIC:      "rpc_pipefs",          /* 0x67596969 local */
   197  	SECURITYFS_SUPER_MAGIC:      "securityfs",          /* 0x73636673 local */
   198  	SELINUX_MAGIC:               "selinux",             /* 0xF97CFF8C local */
   199  	SMB_SUPER_MAGIC:             "smb",                 /* 0x517B remote */
   200  	SOCKFS_MAGIC:                "sockfs",              /* 0x534F434B local */
   201  	SQUASHFS_MAGIC:              "squashfs",            /* 0x73717368 local */
   202  	SYSFS_MAGIC:                 "sysfs",               /* 0x62656572 local */
   203  	SYSV2_SUPER_MAGIC:           "sysv2",               /* 0x012FF7B6 local */
   204  	SYSV4_SUPER_MAGIC:           "sysv4",               /* 0x012FF7B5 local */
   205  	TMPFS_MAGIC:                 "tmpfs",               /* 0x01021994 local */
   206  	UDF_SUPER_MAGIC:             "udf",                 /* 0x15013346 local */
   207  	UFS_MAGIC:                   "ufs",                 /* 0x00011954 local */
   208  	UFS_BYTESWAPPED_SUPER_MAGIC: "ufs",                 /* 0x54190100 local */
   209  	USBDEVICE_SUPER_MAGIC:       "usbdevfs",            /* 0x9FA2 local */
   210  	V9FS_MAGIC:                  "v9fs",                /* 0x01021997 local */
   211  	VMHGFS_SUPER_MAGIC:          "vmhgfs",              /* 0xBACBACBC remote */
   212  	VXFS_SUPER_MAGIC:            "vxfs",                /* 0xA501FCF5 local */
   213  	VZFS_SUPER_MAGIC:            "vzfs",                /* 0x565A4653 local */
   214  	XENFS_SUPER_MAGIC:           "xenfs",               /* 0xABBA1974 local */
   215  	XENIX_SUPER_MAGIC:           "xenix",               /* 0x012FF7B4 local */
   216  	XFS_SUPER_MAGIC:             "xfs",                 /* 0x58465342 local */
   217  	_XIAFS_SUPER_MAGIC:          "xia",                 /* 0x012FD16D local */
   218  	ZFS_SUPER_MAGIC:             "zfs",                 /* 0x2FC12FC1 local */
   219  }
   220  
   221  func PartitionsWithContext(ctx context.Context, all bool) ([]PartitionStat, error) {
   222  	useMounts := false
   223  
   224  	filename := common.HostProc("1/mountinfo")
   225  	lines, err := common.ReadLines(filename)
   226  	if err != nil {
   227  		if err != err.(*os.PathError) {
   228  			return nil, err
   229  		}
   230  		// if kernel does not support 1/mountinfo, fallback to 1/mounts (<2.6.26)
   231  		useMounts = true
   232  		filename = common.HostProc("1/mounts")
   233  		lines, err = common.ReadLines(filename)
   234  		if err != nil {
   235  			return nil, err
   236  		}
   237  	}
   238  
   239  	fs, err := getFileSystems()
   240  	if err != nil && !all {
   241  		return nil, err
   242  	}
   243  
   244  	ret := make([]PartitionStat, 0, len(lines))
   245  
   246  	for _, line := range lines {
   247  		var d PartitionStat
   248  		if useMounts {
   249  			fields := strings.Fields(line)
   250  
   251  			d = PartitionStat{
   252  				Device:     fields[0],
   253  				Mountpoint: unescapeFstab(fields[1]),
   254  				Fstype:     fields[2],
   255  				Opts:       fields[3],
   256  			}
   257  
   258  			if !all {
   259  				if d.Device == "none" || !common.StringsHas(fs, d.Fstype) {
   260  					continue
   261  				}
   262  			}
   263  		} else {
   264  			// a line of 1/mountinfo has the following structure:
   265  			// 36  35  98:0 /mnt1 /mnt2 rw,noatime master:1 - ext3 /dev/root rw,errors=continue
   266  			// (1) (2) (3)   (4)   (5)      (6)      (7)   (8) (9)   (10)         (11)
   267  
   268  			// split the mountinfo line by the separator hyphen
   269  			parts := strings.Split(line, " - ")
   270  			if len(parts) != 2 {
   271  				return nil, fmt.Errorf("found invalid mountinfo line in file %s: %s ", filename, line)
   272  			}
   273  
   274  			fields := strings.Fields(parts[0])
   275  			blockDeviceID := fields[2]
   276  			mountPoint := fields[4]
   277  			mountOpts := fields[5]
   278  
   279  			if rootDir := fields[3]; rootDir != "" && rootDir != "/" {
   280  				if len(mountOpts) == 0 {
   281  					mountOpts = "bind"
   282  				} else {
   283  					mountOpts = "bind," + mountOpts
   284  				}
   285  			}
   286  
   287  			fields = strings.Fields(parts[1])
   288  			fstype := fields[0]
   289  			device := fields[1]
   290  
   291  			d = PartitionStat{
   292  				Device:     device,
   293  				Mountpoint: unescapeFstab(mountPoint),
   294  				Fstype:     fstype,
   295  				Opts:       mountOpts,
   296  			}
   297  
   298  			if !all {
   299  				if d.Device == "none" || !common.StringsHas(fs, d.Fstype) {
   300  					continue
   301  				}
   302  			}
   303  
   304  			if strings.HasPrefix(d.Device, "/dev/mapper/") {
   305  				devpath, err := filepath.EvalSymlinks(common.HostDev(strings.Replace(d.Device, "/dev", "", -1)))
   306  				if err == nil {
   307  					d.Device = devpath
   308  				}
   309  			}
   310  
   311  			// /dev/root is not the real device name
   312  			// so we get the real device name from its major/minor number
   313  			if d.Device == "/dev/root" {
   314  				devpath, err := os.Readlink(common.HostSys("/dev/block/" + blockDeviceID))
   315  				if err != nil {
   316  					return nil, err
   317  				}
   318  				d.Device = strings.Replace(d.Device, "root", filepath.Base(devpath), 1)
   319  			}
   320  		}
   321  		ret = append(ret, d)
   322  	}
   323  
   324  	return ret, nil
   325  }
   326  
   327  // getFileSystems returns supported filesystems from /proc/filesystems
   328  func getFileSystems() ([]string, error) {
   329  	filename := common.HostProc("filesystems")
   330  	lines, err := common.ReadLines(filename)
   331  	if err != nil {
   332  		return nil, err
   333  	}
   334  	var ret []string
   335  	for _, line := range lines {
   336  		if !strings.HasPrefix(line, "nodev") {
   337  			ret = append(ret, strings.TrimSpace(line))
   338  			continue
   339  		}
   340  		t := strings.Split(line, "\t")
   341  		if len(t) != 2 || t[1] != "zfs" {
   342  			continue
   343  		}
   344  		ret = append(ret, strings.TrimSpace(t[1]))
   345  	}
   346  
   347  	return ret, nil
   348  }
   349  
   350  func IOCountersWithContext(ctx context.Context, names ...string) (map[string]IOCountersStat, error) {
   351  	filename := common.HostProc("diskstats")
   352  	lines, err := common.ReadLines(filename)
   353  	if err != nil {
   354  		return nil, err
   355  	}
   356  	ret := make(map[string]IOCountersStat, 0)
   357  	empty := IOCountersStat{}
   358  
   359  	// use only basename such as "/dev/sda1" to "sda1"
   360  	for i, name := range names {
   361  		names[i] = filepath.Base(name)
   362  	}
   363  
   364  	for _, line := range lines {
   365  		fields := strings.Fields(line)
   366  		if len(fields) < 14 {
   367  			// malformed line in /proc/diskstats, avoid panic by ignoring.
   368  			continue
   369  		}
   370  		name := fields[2]
   371  
   372  		if len(names) > 0 && !common.StringsHas(names, name) {
   373  			continue
   374  		}
   375  
   376  		reads, err := strconv.ParseUint((fields[3]), 10, 64)
   377  		if err != nil {
   378  			return ret, err
   379  		}
   380  		mergedReads, err := strconv.ParseUint((fields[4]), 10, 64)
   381  		if err != nil {
   382  			return ret, err
   383  		}
   384  		rbytes, err := strconv.ParseUint((fields[5]), 10, 64)
   385  		if err != nil {
   386  			return ret, err
   387  		}
   388  		rtime, err := strconv.ParseUint((fields[6]), 10, 64)
   389  		if err != nil {
   390  			return ret, err
   391  		}
   392  		writes, err := strconv.ParseUint((fields[7]), 10, 64)
   393  		if err != nil {
   394  			return ret, err
   395  		}
   396  		mergedWrites, err := strconv.ParseUint((fields[8]), 10, 64)
   397  		if err != nil {
   398  			return ret, err
   399  		}
   400  		wbytes, err := strconv.ParseUint((fields[9]), 10, 64)
   401  		if err != nil {
   402  			return ret, err
   403  		}
   404  		wtime, err := strconv.ParseUint((fields[10]), 10, 64)
   405  		if err != nil {
   406  			return ret, err
   407  		}
   408  		iopsInProgress, err := strconv.ParseUint((fields[11]), 10, 64)
   409  		if err != nil {
   410  			return ret, err
   411  		}
   412  		iotime, err := strconv.ParseUint((fields[12]), 10, 64)
   413  		if err != nil {
   414  			return ret, err
   415  		}
   416  		weightedIO, err := strconv.ParseUint((fields[13]), 10, 64)
   417  		if err != nil {
   418  			return ret, err
   419  		}
   420  		d := IOCountersStat{
   421  			ReadBytes:        rbytes * SectorSize,
   422  			WriteBytes:       wbytes * SectorSize,
   423  			ReadCount:        reads,
   424  			WriteCount:       writes,
   425  			MergedReadCount:  mergedReads,
   426  			MergedWriteCount: mergedWrites,
   427  			ReadTime:         rtime,
   428  			WriteTime:        wtime,
   429  			IopsInProgress:   iopsInProgress,
   430  			IoTime:           iotime,
   431  			WeightedIO:       weightedIO,
   432  		}
   433  		if d == empty {
   434  			continue
   435  		}
   436  		d.Name = name
   437  
   438  		d.SerialNumber = GetDiskSerialNumber(name)
   439  		d.Label = GetLabel(name)
   440  
   441  		ret[name] = d
   442  	}
   443  	return ret, nil
   444  }
   445  
   446  // GetDiskSerialNumber returns Serial Number of given device or empty string
   447  // on error. Name of device is expected, eg. /dev/sda
   448  func GetDiskSerialNumber(name string) string {
   449  	return GetDiskSerialNumberWithContext(context.Background(), name)
   450  }
   451  
   452  func GetDiskSerialNumberWithContext(ctx context.Context, name string) string {
   453  	var stat unix.Stat_t
   454  	err := unix.Stat(name, &stat)
   455  	if err != nil {
   456  		return ""
   457  	}
   458  	major := unix.Major(uint64(stat.Rdev))
   459  	minor := unix.Minor(uint64(stat.Rdev))
   460  
   461  	// Try to get the serial from udev data
   462  	udevDataPath := common.HostRun(fmt.Sprintf("udev/data/b%d:%d", major, minor))
   463  	if udevdata, err := ioutil.ReadFile(udevDataPath); err == nil {
   464  		scanner := bufio.NewScanner(bytes.NewReader(udevdata))
   465  		for scanner.Scan() {
   466  			values := strings.Split(scanner.Text(), "=")
   467  			if len(values) == 2 && values[0] == "E:ID_SERIAL" {
   468  				return values[1]
   469  			}
   470  		}
   471  	}
   472  
   473  	// Try to get the serial from sysfs, look at the disk device (minor 0) directly
   474  	// because if it is a partition it is not going to contain any device information
   475  	devicePath := common.HostSys(fmt.Sprintf("dev/block/%d:0/device", major))
   476  	model, _ := ioutil.ReadFile(filepath.Join(devicePath, "model"))
   477  	serial, _ := ioutil.ReadFile(filepath.Join(devicePath, "serial"))
   478  	if len(model) > 0 && len(serial) > 0 {
   479  		return fmt.Sprintf("%s_%s", string(model), string(serial))
   480  	}
   481  	return ""
   482  }
   483  
   484  // GetLabel returns label of given device or empty string on error.
   485  // Name of device is expected, eg. /dev/sda
   486  // Supports label based on devicemapper name
   487  // See https://www.kernel.org/doc/Documentation/ABI/testing/sysfs-block-dm
   488  func GetLabel(name string) string {
   489  	// Try label based on devicemapper name
   490  	dmname_filename := common.HostSys(fmt.Sprintf("block/%s/dm/name", name))
   491  
   492  	if !common.PathExists(dmname_filename) {
   493  		return ""
   494  	}
   495  
   496  	dmname, err := ioutil.ReadFile(dmname_filename)
   497  	if err != nil {
   498  		return ""
   499  	} else {
   500  		return strings.TrimSpace(string(dmname))
   501  	}
   502  }
   503  
   504  func getFsType(stat unix.Statfs_t) string {
   505  	t := int64(stat.Type)
   506  	ret, ok := fsTypeMap[t]
   507  	if !ok {
   508  		return ""
   509  	}
   510  	return ret
   511  }