Skip to content

Commit

Permalink
libaquarium: Functions for reading drives
Browse files Browse the repository at this point in the history
  • Loading branch information
obiwac committed Dec 22, 2022
1 parent be28514 commit 84990f0
Show file tree
Hide file tree
Showing 2 changed files with 217 additions and 4 deletions.
35 changes: 31 additions & 4 deletions src/aquarium.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,20 @@ typedef enum {
AQUARIUM_OS_LINUX,
} aquarium_os_info_t;

typedef enum {
AQUARIUM_TEMPLATE_KIND_BASE,
AQUARIUM_TEMPLATE_KIND_KERNEL,
} aquarium_template_kind_t;

typedef enum {
AQUARIUM_DRIVE_KIND_MD, // memory disk
AQUARIUM_DRIVE_KIND_ADA, // ATA direct access
AQUARIUM_DRIVE_KIND_DA, // SCSI direct access
AQUARIUM_DRIVE_KIND_NVME, // NVMe
AQUARIUM_DRIVE_KIND_CD, // optical disk
AQUARIUM_DRIVE_KIND_OTHER, // could be 'mmcsd', 'mmc', 'at91_mci', or 'sdhci'
} aquarium_drive_kind_t;

// structs

typedef struct {
Expand All @@ -41,10 +55,20 @@ typedef struct {
char* aquarium_path;
} aquarium_db_ent_t;

typedef enum {
AQUARIUM_TEMPLATE_KIND_BASE,
AQUARIUM_TEMPLATE_KIND_KERNEL,
} aquarium_template_kind_t;
typedef struct {
aquarium_drive_kind_t kind;
char* provider;
int rank;

uint64_t sectors;
uint64_t sector_size;

uint64_t size;

char* ident;
char* name;
char* label;
} aquarium_drive_t;

// function prototypes

Expand All @@ -57,3 +81,6 @@ int aquarium_download_template(aquarium_opts_t* opts, char const* path, char con
int aquarium_extract_template(aquarium_opts_t* opts, char const* path, char const* name, aquarium_template_kind_t kind);

int aquarium_create(aquarium_opts_t* opts, char const* path, char const* template, char const* kernel_template);

int aquarium_read_drives(aquarium_drive_t** drives_ref, size_t* drives_len_ref);
void aquarium_free_drives(aquarium_drive_t* drives, size_t drives_len);
186 changes: 186 additions & 0 deletions src/lib/drive.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
// #include <aquarium.h>
#include "../aquarium.h"
#include <err.h>
#include <errno.h>
#include <libgeom.h>
#include <stdlib.h>
#include <string.h>
#include <sys/queue.h>

static aquarium_drive_kind_t drive_kind(char const* provider) {
// not super super robust but whatever

if (!strncmp(provider, "md", 2)) return AQUARIUM_DRIVE_KIND_MD;
if (!strncmp(provider, "ad", 2)) return AQUARIUM_DRIVE_KIND_ADA;
if (!strncmp(provider, "da", 2)) return AQUARIUM_DRIVE_KIND_DA;
if (!strncmp(provider, "nv", 2)) return AQUARIUM_DRIVE_KIND_NVME;
if (!strncmp(provider, "cd", 2)) return AQUARIUM_DRIVE_KIND_CD;

return AQUARIUM_DRIVE_KIND_OTHER;
}

static int process_drive(aquarium_drive_t** drives_ref, size_t* drives_len_ref, struct ggeom* geom, struct gclass* class) {
aquarium_drive_t* drives = *drives_ref;
size_t drives_len = *drives_len_ref;

if (LIST_EMPTY(&geom->lg_provider)) {
return 0;
}

// find provider(s)

struct gprovider* provider;

LIST_FOREACH(provider, &geom->lg_provider, lg_provider) {
drives = realloc(drives, ++drives_len * sizeof *drives);
aquarium_drive_t* const drive = &drives[drives_len - 1];

memset(drive, 0, sizeof *drive); // 'realloc' doesn't zero out anything unfortunately
drive->kind = drive_kind(provider->lg_name);

drive->provider = strdup(provider->lg_name); // TODO vs 'geom->lg_name'?
drive->rank = geom->lg_rank;

drive->sector_size = provider->lg_sectorsize;
drive->size = provider->lg_mediasize;

// find extra information on drive

struct gconfig* config;

LIST_FOREACH(config, &provider->lg_config, lg_config) {
if (!strcmp(config->lg_name, "ident") && config->lg_val) {
drive->ident = strdup(config->lg_val);
}

else if (!strcmp(config->lg_name, "descr") && config->lg_val) {
drive->name = strdup(config->lg_val);
}

else if (!strcmp(config->lg_name, "label") && config->lg_val) {
drive->label = strdup(config->lg_val);
}
}
}

// find potential label(s)

struct ggeom* label_geom;

LIST_FOREACH(label_geom, &class->lg_geom, lg_geom) {
if (strcmp(label_geom->lg_name, geom->lg_name)) {
continue;
}

// 'provider' already defined previously

LIST_FOREACH(provider, &label_geom->lg_provider, lg_provider) {
for (size_t i = 0; i < drives_len; i++) {
aquarium_drive_t* drive = &drives[i];

if (strcmp(drive->provider, provider->lg_name)) {
continue;
}

drive->label = strdup(provider->lg_name);
break;
}
}

break;
}

// set references

*drives_ref = drives;
*drives_len_ref = drives_len;

return 0;
}

static void free_drive(aquarium_drive_t* drive) {
if (drive->provider) {
free(drive->provider);
}

if (drive->ident) {
free(drive->ident);
}

if (drive->name) {
free(drive->name);
}

if (drive->label) {
free(drive->label);
}
}

static int process_class(aquarium_drive_t** drives_ref, size_t* drives_len_ref, struct gmesh* mesh, char const* name) {
struct gclass* class;

// find class we're interested in

LIST_FOREACH(class, &mesh->lg_class, lg_class) {
if (!strcmp(class->lg_name, name)) {
break;
}
}

if (!class) {
warnx("Failed to find '%s' class\n", name);
return -1;
}

// traverse through first layer of disk geometry (rank 1)

struct ggeom* geom;

LIST_FOREACH(geom, &class->lg_geom, lg_geom) {
process_drive(drives_ref, drives_len_ref, geom, class);
}

return 0;
}

int aquarium_read_drives(aquarium_drive_t** drives_ref, size_t* drives_len_ref) {
int rv = -1;

// get drive geometry mesh

struct gmesh mesh;

if (geom_gettree(&mesh) < 0) {
warnx("geom_gettree: %s\n", strerror(errno));
goto err_gettree;
}

if (
process_class(drives_ref, drives_len_ref, &mesh, "DISK" ) < 0 ||
process_class(drives_ref, drives_len_ref, &mesh, "MD" ) < 0 ||
process_class(drives_ref, drives_len_ref, &mesh, "LABEL") < 0
) {
goto class_err;
}

// success

rv = 0;

class_err:

geom_deletetree(&mesh);

err_gettree:

return rv;
}

void aquarium_free_drives(aquarium_drive_t* drives, size_t drives_len) {
for (size_t i = 0; i < drives_len; i++) {
aquarium_drive_t* const drive = &drives[i];
free_drive(drive);
}

free(drives);
}

0 comments on commit 84990f0

Please sign in to comment.