1
0
Fork 0
mirror of https://gitlab.com/sortix/sortix.git synced 2023-02-13 20:55:38 -05:00
sortix--sortix/libmount/devices.c
Jonas 'Sortie' Termansen e6a1cd6dee Add libmount.
2016-02-03 01:01:20 +01:00

170 lines
4.5 KiB
C

/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2015.
This file is part of Sortix libmount.
Sortix libmount is free software: you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by the
Free Software Foundation, either version 3 of the License, or (at your
option) any later version.
Sortix libmount 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 Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with Sortix libmount. If not, see <http://www.gnu.org/licenses/>.
devices.c
Locate block devices.
*******************************************************************************/
#include <ctype.h>
#include <errno.h>
#include <dirent.h>
#include <fcntl.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <mount/devices.h>
#include <mount/harddisk.h>
static bool is_partition_name(const char* path)
{
const char* name = path;
for ( size_t i = 0; path[i]; i++ )
if ( path[i] == '/' )
name = path + i + 1;
if ( !isalpha((unsigned char) *name) )
return false;
name++;
while ( isalpha((unsigned char) *name) )
name++;
if ( !isdigit((unsigned char) *name) )
return false;
name++;
while ( isdigit((unsigned char) *name) )
name++;
if ( *name != 'p' )
return false;
name++;
if ( !isdigit((unsigned char) *name) )
return false;
name++;
while ( isdigit((unsigned char) *name) )
name++;
return *name == '\0';
}
bool devices_iterate_path(bool (*callback)(void*, const char*), void* ctx)
{
const char* dev_path = "/dev";
DIR* dir = opendir(dev_path);
if ( !dir )
return errno == ENOENT;
// TODO: This readdir loop can be derailed if the callback creates devices.
struct dirent* entry;
while ( (errno = 0, entry = readdir(dir)) )
{
if ( entry->d_name[0] == '.' )
continue;
if ( entry->d_type != DT_UNKNOWN && entry->d_type != DT_BLK )
continue;
// TODO: Remove this once partitions identify themselves as such and
// libmount doesn't allow using them as a real full block device.
if ( is_partition_name(entry->d_name) )
continue;
char* path;
if ( asprintf(&path, "%s/%s", dev_path, entry->d_name) < 0 )
return closedir(dir), false;
bool success = callback(ctx, path);
free(path);
if ( !success )
return closedir(dir), false;
}
bool success = errno == 0;
closedir(dir);
return success;
}
struct devices_iterate_open
{
void* ctx;
bool (*callback)(void*, struct harddisk*);
};
static bool devices_iterate_open_callback(void* ctx_ptr, const char* path)
{
struct devices_iterate_open* ctx = (struct devices_iterate_open*) ctx_ptr;
struct harddisk* hd = harddisk_openat(AT_FDCWD, path, O_RDWR);
if ( !hd )
{
int true_errno = errno;
struct stat st;
if ( lstat(path, 0) == 0 && !S_ISBLK(st.st_mode) )
return true;
errno = true_errno;
return false;
}
if ( !harddisk_inspect_blockdevice(hd) )
{
bool success = errno == ENOTBLK;
harddisk_close(hd);
return success;
}
return ctx->callback(ctx->ctx, hd);
}
bool devices_iterate_open(bool (*callback)(void*, struct harddisk*), void* ctx)
{
struct devices_iterate_open myctx;
myctx.ctx = ctx;
myctx.callback = callback;
return devices_iterate_path(devices_iterate_open_callback, &myctx);
}
struct devices_open_all
{
struct harddisk** hds;
size_t hds_count;
size_t hds_allocated;
};
static bool devices_open_all_callback(void* ctx_ptr, struct harddisk* hd)
{
struct devices_open_all* ctx = (struct devices_open_all*) ctx_ptr;
if ( ctx->hds_count == ctx->hds_allocated )
{
size_t new_allocated = ctx->hds_allocated ? 2 * ctx->hds_allocated : 16;
struct harddisk** new_hds = (struct harddisk**)
reallocarray(ctx->hds, new_allocated, sizeof(struct harddisk*));
if ( !new_hds )
return harddisk_close(hd), false;
ctx->hds = new_hds;
ctx->hds_allocated = new_allocated;
}
ctx->hds[ctx->hds_count++] = hd;
return true;
}
bool devices_open_all(struct harddisk*** hds_ptr, size_t* hds_count_ptr)
{
struct devices_open_all myctx;
myctx.hds = NULL;
myctx.hds_count = 0;
myctx.hds_allocated = 0;
if ( !devices_iterate_open(devices_open_all_callback, &myctx) )
{
for ( size_t i = 0; i < myctx.hds_count; i++ )
harddisk_close(myctx.hds[i]);
free(myctx.hds);
return false;
}
*hds_ptr = myctx.hds;
*hds_count_ptr = myctx.hds_count;
return true;
}