GO解析 - Linux 指令之 lsblk

版本

lsblk --version

lsblk from util-linux 2.38.1

代码

lsblkParser.go

go 复制代码
package utils

type LSBlkItem struct {
	Name       string // 名称
	Major      uint   // 主版本
	Minor      uint   // 此版本
	Removable  bool   // 可移除de
	Writable   bool   // 可写的
	Size       uint   // 大小字节
	Type       string // 类型, part是上一个磁盘的一部分,disk就是磁盘
	MountPoint string // 挂载点

	Parent *LSBlkItem // 父挂载点
}

type LSBlkParser struct {
}

lsblkParser_linux.go

go 复制代码
package utils

import (
	"errors"
	"os/exec"
	"strconv"
	"strings"
)

func (l *LSBlkParser) GetSizes(devNames []string) ([]LSBlkItem, error) {
	items, err := l.getItems()
	if nil != err {
		return nil, err
	}
	return items, err
}

func (l *LSBlkParser) getItems() ([]LSBlkItem, error) {
	/*
		-b 以字节显示磁盘大小
		-p 打印设备完整路径
	*/
	cmd := exec.Command("lsblk", "-b", "-p")
	bs, err := cmd.CombinedOutput()
	if nil != err {
		return nil, err
	}

	lines := strings.SplitN(string(bs), "\n", -1)
	var (
		isChild bool
		parent  *LSBlkItem
		items   = make([]LSBlkItem, 0)
	)
	for i, line := range lines {
		var item LSBlkItem
		if 0 == i || 0 >= len(line) {
			continue
		} // 第一行是标题行, 跳过
		item, isChild, err = l.getItem(line)
		if nil != err {
			return nil, err
		}
		if isChild {
			item.Parent = parent
		}
		items = append(items, item)
		if !isChild {
			parent = &items[len(items)-1]
		}
	}

	return items, err
}

func (l *LSBlkParser) getItem(line string) (item LSBlkItem, isChild bool, err error) {
	var (
		itemMinCnt = 6 // 字符串分解之后最少会有多少个
		//itemMaxCnt = 7
		currItemCnt = 0
	)
	/*
		NAME              MAJ:MIN RM        SIZE RO TYPE MOUNTPOINTS
		/dev/sda            8:0    1           0  0 disk
		/dev/sdb            8:16   1 31104958464  0 disk
		/dev/mmcblk0      179:0    0  7818182656  0 disk
		├─/dev/mmcblk0p1  179:1    0   536870912  0 part /boot/firmware
		└─/dev/mmcblk0p2  179:2    0  7277117440  0 part /
		/dev/mmcblk0boot0 179:32   0     4194304  1 disk
		/dev/mmcblk0boot1 179:64   0     4194304  1 disk
	*/
	strs := strings.Fields(line)
	currItemCnt = len(strs)
	if itemMinCnt > currItemCnt {
		return item, false, errors.New("item count not enough")
	}
	for i, str := range strs {
		switch i {
		case 0:
			if item.Name, err = l.getName(str); nil != err {
				return
			}
		case 1:
			if item.Major, item.Minor, err = l.getMajorMinor(str); nil != err {
				return
			}
		case 2:
			if item.Removable, err = l.getRemovable(str); nil != err {
				return
			}
		case 3:
			if item.Size, err = l.getSize(str); nil != err {
				return
			}
		case 4:
			if item.Writable, err = l.getWritable(str); nil != err {
				return
			}
		case 5:
			if item.Type, isChild, err = l.getType(str); nil != err {
				return
			}
		case 6:
			if item.MountPoint, err = l.getMountPoint(str); nil != err {
				return
			}
		}
	}

	return
}

func (l *LSBlkParser) getName(str string) (string, error) {
	for i := range str {
		if str[i] != '/' {
			continue
		}
		str = str[i:]
		return str, nil
	}

	return str, nil
}

func (l *LSBlkParser) getMajorMinor(str string) (major uint, minor uint, err error) {
	var temp uint64
	strs := strings.Split(str, ":") // 8:0
	for i := range strs {
		if temp, err = strconv.ParseUint(strs[i], 10, 32); nil != err {
			return
		}
		if 0 == i {
			major = uint(temp)
		} else if 1 == i {
			minor = uint(temp)
		} else {
			break
		}
	}
	return
}

func (l *LSBlkParser) getRemovable(str string) (bool, error) {
	temp, err := strconv.ParseUint(str, 10, 64)
	if nil != err {
		return false, err
	}
	if 0 == temp {
		return false, nil
	} else {
		return true, nil
	}
}

func (l *LSBlkParser) getSize(str string) (uint, error) {
	temp, err := strconv.ParseUint(str, 10, 64)
	if nil != err {
		return 0, err
	}
	return uint(temp), nil
}

func (l *LSBlkParser) getWritable(str string) (bool, error) {
	temp, err := strconv.ParseUint(str, 10, 64)
	if nil != err {
		return false, err
	}
	if 0 == temp {
		return true, nil
	} else {
		return false, nil
	}
}

func (l *LSBlkParser) getType(str string) (typ string, isChild bool, err error) {
	typ = str
	if 0 == strings.Compare(str, "disk") {
		isChild = false
	} else if 0 == strings.Compare(str, "part") {
		isChild = true
	}
	return
}

func (l *LSBlkParser) getMountPoint(str string) (string, error) {
	return str, nil
}

测试

main.go

go 复制代码
package main

import (
	"encoding/json"
	"fmt"
	"pi_gpio_test/utils"
)

func main() {
	var lsblkParser utils.LSBlkParser

	items, err := lsblkParser.GetSizes([]string{
		"/dev/sda", "/dev/sdb",
	})
	if nil != err {
		fmt.Println(err)
		return
	}

	for _, item := range items {
		bs, err := json.Marshal(item)
		fmt.Println(string(bs), err)
	}
}

结果

{"Name":"/dev/sda","Major":8,"Minor":0,"Removable":true,"Writable":true,"Size":0,"Type":"disk","MountPoint":"","Parent":null}

{"Name":"/dev/mmcblk0","Major":179,"Minor":0,"Removable":false,"Writable":true,"Size":3523215360,"Type":"disk","MountPoint":"","Parent":null}

{"Name":"├─/dev/mmcblk0p1","Major":179,"Minor":1,"Removable":false,"Writable":true,"Size":536870912,"Type":"part","MountPoint":"/boot/firmware","Parent":{"Name":"/dev/mmcblk0","Major":179,"Minor":0,"Removable":false,"Writable":true,"Size":3523215360,"Type":"disk","MountPoint":"","Parent":null}}

{"Name":"└─/dev/mmcblk0p2","Major":179,"Minor":2,"Removable":false,"Writable":true,"Size":2982150144,"Type":"part","MountPoint":"/","Parent":{"Name":"/dev/mmcblk0","Major":179,"Minor":0,"Removable":false,"Writable":true,"Size":3523215360,"Type":"disk","MountPoint":"","Parent":null}}

{"Name":"/dev/mmcblk0boot0","Major":179,"Minor":32,"Removable":false,"Writable":false,"Size":4194304,"Type":"disk","MountPoint":"","Parent":null}

{"Name":"/dev/mmcblk0boot1","Major":179,"Minor":64,"Removable":false,"Writable":false,"Size":4194304,"Type":"disk","MountPoint":"","Parent":null}

相关推荐
xuanzdhc4 分钟前
Linux 基础IO
linux·运维·服务器
愚润求学9 分钟前
【Linux】网络基础
linux·运维·网络
bantinghy40 分钟前
Linux进程单例模式运行
linux·服务器·单例模式
小和尚同志2 小时前
29.4k!使用 1Panel 来管理你的服务器吧
linux·运维
帽儿山的枪手2 小时前
为什么Linux需要3种NAT地址转换?一探究竟
linux·网络协议·安全
shadon1789 天前
回答 如何通过inode client的SSLVPN登录之后,访问需要通过域名才能打开的服务
linux
小米里的大麦9 天前
014 Linux 2.6内核进程调度队列(了解)
linux·运维·驱动开发
算法练习生9 天前
Linux文件元信息完全指南:权限、链接与时间属性
linux·运维·服务器
忘了ʷºᵇₐ9 天前
Linux系统能ping通ip但无法ping通域名的解决方法
linux·服务器·tcp/ip
浩浩测试一下9 天前
渗透测试指南(CS&&MSF):Windows 与 Linux 系统中的日志与文件痕迹清理
linux·运维·windows·安全·web安全·网络安全·系统安全