Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions build-aux/snap/snapcraft.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ parts:
runtime:
plugin: nil
stage-packages:
- libblkid1
- libbrotli1
- libc6
- libcap2
Expand Down Expand Up @@ -231,6 +232,7 @@ parts:
- autoconf-archive
- automake
- xfslibs-dev
- libblkid-dev
- libudev-dev
- libcap-dev
- libseccomp-dev
Expand Down
186 changes: 186 additions & 0 deletions cmd/snap-bootstrap/blkid/blkid.go
Comment thread
pedronis marked this conversation as resolved.
Outdated
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
// -*- Mode: Go; indent-tabs-mode: t -*-

/*
* Copyright (C) Canonical Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/

package blkid

//#cgo CFLAGS: -D_FILE_OFFSET_BITS=64
//#cgo pkg-config: blkid
//#cgo LDFLAGS:
//
//#include <stdlib.h>
//#include <blkid.h>
import "C"

import (
"fmt"
"unsafe"
)

const (
BLKID_PARTS_ENTRY_DETAILS int = C.BLKID_PARTS_ENTRY_DETAILS
)

// AbstractBlkidProbe is wrapper for blkid_probe
// See "Low-level" section of libblkid documentation
type AbstractBlkidProbe interface {
// LookupValue is a wrapper for blkid_probe_lookup_value
LookupValue(entryName string) (string, error)
// Close is a wrapper for blkid_free_probe
Close()
// EnablePartitions is a wrapper for blkid_probe_enable_partitions
EnablePartitions(value bool)
// EnableSuperblocks is a wrapper for blkid_probe_enable_superblocks
EnableSuperblocks(value bool)
// SetPartitionsFlags is a wrapper for blkid_probe_set_partitions_flags
SetPartitionsFlags(flags int)
// DoSafeprobe is a wrapper for blkid_do_safeprobe
DoSafeprobe() error
// GetPartitions is a wrapper for blkid_probe_get_partitions
GetPartitions() (AbstractBlkidPartlist, error)
}

// AbstractBlkidPartlist is a wrapper for blkid_partlist
type AbstractBlkidPartlist interface {
// GetPartitions is a wrapper for blkid_partlist_get_partition
// and blkid_partlist_numof_partitions.
GetPartitions() []AbstractBlkidPartition
}

// AbstractBlkidPartition is a wrapper for blkid_partition
type AbstractBlkidPartition interface {
// GetName is a wrapper for blkid_partition_get_name
GetName() string
// GetUUID is a wrapper for blkid_partition_get_uuid
GetUUID() string
}

type blkidProbe struct {
probeHandle C.blkid_probe
}

func newProbeFromFilenameImpl(node string) (AbstractBlkidProbe, error) {
cnode := C.CString(node)
defer C.free(unsafe.Pointer(cnode))
probe, err := C.blkid_new_probe_from_filename(cnode)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From my understanding, err will contain some representation of errno, from C. Would it be safer to check both err and probe?

Do we know for sure err != nil when probe == nil?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see. Although that is a bit different, I think. I wanted to make sure that errno is always set by these functions on failure, but that isn't mentioned in the docs. I took a look at the code, and I think that errno would be set in all failure paths, but it is hard to tell.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have changed it to use err.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we use err, then we're saying that errno will always be set by the C function on failure. Is that definitely true?

if probe == nil {
if err == nil {
return nil, fmt.Errorf("blkid_new_probe_from_filename failed but no error was returned")
}
return nil, err
}
return &blkidProbe{probe}, nil
}

var NewProbeFromFilename = newProbeFromFilenameImpl

func (p *blkidProbe) checkProbe() {
if p.probeHandle == nil {
panic("used blkid probe after Close")
}
}

func (p *blkidProbe) LookupValue(entryName string) (string, error) {
p.checkProbe()
var value *C.char
var value_len C.size_t
cname := C.CString(entryName)
defer C.free(unsafe.Pointer(cname))
res := C.blkid_probe_lookup_value(p.probeHandle, cname, &value, &value_len)
if res < 0 {
return "", fmt.Errorf("probe value was not found: %s", entryName)
}
if value_len > 0 {
return C.GoStringN(value, C.int(value_len-1)), nil
} else {
return "", fmt.Errorf("probe value has unexpected size")
}
}

func (p *blkidProbe) Close() {
p.checkProbe()
C.blkid_free_probe(p.probeHandle)
Comment thread
pedronis marked this conversation as resolved.
Outdated
p.probeHandle = C.blkid_probe(nil)
}

func (p *blkidProbe) EnablePartitions(value bool) {
Comment thread
pedronis marked this conversation as resolved.
Outdated
p.checkProbe()
v := 0
if value {
v = 1
}
C.blkid_probe_enable_partitions(p.probeHandle, C.int(v))
}

func (p *blkidProbe) EnableSuperblocks(value bool) {
p.checkProbe()
v := 0
if value {
v = 1
}
C.blkid_probe_enable_superblocks(p.probeHandle, C.int(v))
}

func (p *blkidProbe) SetPartitionsFlags(flags int) {
p.checkProbe()
C.blkid_probe_set_partitions_flags(p.probeHandle, C.int(flags))
}

func (p *blkidProbe) DoSafeprobe() error {
p.checkProbe()
res, err := C.blkid_do_safeprobe(p.probeHandle)
if res < 0 {
return err
}
return nil
}

type blkidPartlist struct {
partlistHandle C.blkid_partlist
}

func (p *blkidProbe) GetPartitions() (AbstractBlkidPartlist, error) {
p.checkProbe()
partitions, err := C.blkid_probe_get_partitions(p.probeHandle)
if partitions == nil {
return nil, err
}
return &blkidPartlist{partitions}, nil
}

type blkidPartition struct {
partitionHandle C.blkid_partition
Comment thread
pedronis marked this conversation as resolved.
Outdated
}

func (p *blkidPartlist) GetPartitions() []AbstractBlkidPartition {
npartitions := C.blkid_partlist_numof_partitions(p.partlistHandle)
ret := make([]AbstractBlkidPartition, npartitions)
for i := 0; i < int(npartitions); i++ {
partition := C.blkid_partlist_get_partition(p.partlistHandle, C.int(i))
ret[i] = &blkidPartition{partition}
}
return ret
}

func (p *blkidPartition) GetName() string {
return C.GoString(C.blkid_partition_get_name(p.partitionHandle))
}

func (p *blkidPartition) GetUUID() string {
return C.GoString(C.blkid_partition_get_uuid(p.partitionHandle))
}
90 changes: 90 additions & 0 deletions cmd/snap-bootstrap/blkid/blkid_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
// -*- Mode: Go; indent-tabs-mode: t -*-

/*
* Copyright (C) Canonical Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/

package blkid_test

import (
"os/exec"
"path/filepath"
"testing"

. "gopkg.in/check.v1"

"github.com/snapcore/snapd/cmd/snap-bootstrap/blkid"

"github.com/snapcore/snapd/testutil"
)

func Test(t *testing.T) { TestingT(t) }

type blkidSuite struct {
testutil.BaseTest

image string
}

var _ = Suite(&blkidSuite{})

func (s *blkidSuite) SetUpTest(c *C) {
systemdRepart, err := exec.LookPath("systemd-repart")
if err != nil {
c.Skip("systemd-repart is not available")
}

s.BaseTest.SetUpTest(c)

tmp := c.MkDir()
image := filepath.Join(tmp, "image")

cmd := exec.Command(systemdRepart, "--offline=yes", "--size=64M", "--empty=create", "--definitions=test-data/repart.d", image)
err = cmd.Run()
if err != nil {
c.Skip("systemd-repart is not working")
}

s.image = image
}

func (s *blkidSuite) TestScanPartitionTable(c *C) {
probe, err := blkid.NewProbeFromFilename(s.image)
c.Assert(err, IsNil)
defer probe.Close()

probe.EnablePartitions(true)

err = probe.DoSafeprobe()
c.Assert(err, IsNil)

pttype, err := probe.LookupValue("PTTYPE")
c.Assert(err, IsNil)
c.Check(pttype, Equals, "gpt")

partlist, err := probe.GetPartitions()
c.Assert(err, IsNil)

partitions := 0
for _, p := range partlist.GetPartitions() {
partitions++
label := p.GetName()
c.Check(label, Equals, "thelabel")
uuid := p.GetUUID()
c.Check(uuid, Equals, "93fd7d8f-a662-4451-a03f-c065f2c2e1ab")
}
c.Check(partitions, Equals, 1)
}
Loading