Most of the modern linux systems will manage the filesystem
parititions using the device block UUID, a 128bit number represented
as 32 hexdecimal digits. One can use command blkid to print out all
the block device attributes, including the UUID. However, there are
moments we would like to find that information programatically.
This is an exercise trying to call blkid low level functions through CGO, to figure out the block device UUID.
Photo by Mr Cup / Fabien Barral on UnsplashBefore we proceed to the golang implemnetation, let’s see how it is done in C as follows:
blkid_probe pr;
const char *uuid;
pr = blkid_new_probe_from_filename(devname);
if (!pr) {
err(2, "Failed to open %s", devname);
}
blkid_do_probe(pr);
blkid_probe_lookup_value(pr, "UUID", &uuid, NULL);
printf("UUID=%s\n", uuid);
blkid_free_probe(pr);
First, we create a new blkid probe based on the device name. Then
we run the probe. Afterwards, we look up the UUID attributes from
the probe result. Finally, we release resources allocated for this probe.
This is the golang implementation in CGO:
package blkid
/*
#include <unistd.h>
#include <sys/types.h>
#include <blkid/blkid.h>
#cgo CFLAGS: -O2
#cgo LDFLAGS: -lblkid -luuid
*/
import "C"
import "fmt"
func GetUUIDForBlockDevice(devname string) (uuid string, err error) {
pr := C.blkid_new_probe_from_filename(C.CString(devname))
if pr == nil {
err = fmt.Errorf("error to open device '%s'", devname)
return
}
C.blkid_do_probe(pr)
var value *C.char
var ssize *C.size_t = nil
if C.blkid_probe_lookup_value(pr, C.CString("UUID"), &value, ssize) == 0 {
uuid = C.GoString(value)
}
C.blkid_free_probe(pr);
return
}