653 lines
18 KiB
Go
653 lines
18 KiB
Go
// Use and distribution licensed under the Apache license version 2.
|
|
//
|
|
// See the COPYING file in the root project directory for full text.
|
|
//
|
|
|
|
package ghw
|
|
|
|
import (
|
|
"bufio"
|
|
"io"
|
|
"io/ioutil"
|
|
"os"
|
|
"path/filepath"
|
|
"regexp"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
const (
|
|
sectorSize = 512
|
|
)
|
|
|
|
func (ctx *context) blockFillInfo(info *BlockInfo) error {
|
|
info.Disks = ctx.disks()
|
|
var tpb uint64
|
|
for _, d := range info.Disks {
|
|
tpb += d.SizeBytes
|
|
}
|
|
info.TotalPhysicalBytes = tpb
|
|
return nil
|
|
}
|
|
|
|
// DiskPhysicalBlockSizeBytes has been deprecated in 0.2. Please use the
|
|
// Disk.PhysicalBlockSizeBytes attribute.
|
|
// TODO(jaypipes): Remove in 1.0.
|
|
func DiskPhysicalBlockSizeBytes(disk string) uint64 {
|
|
msg := `
|
|
The DiskPhysicalBlockSizeBytes() function has been DEPRECATED and will be
|
|
removed in the 1.0 release of ghw. Please use the Disk.PhysicalBlockSizeBytes
|
|
attribute.
|
|
`
|
|
warn(msg)
|
|
ctx := contextFromEnv()
|
|
return ctx.diskPhysicalBlockSizeBytes(disk)
|
|
}
|
|
|
|
func (ctx *context) diskPhysicalBlockSizeBytes(disk string) uint64 {
|
|
// We can find the sector size in Linux by looking at the
|
|
// /sys/block/$DEVICE/queue/physical_block_size file in sysfs
|
|
path := filepath.Join(ctx.pathSysBlock(), disk, "queue", "physical_block_size")
|
|
contents, err := ioutil.ReadFile(path)
|
|
if err != nil {
|
|
return 0
|
|
}
|
|
size, err := strconv.ParseUint(strings.TrimSpace(string(contents)), 10, 64)
|
|
if err != nil {
|
|
return 0
|
|
}
|
|
return size
|
|
}
|
|
|
|
// DiskSizeBytes has been deprecated in 0.2. Please use the Disk.SizeBytes
|
|
// attribute.
|
|
// TODO(jaypipes): Remove in 1.0.
|
|
func DiskSizeBytes(disk string) uint64 {
|
|
msg := `
|
|
The DiskSizeBytes() function has been DEPRECATED and will be
|
|
removed in the 1.0 release of ghw. Please use the Disk.SizeBytes attribute.
|
|
`
|
|
warn(msg)
|
|
ctx := contextFromEnv()
|
|
return ctx.diskSizeBytes(disk)
|
|
}
|
|
|
|
func (ctx *context) diskSizeBytes(disk string) uint64 {
|
|
// We can find the number of 512-byte sectors by examining the contents of
|
|
// /sys/block/$DEVICE/size and calculate the physical bytes accordingly.
|
|
path := filepath.Join(ctx.pathSysBlock(), disk, "size")
|
|
contents, err := ioutil.ReadFile(path)
|
|
if err != nil {
|
|
return 0
|
|
}
|
|
size, err := strconv.ParseUint(strings.TrimSpace(string(contents)), 10, 64)
|
|
if err != nil {
|
|
return 0
|
|
}
|
|
return size * sectorSize
|
|
}
|
|
|
|
// DiskNUMANodeID has been deprecated in 0.2. Please use the Disk.NUMANodeID
|
|
// attribute.
|
|
// TODO(jaypipes): Remove in 1.0.
|
|
func DiskNUMANodeID(disk string) int {
|
|
msg := `
|
|
The DiskNUMANodeID() function has been DEPRECATED and will be
|
|
removed in the 1.0 release of ghw. Please use the Disk.NUMANodeID attribute.
|
|
`
|
|
warn(msg)
|
|
ctx := contextFromEnv()
|
|
return ctx.diskNUMANodeID(disk)
|
|
}
|
|
|
|
func (ctx *context) diskNUMANodeID(disk string) int {
|
|
link, err := os.Readlink(filepath.Join(ctx.pathSysBlock(), disk))
|
|
if err != nil {
|
|
return -1
|
|
}
|
|
for partial := link; strings.HasPrefix(partial, "../devices/"); partial = filepath.Base(partial) {
|
|
if nodeContents, err := ioutil.ReadFile(filepath.Join(ctx.pathSysBlock(), partial, "numa_node")); err != nil {
|
|
if nodeInt, err := strconv.Atoi(string(nodeContents)); err != nil {
|
|
return nodeInt
|
|
}
|
|
}
|
|
}
|
|
return -1
|
|
}
|
|
|
|
// DiskVendor has been deprecated in 0.2. Please use the Disk.Vendor attribute.
|
|
// TODO(jaypipes): Remove in 1.0.
|
|
func DiskVendor(disk string) string {
|
|
msg := `
|
|
The DiskVendor() function has been DEPRECATED and will be
|
|
removed in the 1.0 release of ghw. Please use the Disk.Vendor attribute.
|
|
`
|
|
warn(msg)
|
|
ctx := contextFromEnv()
|
|
return ctx.diskVendor(disk)
|
|
}
|
|
|
|
func (ctx *context) diskVendor(disk string) string {
|
|
// In Linux, the vendor for a disk device is found in the
|
|
// /sys/block/$DEVICE/device/vendor file in sysfs
|
|
path := filepath.Join(ctx.pathSysBlock(), disk, "device", "vendor")
|
|
contents, err := ioutil.ReadFile(path)
|
|
if err != nil {
|
|
return UNKNOWN
|
|
}
|
|
return strings.TrimSpace(string(contents))
|
|
}
|
|
|
|
func (ctx *context) udevInfo(disk string) (map[string]string, error) {
|
|
// Get device major:minor numbers
|
|
devNo, err := ioutil.ReadFile(filepath.Join(ctx.pathSysBlock(), disk, "dev"))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Look up block device in udev runtime database
|
|
udevID := "b" + strings.TrimSpace(string(devNo))
|
|
udevBytes, err := ioutil.ReadFile(filepath.Join(ctx.pathRunUdevData(), udevID))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
udevInfo := make(map[string]string)
|
|
for _, udevLine := range strings.Split(string(udevBytes), "\n") {
|
|
if strings.HasPrefix(udevLine, "E:") {
|
|
if s := strings.SplitN(udevLine[2:], "=", 2); len(s) == 2 {
|
|
udevInfo[s[0]] = s[1]
|
|
}
|
|
}
|
|
}
|
|
return udevInfo, nil
|
|
}
|
|
|
|
// DiskModel has been deprecated in 0.2. Please use the Disk.Model attribute.
|
|
// TODO(jaypipes): Remove in 1.0.
|
|
func DiskModel(disk string) string {
|
|
msg := `
|
|
The DiskModel() function has been DEPRECATED and will be removed in the 1.0
|
|
release of ghw. Please use the Disk.Model attribute.
|
|
`
|
|
warn(msg)
|
|
ctx := contextFromEnv()
|
|
return ctx.diskModel(disk)
|
|
}
|
|
|
|
func (ctx *context) diskModel(disk string) string {
|
|
info, err := ctx.udevInfo(disk)
|
|
if err != nil {
|
|
return UNKNOWN
|
|
}
|
|
|
|
if model, ok := info["ID_MODEL"]; ok {
|
|
return model
|
|
}
|
|
return UNKNOWN
|
|
}
|
|
|
|
// DiskSerialNumber has been deprecated in 0.2. Please use the Disk.SerialNumber attribute.
|
|
// TODO(jaypipes): Remove in 1.0.
|
|
func DiskSerialNumber(disk string) string {
|
|
msg := `
|
|
The DiskSerialNumber() function has been DEPRECATED and will be removed in the
|
|
1.0 release of ghw. Please use the Disk.SerialNumber attribute.
|
|
`
|
|
warn(msg)
|
|
ctx := contextFromEnv()
|
|
return ctx.diskSerialNumber(disk)
|
|
}
|
|
|
|
func (ctx *context) diskSerialNumber(disk string) string {
|
|
info, err := ctx.udevInfo(disk)
|
|
if err != nil {
|
|
return UNKNOWN
|
|
}
|
|
|
|
// There are two serial number keys, ID_SERIAL and ID_SERIAL_SHORT
|
|
// The non-_SHORT version often duplicates vendor information collected elsewhere, so use _SHORT.
|
|
if serial, ok := info["ID_SERIAL_SHORT"]; ok {
|
|
return serial
|
|
}
|
|
return UNKNOWN
|
|
}
|
|
|
|
// DiskBusPath has been deprecated in 0.2. Please use the Disk.BusPath attribute.
|
|
// TODO(jaypipes): Remove in 1.0.
|
|
func DiskBusPath(disk string) string {
|
|
msg := `
|
|
The DiskBusPath() function has been DEPRECATED and will be removed in the 1.0
|
|
release of ghw. Please use the Disk.BusPath attribute.
|
|
`
|
|
warn(msg)
|
|
ctx := contextFromEnv()
|
|
return ctx.diskBusPath(disk)
|
|
}
|
|
|
|
func (ctx *context) diskBusPath(disk string) string {
|
|
info, err := ctx.udevInfo(disk)
|
|
if err != nil {
|
|
return UNKNOWN
|
|
}
|
|
|
|
// There are two path keys, ID_PATH and ID_PATH_TAG.
|
|
// The difference seems to be _TAG has funky characters converted to underscores.
|
|
if path, ok := info["ID_PATH"]; ok {
|
|
return path
|
|
}
|
|
return UNKNOWN
|
|
}
|
|
|
|
// DiskWWN has been deprecated in 0.2. Please use the Disk.WWN attribute.
|
|
// TODO(jaypipes): Remove in 1.0.
|
|
func DiskWWN(disk string) string {
|
|
msg := `
|
|
The DiskWWN() function has been DEPRECATED and will be removed in the 1.0
|
|
release of ghw. Please use the Disk.WWN attribute.
|
|
`
|
|
warn(msg)
|
|
ctx := contextFromEnv()
|
|
return ctx.diskWWN(disk)
|
|
}
|
|
|
|
func (ctx *context) diskWWN(disk string) string {
|
|
info, err := ctx.udevInfo(disk)
|
|
if err != nil {
|
|
return UNKNOWN
|
|
}
|
|
|
|
// Trying ID_WWN_WITH_EXTENSION and falling back to ID_WWN is the same logic lsblk uses
|
|
if wwn, ok := info["ID_WWN_WITH_EXTENSION"]; ok {
|
|
return wwn
|
|
}
|
|
if wwn, ok := info["ID_WWN"]; ok {
|
|
return wwn
|
|
}
|
|
return UNKNOWN
|
|
}
|
|
|
|
// DiskPartitions has been deprecated in 0.2. Please use the Disk.Partitions attribute.
|
|
// TODO(jaypipes): Remove in 1.0.
|
|
func DiskPartitions(disk string) []*Partition {
|
|
msg := `
|
|
The DiskPartitions() function has been DEPRECATED and will be removed in the
|
|
1.0 release of ghw. Please use the Disk.Partitions attribute.
|
|
`
|
|
warn(msg)
|
|
ctx := contextFromEnv()
|
|
return ctx.diskPartitions(disk)
|
|
}
|
|
|
|
// diskPartitions takes the name of a disk (note: *not* the path of the disk,
|
|
// but just the name. In other words, "sda", not "/dev/sda" and "nvme0n1" not
|
|
// "/dev/nvme0n1") and returns a slice of pointers to Partition structs
|
|
// representing the partitions in that disk
|
|
func (ctx *context) diskPartitions(disk string) []*Partition {
|
|
out := make([]*Partition, 0)
|
|
path := filepath.Join(ctx.pathSysBlock(), disk)
|
|
files, err := ioutil.ReadDir(path)
|
|
if err != nil {
|
|
warn("failed to read disk partitions: %s\n", err)
|
|
return out
|
|
}
|
|
for _, file := range files {
|
|
fname := file.Name()
|
|
if !strings.HasPrefix(fname, disk) {
|
|
continue
|
|
}
|
|
size := ctx.partitionSizeBytes(disk, fname)
|
|
mp, pt, ro := ctx.partitionInfo(fname)
|
|
p := &Partition{
|
|
Name: fname,
|
|
SizeBytes: size,
|
|
MountPoint: mp,
|
|
Type: pt,
|
|
IsReadOnly: ro,
|
|
}
|
|
out = append(out, p)
|
|
}
|
|
return out
|
|
}
|
|
|
|
func (ctx *context) diskIsRemovable(disk string) bool {
|
|
path := filepath.Join(ctx.pathSysBlock(), disk, "removable")
|
|
contents, err := ioutil.ReadFile(path)
|
|
if err != nil {
|
|
return false
|
|
}
|
|
removable := strings.TrimSpace(string(contents))
|
|
if removable == "1" {
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
// Disks has been deprecated in 0.2. Please use the BlockInfo.Disks attribute.
|
|
// TODO(jaypipes): Remove in 1.0.
|
|
func Disks() []*Disk {
|
|
msg := `
|
|
The Disks() function has been DEPRECATED and will be removed in the
|
|
1.0 release of ghw. Please use the BlockInfo.Disks attribute.
|
|
`
|
|
warn(msg)
|
|
ctx := contextFromEnv()
|
|
return ctx.disks()
|
|
}
|
|
|
|
func (ctx *context) disks() []*Disk {
|
|
// In Linux, we could use the fdisk, lshw or blockdev commands to list disk
|
|
// information, however all of these utilities require root privileges to
|
|
// run. We can get all of this information by examining the /sys/block
|
|
// and /sys/class/block files
|
|
disks := make([]*Disk, 0)
|
|
files, err := ioutil.ReadDir(ctx.pathSysBlock())
|
|
if err != nil {
|
|
return nil
|
|
}
|
|
for _, file := range files {
|
|
dname := file.Name()
|
|
if strings.HasPrefix(dname, "loop") {
|
|
continue
|
|
}
|
|
|
|
driveType, storageController, busType := diskTypes(dname)
|
|
// TODO(jaypipes): Move this into diskTypes() once abstracting
|
|
// diskIsRotational for ease of unit testing
|
|
if !ctx.diskIsRotational(dname) {
|
|
driveType = DRIVE_TYPE_SSD
|
|
}
|
|
size := ctx.diskSizeBytes(dname)
|
|
pbs := ctx.diskPhysicalBlockSizeBytes(dname)
|
|
busPath := ctx.diskBusPath(dname)
|
|
node := ctx.diskNUMANodeID(dname)
|
|
vendor := ctx.diskVendor(dname)
|
|
model := ctx.diskModel(dname)
|
|
serialNo := ctx.diskSerialNumber(dname)
|
|
wwn := ctx.diskWWN(dname)
|
|
removable := ctx.diskIsRemovable(dname)
|
|
|
|
d := &Disk{
|
|
Name: dname,
|
|
SizeBytes: size,
|
|
PhysicalBlockSizeBytes: pbs,
|
|
DriveType: driveType,
|
|
IsRemovable: removable,
|
|
StorageController: storageController,
|
|
BusType: busType,
|
|
BusPath: busPath,
|
|
NUMANodeID: node,
|
|
Vendor: vendor,
|
|
Model: model,
|
|
SerialNumber: serialNo,
|
|
WWN: wwn,
|
|
}
|
|
|
|
parts := ctx.diskPartitions(dname)
|
|
// Map this Disk object into the Partition...
|
|
for _, part := range parts {
|
|
part.Disk = d
|
|
}
|
|
d.Partitions = parts
|
|
|
|
disks = append(disks, d)
|
|
}
|
|
|
|
return disks
|
|
}
|
|
|
|
// diskTypes returns the drive type, storage controller and bus type of a disk
|
|
func diskTypes(dname string) (
|
|
DriveType,
|
|
StorageController,
|
|
BusType,
|
|
) {
|
|
// The conditionals below which set the controller and drive type are
|
|
// based on information listed here:
|
|
// https://en.wikipedia.org/wiki/Device_file
|
|
busType := BUS_TYPE_UNKNOWN
|
|
driveType := DRIVE_TYPE_UNKNOWN
|
|
storageController := STORAGE_CONTROLLER_UNKNOWN
|
|
if strings.HasPrefix(dname, "fd") {
|
|
driveType = DRIVE_TYPE_FDD
|
|
} else if strings.HasPrefix(dname, "sd") {
|
|
driveType = DRIVE_TYPE_HDD
|
|
busType = BUS_TYPE_SCSI
|
|
storageController = STORAGE_CONTROLLER_SCSI
|
|
} else if strings.HasPrefix(dname, "hd") {
|
|
driveType = DRIVE_TYPE_HDD
|
|
busType = BUS_TYPE_IDE
|
|
storageController = STORAGE_CONTROLLER_IDE
|
|
} else if strings.HasPrefix(dname, "vd") {
|
|
driveType = DRIVE_TYPE_HDD
|
|
busType = BUS_TYPE_VIRTIO
|
|
storageController = STORAGE_CONTROLLER_VIRTIO
|
|
} else if strings.HasPrefix(dname, "nvme") {
|
|
driveType = DRIVE_TYPE_SSD
|
|
busType = BUS_TYPE_NVME
|
|
storageController = STORAGE_CONTROLLER_NVME
|
|
} else if strings.HasPrefix(dname, "sr") {
|
|
driveType = DRIVE_TYPE_ODD
|
|
busType = BUS_TYPE_SCSI
|
|
storageController = STORAGE_CONTROLLER_SCSI
|
|
} else if strings.HasPrefix(dname, "xvd") {
|
|
driveType = DRIVE_TYPE_HDD
|
|
busType = BUS_TYPE_SCSI
|
|
storageController = STORAGE_CONTROLLER_SCSI
|
|
} else if strings.HasPrefix(dname, "mmc") {
|
|
driveType = DRIVE_TYPE_SSD
|
|
busType = BUS_TYPE_UNKNOWN
|
|
storageController = STORAGE_CONTROLLER_MMC
|
|
}
|
|
|
|
return driveType, storageController, busType
|
|
}
|
|
|
|
func (ctx *context) diskIsRotational(devName string) bool {
|
|
path := filepath.Join(ctx.pathSysBlock(), devName, "queue", "rotational")
|
|
contents := safeIntFromFile(path)
|
|
return contents == 1
|
|
}
|
|
|
|
// PartitionSizeBytes has been deprecated in 0.2. Please use the
|
|
// Partition.SizeBytes attribute. TODO(jaypipes): Remove in 1.0.
|
|
func PartitionSizeBytes(part string) uint64 {
|
|
msg := `
|
|
The PartitionSizeBytes() function has been DEPRECATED and will be removed in
|
|
the 1.0 release of ghw. Please use the Partition.SizeBytes attribute.
|
|
`
|
|
warn(msg)
|
|
ctx := contextFromEnv()
|
|
disk := strings.TrimPrefix(part, "/dev")
|
|
if len(disk) < 3 {
|
|
warn("PartitionSizeBytes: unknown disk %s, returning 0\n", disk)
|
|
return 0
|
|
}
|
|
switch disk[0:2] {
|
|
case "fd":
|
|
case "sd":
|
|
case "hd":
|
|
case "vd":
|
|
case "sr":
|
|
case "mm":
|
|
disk = disk[0:3]
|
|
case "xv":
|
|
disk = disk[0:4]
|
|
case "nv":
|
|
// NOTE(jaypipes): I'm putting this regex here instead of a const
|
|
// because this function is the only thing that uses it and I'm
|
|
// deprecating this function in 1.0
|
|
// nvme0n1p2
|
|
var regexNVMeDev = regexp.MustCompile(`^nvme\d+n\d+$`)
|
|
matches := regexNVMeDev.FindSubmatch([]byte(disk))
|
|
if len(matches) < 1 {
|
|
warn("PartitionSizeBytes: unknown disk %s, returning 0\n", disk)
|
|
return 0
|
|
}
|
|
disk = string(matches[0])
|
|
}
|
|
return ctx.partitionSizeBytes(disk, part)
|
|
}
|
|
|
|
// partitionSizeBytes returns the size in bytes of the partition given a disk
|
|
// name and a partition name. Note: disk name and partition name do *not*
|
|
// contain any leading "/dev" parts. In other words, they are *names*, not
|
|
// paths.
|
|
func (ctx *context) partitionSizeBytes(disk string, part string) uint64 {
|
|
path := filepath.Join(ctx.pathSysBlock(), disk, part, "size")
|
|
contents, err := ioutil.ReadFile(path)
|
|
if err != nil {
|
|
return 0
|
|
}
|
|
size, err := strconv.ParseUint(strings.TrimSpace(string(contents)), 10, 64)
|
|
if err != nil {
|
|
return 0
|
|
}
|
|
return size * sectorSize
|
|
}
|
|
|
|
// PartitionInfo has been deprecated in 0.2. Please use the Partition struct.
|
|
// TODO(jaypipes): Remove in 1.0.
|
|
func PartitionInfo(part string) (string, string, bool) {
|
|
msg := `
|
|
The PartitionInfo() function has been DEPRECATED and will be removed in
|
|
the 1.0 release of ghw. Please use the Partition struct.
|
|
`
|
|
warn(msg)
|
|
ctx := contextFromEnv()
|
|
return ctx.partitionInfo(part)
|
|
}
|
|
|
|
// Given a full or short partition name, returns the mount point, the type of
|
|
// the partition and whether it's readonly
|
|
func (ctx *context) partitionInfo(part string) (string, string, bool) {
|
|
// Allow calling PartitionInfo with either the full partition name
|
|
// "/dev/sda1" or just "sda1"
|
|
if !strings.HasPrefix(part, "/dev") {
|
|
part = "/dev/" + part
|
|
}
|
|
|
|
// /etc/mtab entries for mounted partitions look like this:
|
|
// /dev/sda6 / ext4 rw,relatime,errors=remount-ro,data=ordered 0 0
|
|
var r io.ReadCloser
|
|
r, err := os.Open(ctx.pathEtcMtab())
|
|
if err != nil {
|
|
return "", "", true
|
|
}
|
|
defer safeClose(r)
|
|
|
|
scanner := bufio.NewScanner(r)
|
|
for scanner.Scan() {
|
|
line := scanner.Text()
|
|
entry := parseMtabEntry(line)
|
|
if entry == nil || entry.Partition != part {
|
|
continue
|
|
}
|
|
ro := true
|
|
for _, opt := range entry.Options {
|
|
if opt == "rw" {
|
|
ro = false
|
|
break
|
|
}
|
|
}
|
|
|
|
return entry.Mountpoint, entry.FilesystemType, ro
|
|
}
|
|
return "", "", true
|
|
}
|
|
|
|
type mtabEntry struct {
|
|
Partition string
|
|
Mountpoint string
|
|
FilesystemType string
|
|
Options []string
|
|
}
|
|
|
|
func parseMtabEntry(line string) *mtabEntry {
|
|
// /etc/mtab entries for mounted partitions look like this:
|
|
// /dev/sda6 / ext4 rw,relatime,errors=remount-ro,data=ordered 0 0
|
|
if line[0] != '/' {
|
|
return nil
|
|
}
|
|
fields := strings.Fields(line)
|
|
|
|
if len(fields) < 4 {
|
|
return nil
|
|
}
|
|
|
|
// We do some special parsing of the mountpoint, which may contain space,
|
|
// tab and newline characters, encoded into the mtab entry line using their
|
|
// octal-to-string representations. From the GNU mtab man pages:
|
|
//
|
|
// "Therefore these characters are encoded in the files and the getmntent
|
|
// function takes care of the decoding while reading the entries back in.
|
|
// '\040' is used to encode a space character, '\011' to encode a tab
|
|
// character, '\012' to encode a newline character, and '\\' to encode a
|
|
// backslash."
|
|
mp := fields[1]
|
|
r := strings.NewReplacer(
|
|
"\\011", "\t", "\\012", "\n", "\\040", " ", "\\\\", "\\",
|
|
)
|
|
mp = r.Replace(mp)
|
|
|
|
res := &mtabEntry{
|
|
Partition: fields[0],
|
|
Mountpoint: mp,
|
|
FilesystemType: fields[2],
|
|
}
|
|
opts := strings.Split(fields[3], ",")
|
|
res.Options = opts
|
|
return res
|
|
}
|
|
|
|
// PartitionMountPoint has been deprecated in 0.2. Please use the
|
|
// Partition.MountPoint attribute. TODO(jaypipes): Remove in 1.0.
|
|
func PartitionMountPoint(part string) string {
|
|
msg := `
|
|
The PartitionMountPoint() function has been DEPRECATED and will be removed in
|
|
the 1.0 release of ghw. Please use the Partition.MountPoint attribute.
|
|
`
|
|
warn(msg)
|
|
ctx := contextFromEnv()
|
|
return ctx.partitionMountPoint(part)
|
|
}
|
|
|
|
func (ctx *context) partitionMountPoint(part string) string {
|
|
mp, _, _ := ctx.partitionInfo(part)
|
|
return mp
|
|
}
|
|
|
|
// PartitionType has been deprecated in 0.2. Please use the
|
|
// Partition.Type attribute. TODO(jaypipes): Remove in 1.0.
|
|
func PartitionType(part string) string {
|
|
msg := `
|
|
The PartitionType() function has been DEPRECATED and will be removed in
|
|
the 1.0 release of ghw. Please use the Partition.Type attribute.
|
|
`
|
|
warn(msg)
|
|
ctx := contextFromEnv()
|
|
return ctx.partitionType(part)
|
|
}
|
|
|
|
func (ctx *context) partitionType(part string) string {
|
|
_, pt, _ := ctx.partitionInfo(part)
|
|
return pt
|
|
}
|
|
|
|
// PartitionIsReadOnly has been deprecated in 0.2. Please use the
|
|
// Partition.IsReadOnly attribute. TODO(jaypipes): Remove in 1.0.
|
|
func PartitionIsReadOnly(part string) bool {
|
|
msg := `
|
|
The PartitionIsReadOnly() function has been DEPRECATED and will be removed in
|
|
the 1.0 release of ghw. Please use the Partition.IsReadOnly attribute.
|
|
`
|
|
warn(msg)
|
|
ctx := contextFromEnv()
|
|
return ctx.partitionIsReadOnly(part)
|
|
}
|
|
|
|
func (ctx *context) partitionIsReadOnly(part string) bool {
|
|
_, _, ro := ctx.partitionInfo(part)
|
|
return ro
|
|
}
|