summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authormananth <mananth>2003-10-15 12:22:43 +0000
committermananth <mananth>2003-10-15 12:22:43 +0000
commit86c5b90a76fe07731224d3b47c08721c30b41f29 (patch)
tree1e6c0934c3f3d8a013b710770463536aab8f1d47 /lib
parent7838df3254db021c96f1c53593c1753cb4315057 (diff)
downloadsysfsutils-86c5b90a76fe07731224d3b47c08721c30b41f29.tar.gz
Added sysfs_block.c
Diffstat (limited to 'lib')
-rw-r--r--lib/Makefile.am2
-rw-r--r--lib/Makefile.in10
-rw-r--r--lib/sysfs_block.c309
-rw-r--r--lib/sysfs_class.c2
-rw-r--r--lib/sysfs_dir.c3
5 files changed, 319 insertions, 7 deletions
diff --git a/lib/Makefile.am b/lib/Makefile.am
index d343f01..2b5049a 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -1,5 +1,5 @@
lib_LIBRARIES = libsysfs.a
libsysfs_a_SOURCES = sysfs_utils.c sysfs_dir.c sysfs_bus.c sysfs_class.c \
- sysfs_device.c sysfs_driver.c sysfs.h dlist.c
+ sysfs_device.c sysfs_driver.c sysfs_block.c sysfs.h dlist.c
INCLUDES = -I../include
diff --git a/lib/Makefile.in b/lib/Makefile.in
index a2e859e..2ecbd5f 100644
--- a/lib/Makefile.in
+++ b/lib/Makefile.in
@@ -77,7 +77,7 @@ am__quote = @am__quote@
install_sh = @install_sh@
lib_LIBRARIES = libsysfs.a
libsysfs_a_SOURCES = sysfs_utils.c sysfs_dir.c sysfs_bus.c sysfs_class.c \
- sysfs_device.c sysfs_driver.c sysfs.h dlist.c
+ sysfs_device.c sysfs_driver.c sysfs_block.c sysfs.h dlist.c
INCLUDES = -I../include
subdir = lib
@@ -90,7 +90,8 @@ libsysfs_a_AR = $(AR) cru
libsysfs_a_LIBADD =
am_libsysfs_a_OBJECTS = sysfs_utils.$(OBJEXT) sysfs_dir.$(OBJEXT) \
sysfs_bus.$(OBJEXT) sysfs_class.$(OBJEXT) \
- sysfs_device.$(OBJEXT) sysfs_driver.$(OBJEXT) dlist.$(OBJEXT)
+ sysfs_device.$(OBJEXT) sysfs_driver.$(OBJEXT) \
+ sysfs_block.$(OBJEXT) dlist.$(OBJEXT)
libsysfs_a_OBJECTS = $(am_libsysfs_a_OBJECTS)
DEFS = @DEFS@
@@ -100,8 +101,8 @@ LDFLAGS = @LDFLAGS@
LIBS = @LIBS@
depcomp = $(SHELL) $(top_srcdir)/depcomp
am__depfiles_maybe = depfiles
-@AMDEP_TRUE@DEP_FILES = ./$(DEPDIR)/dlist.Po ./$(DEPDIR)/sysfs_bus.Po \
-@AMDEP_TRUE@ ./$(DEPDIR)/sysfs_class.Po \
+@AMDEP_TRUE@DEP_FILES = ./$(DEPDIR)/dlist.Po ./$(DEPDIR)/sysfs_block.Po \
+@AMDEP_TRUE@ ./$(DEPDIR)/sysfs_bus.Po ./$(DEPDIR)/sysfs_class.Po \
@AMDEP_TRUE@ ./$(DEPDIR)/sysfs_device.Po \
@AMDEP_TRUE@ ./$(DEPDIR)/sysfs_dir.Po \
@AMDEP_TRUE@ ./$(DEPDIR)/sysfs_driver.Po \
@@ -168,6 +169,7 @@ distclean-compile:
-rm -f *.tab.c
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dlist.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sysfs_block.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sysfs_bus.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sysfs_class.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sysfs_device.Po@am__quote@
diff --git a/lib/sysfs_block.c b/lib/sysfs_block.c
new file mode 100644
index 0000000..601f575
--- /dev/null
+++ b/lib/sysfs_block.c
@@ -0,0 +1,309 @@
+/*
+ * sysfs_block.c
+ *
+ * Generic block utility functions for libsysfs
+ *
+ * Copyright (C) IBM Corp. 2003
+ *
+ * This library 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 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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 this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+/*
+ * NOTES:
+ * Write functions to:
+ * Device major/minor given a device
+ * As of now, only the "block" device has writable attribs.
+ * Library has to take care of navigating to the attribute
+ * (may be at various directory levels)
+ */
+
+#include "libsysfs.h"
+#include "sysfs.h"
+
+void sysfs_del_partition(void *partition)
+{
+ sysfs_close_block_partition((struct sysfs_block_partition *)partition);
+}
+
+/**
+ * sysfs_close_block_partition: closes a block partition
+ * @partition: sysfs_block_partition to close
+ */
+void sysfs_close_block_partition(struct sysfs_block_partition *partition)
+{
+ if (partition != NULL) {
+ if (partition->directory != NULL)
+/* reuse sysfs_dir from the earlier structure - just set it to NULL here
+ * free it while closing sysfs_block_device->directory
+ * sysfs_close_directory(partition->directory);*/
+ partition->directory = NULL;
+ }
+}
+
+/**
+ * sysfs_close_block_device: closes a sysfs_block_device
+ * @block: sysfs_block_device structure
+ */
+void sysfs_close_block_device(struct sysfs_block_device *block)
+{
+ if (block != NULL) {
+ if (block->directory != NULL)
+ sysfs_close_directory(block->directory);
+ if (block->device != NULL)
+ sysfs_close_device(block->device);
+ if (block->partitions != NULL)
+ dlist_destroy(block->partitions);
+ }
+}
+
+/**
+ * alloc_block_device: allocate a sysfs_block_device
+ * returns sysfs_block_device or NULL
+ */
+static struct sysfs_block_device *alloc_block_device()
+{
+ return (struct sysfs_block_device *)
+ calloc(1, sizeof(struct sysfs_block_device));
+}
+
+/**
+ * open_block_dir: opens a sysfs block directory
+ * returns sysfs_directory on success or NULL on error
+ */
+static struct sysfs_directory *open_block_dir(const unsigned char *name)
+{
+ unsigned char path[SYSFS_PATH_MAX];
+ struct sysfs_directory *directory = NULL;
+
+ if (name == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ memset(path, 0, SYSFS_PATH_MAX);
+ if ((sysfs_get_mnt_path(path, SYSFS_PATH_MAX)) != 0) {
+ dprintf("Error getting sysfs mount path\n");
+ return NULL;
+ }
+
+ strcat(path, SYSFS_BLOCK_DIR);
+ strcat(path, "/");
+ strcat(path, name);
+ directory = sysfs_open_directory(path);
+ if (directory == NULL) {
+ dprintf("Block device %s not supported on this system", name);
+ return NULL;
+ }
+ if ((sysfs_read_directory(directory)) != 0) {
+ dprintf("Error reading directory %s\n", directory->path);
+ sysfs_close_directory(directory);
+ return NULL;
+ }
+ sysfs_read_all_subdirs(directory);
+
+ return directory;
+}
+
+/**
+ * alloc_block_partition: alloc a sysfs_block_partition structure
+ */
+static struct sysfs_block_partition *alloc_block_partition(void)
+{
+ return(struct sysfs_block_partition *)
+ calloc(1, sizeof(struct sysfs_block_partition));
+}
+
+/**
+ * get_all_block_devices: Retrieves details of block directory
+ * @block: sysfs_block_device for which details are required
+ * returns 0 on success, -1 on failure
+ */
+static int get_all_block_devices(struct sysfs_block_device *block)
+{
+ struct sysfs_directory *cur = NULL;
+ struct sysfs_block_partition *part = NULL;
+
+ if (block == NULL || block->directory == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ dlist_for_each_data(block->directory->subdirs, cur,
+ struct sysfs_directory) {
+ switch(strcmp(cur->name, SYSFS_QUEUE_NAME)) {
+ case 0: /* this is the "queue" directory */
+ if ((sysfs_read_directory(cur)) < 0) {
+ dprintf("Error reading directory %s\n",
+ cur->path);
+ return -1;
+ }
+ break;
+ default: /* these are the partitions */
+ part = alloc_block_partition();
+ if (part == NULL) {
+ perror("calloc");
+ return -1;
+ }
+ part->directory = cur;
+ strcpy(part->name, cur->name);
+ if (block->partitions == NULL)
+ block->partitions =
+ dlist_new_with_delete
+ (sizeof(struct
+ sysfs_block_partition),
+ sysfs_del_partition);
+ dlist_unshift(block->partitions, part);
+ break;
+ }
+ }
+ return 0;
+}
+
+/**
+ * sysfs_open_block_device: opens the specific block device and all its related
+ * details as partitions, etc
+ * returns sysfs_block_device struct on success and NULL on error
+ */
+struct sysfs_block_device *sysfs_open_block_device(unsigned char *name)
+{
+ struct sysfs_block_device *block = NULL;
+ struct sysfs_directory *blockdir = NULL;
+ struct sysfs_link *curlink = NULL;
+
+ if (name == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ block = alloc_block_device();
+ if (block == NULL) {
+ perror("calloc");
+ return NULL;
+ }
+ strcpy(block->name, name);
+ blockdir = open_block_dir(name);
+ if (blockdir == NULL) {
+ sysfs_close_block_device(block);
+ return NULL;
+ }
+ strcpy(block->path, blockdir->path);
+ block->directory = blockdir;
+ if ((get_all_block_devices(block)) != 0) {
+ dprintf("Error retrieving devices for block %s\n", name);
+ sysfs_close_block_device(block);
+ return NULL;
+ }
+ /* check if the "block" device has a link to the physical device */
+ if (block->directory->links != NULL) {
+ dlist_for_each_data(block->directory->links, curlink,
+ struct sysfs_link) {
+ block->device = sysfs_open_device(curlink->target);
+ if (block->device == NULL) {
+ dprintf("Error opening device at %s\n",
+ curlink->target);
+ }
+ }
+ }
+
+ return block;
+}
+
+/**
+ * sysfs_get_blockdev_attributes: returns attributes for the block device
+ * @block: block device for which attribs are to be returned
+ */
+struct dlist *sysfs_get_blockdev_attributes(struct sysfs_block_device *block)
+{
+ if (block == NULL || block->directory == NULL)
+ return NULL;
+
+ return(block->directory->attributes);
+}
+
+/**
+ * sysfs_get_partition_attributes: returns attributes for the block
+ * device partition
+ * @block: block device partition for which attribs are to be returned
+ */
+struct dlist *sysfs_get_partition_attributes
+ (struct sysfs_block_partition *part)
+{
+ if (part == NULL || part->directory == NULL)
+ return NULL;
+
+ return(part->directory->attributes);
+}
+
+/**
+ * sysfs_get_queue_attributes: returns attributes for the block device's
+ * QUEUE parameters. Used to set #of queued
+ * requests as well as the choice of IO
+ * scheduler
+ * @block: block device for which the attributes are needed.
+ */
+struct dlist *sysfs_get_queue_attributes(struct sysfs_block_device *block)
+{
+ struct dlist *list = NULL;
+ struct sysfs_directory *dir = NULL;
+ unsigned int found = 0;
+
+ dlist_for_each_data(block->directory->subdirs, dir,
+ struct sysfs_directory) {
+ if ((strcmp(dir->name, SYSFS_QUEUE_NAME)) != 0)
+ continue;
+ else
+ return (dir->attributes);
+ }
+ return NULL;
+}
+
+/**
+ * sysfs_get_iosched_attributes: returns attributes for the block device's
+ * IOSCHED parameters for the given device
+ * @block: block device for which the attributes are needed
+ * returns a dlist of iosched attributes.
+ */
+struct dlist *sysfs_get_iosched_attributes(struct sysfs_block_device *block)
+{
+ struct dlist *list = NULL;
+ struct sysfs_directory *dir = NULL, *new = NULL;
+ unsigned int found = 0;
+
+ dlist_for_each_data(block->directory->subdirs, dir,
+ struct sysfs_directory) {
+ if ((strcmp(dir->name, SYSFS_QUEUE_NAME)) != 0)
+ continue;
+ else {
+ found = 1;
+ break;
+ }
+ }
+ if (found) {
+ /*
+ * this is the queue directory - read this and the
+ * iosched directory too
+ */
+ dlist_for_each_data(dir->subdirs, new,
+ struct sysfs_directory) {
+ if ((strcmp(new->name, SYSFS_IOSCHED_NAME)) == 0)
+ if ((sysfs_read_directory(new)) == 0)
+ return new->attributes;
+ }
+ }
+ dprintf("IOSCHED attributes not found\n");
+ return NULL;
+}
+
diff --git a/lib/sysfs_class.c b/lib/sysfs_class.c
index 6c969b5..9172a1e 100644
--- a/lib/sysfs_class.c
+++ b/lib/sysfs_class.c
@@ -264,7 +264,7 @@ struct sysfs_class *sysfs_open_class(const unsigned char *name)
cls = alloc_class();
if (cls == NULL) {
- perror("malloc");
+ perror("calloc");
return NULL;
}
strcpy(cls->name, name);
diff --git a/lib/sysfs_dir.c b/lib/sysfs_dir.c
index 1d730e7..46ebd52 100644
--- a/lib/sysfs_dir.c
+++ b/lib/sysfs_dir.c
@@ -525,10 +525,11 @@ int sysfs_read_directory(struct sysfs_directory *sysdir)
}
}
- if (sysdir->attributes == NULL)
+ if (sysdir->attributes == NULL) {
sysdir->attributes = dlist_new_with_delete
(sizeof(struct sysfs_attribute),
sysfs_del_attribute);
+ }
dlist_unshift(sysdir->attributes, attr);
} else if (S_ISDIR(astats.st_mode)) {
subdir = sysfs_open_directory(file_path);