1
0
mirror of https://github.com/coreos/ignition.git synced 2026-02-06 18:47:54 +01:00
Files
ignition/internal/exec/util/blkid.go
pkucode 547291cd15 chore: fix function name
Signed-off-by: pkucode <cssjtu@163.com>
2024-08-07 18:13:14 +08:00

215 lines
6.3 KiB
Go

// Copyright 2015 CoreOS, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//go:build linux
// +build linux
package util
// We want at least this warning, since the default C behavior of
// assuming int foo(int) is totally broken.
// #cgo CFLAGS: -Werror=implicit-function-declaration
// #cgo LDFLAGS: -lblkid
// #include <stdlib.h>
// #include "blkid.h"
import "C"
import (
"bytes"
"errors"
"fmt"
"strings"
"unsafe"
"github.com/coreos/ignition/v2/config/util"
)
const (
field_name_type = "TYPE"
field_name_uuid = "UUID"
field_name_label = "LABEL"
)
type DiskInfo struct {
LogicalSectorSize int // 4k or 512
Partitions []PartitionInfo
}
func (d DiskInfo) GetPartition(n int) (PartitionInfo, bool) {
for _, part := range d.Partitions {
if part.Number == n {
return part, true
}
}
return PartitionInfo{}, false
}
type PartitionInfo struct {
Label string
GUID string
TypeGUID string
StartSector int64
SizeInSectors int64
Number int
}
type FilesystemInfo struct {
Type string
UUID string
Label string
}
// If allowAmbivalent is false, fail if we find traces of more than one
// filesystem on the device.
func GetFilesystemInfo(device string, allowAmbivalent bool) (FilesystemInfo, error) {
var info FilesystemInfo
var err error
info.Type, err = filesystemLookup(device, allowAmbivalent, field_name_type)
if err != nil {
return FilesystemInfo{}, err
}
info.UUID, err = filesystemLookup(device, allowAmbivalent, field_name_uuid)
if err != nil {
return FilesystemInfo{}, err
}
info.Label, err = filesystemLookup(device, allowAmbivalent, field_name_label)
if err != nil {
return FilesystemInfo{}, err
}
return info, nil
}
// cResultToErr takes a result_t from the blkid c code and returns a golang
// error describing the result code.
func cResultToErr(res C.result_t) error {
switch res {
case C.RESULT_OK:
return nil
case C.RESULT_OPEN_FAILED:
return errors.New("failed to open")
case C.RESULT_PROBE_AMBIVALENT:
return errors.New("found multiple filesystem types")
case C.RESULT_PROBE_FAILED:
return errors.New("failed to probe")
case C.RESULT_LOOKUP_FAILED:
return errors.New("failed to look up attribute")
case C.RESULT_NO_PARTITION_TABLE:
return errors.New("no partition table found")
case C.RESULT_BAD_INDEX:
return errors.New("bad partition index specified")
case C.RESULT_GET_PARTLIST_FAILED:
return errors.New("failed to get list of partitions")
case C.RESULT_GET_CACHE_FAILED:
return fmt.Errorf("failed to retrieve cache")
case C.RESULT_DISK_HAS_NO_TYPE:
return errors.New("disk has no type string, despite having a partition table")
case C.RESULT_DISK_NOT_GPT:
return errors.New("disk does not have a GPT")
case C.RESULT_BAD_PARAMS:
return errors.New("bad parameters passed")
case C.RESULT_OVERFLOW:
return errors.New("return value doesn't fit in buffer")
case C.RESULT_MAX_BLOCK_DEVICES:
return fmt.Errorf("found too many filesystems of the specified type")
case C.RESULT_NO_TOPO:
return errors.New("failed to get topology information")
case C.RESULT_NO_SECTOR_SIZE:
return errors.New("failed to get logical sector size")
case C.RESULT_BAD_SECTOR_SIZE:
return errors.New("logical sector size is not a multiple of 512")
default:
return fmt.Errorf("unknown error: %d", res)
}
}
func CBufToGoStr(s [C.PART_INFO_BUF_SIZE]C.char) string {
return C.GoString(&s[0])
}
func CBufToGoPtr(s [C.PART_INFO_BUF_SIZE]C.char) *string {
return util.StrToPtr(CBufToGoStr(s))
}
// DumpDisk returns a list of all partitions on device (e.g. /dev/vda). The list
// of partitions returned is unordered.
func DumpDisk(device string) (DiskInfo, error) {
output := DiskInfo{}
var cInfo C.struct_partition_info
cDevice := C.CString(device)
defer C.free(unsafe.Pointer(cDevice))
var sectorSize C.int
if err := cResultToErr(C.blkid_get_logical_sector_size(cDevice, &sectorSize)); err != nil {
return DiskInfo{}, fmt.Errorf("getting sector size of %q: %w", device, err)
}
output.LogicalSectorSize = int(sectorSize)
numParts := C.int(0)
if err := cResultToErr(C.blkid_get_num_partitions(cDevice, &numParts)); err != nil {
return DiskInfo{}, fmt.Errorf("getting partition count of %q: %w", device, err)
}
for i := 0; i < int(numParts); i++ {
if err := cResultToErr(C.blkid_get_partition(cDevice, C.int(i), &cInfo)); err != nil {
return DiskInfo{}, fmt.Errorf("querying partition %d of %q: %w", i, device, err)
}
current := PartitionInfo{
Label: CBufToGoStr(cInfo.label),
GUID: strings.ToUpper(CBufToGoStr(cInfo.uuid)),
TypeGUID: strings.ToUpper(CBufToGoStr(cInfo.type_guid)),
Number: int(cInfo.number),
StartSector: int64(cInfo.start),
SizeInSectors: int64(cInfo.size),
}
output.Partitions = append(output.Partitions, current)
}
return output, nil
}
func filesystemLookup(device string, allowAmbivalent bool, fieldName string) (string, error) {
var buf [256]byte
cDevice := C.CString(device)
defer C.free(unsafe.Pointer(cDevice))
cFieldName := C.CString(fieldName)
defer C.free(unsafe.Pointer(cFieldName))
if err := cResultToErr(C.blkid_lookup(cDevice, C.bool(allowAmbivalent), cFieldName, (*C.char)(unsafe.Pointer(&buf[0])), C.size_t(len(buf)))); err != nil {
return "", fmt.Errorf("querying filesystem field %q of %q: %w", fieldName, device, err)
}
return string(buf[:bytes.IndexByte(buf[:], 0)]), nil
}
// GetBlockDevices returns a slice of block devices with the given filesystem
func GetBlockDevices(fstype string) ([]string, error) {
var dev C.struct_block_device_list
res := C.blkid_get_block_devices(C.CString(fstype), &dev)
if res != C.RESULT_OK {
return nil, cResultToErr(res)
}
length := int(dev.count)
blkDeviceList := make([]string, length)
for i := 0; i < length; i++ {
blkDeviceList[i] = C.GoString(&dev.path[i][0])
}
return blkDeviceList, nil
}