15
14
#include <string.h>
16
#include <sysfs/libsysfs.h>
17
15
#include <sys/stat.h>
16
#include <sys/types.h>
18
#include <sys/sysmacros.h>
21
23
#define DEV_BUFFER_LENGTH 20
25
* helper function that compares the string dev against the
26
* attribute "dev" in directory dir
27
* returns 1 if match is found, else 0
30
dir_matches_device(const char *dir, const char *dev) {
31
int dev_attr_len, dev_parm_len, ret = 0;
32
struct sysfs_attribute *devattr;
33
char path[SYSFS_PATH_MAX];
37
devattr = sysfs_open_attribute(path);
39
sysfs_read_attribute(devattr);
40
/* exclude white space from comparison */
41
dev_attr_len = strspn(devattr->value, "1234567890:");
42
dev_parm_len = strlen(dev);
43
if (dev_attr_len != dev_parm_len )
45
else if (!strncmp(dev,devattr->value, dev_parm_len))
47
sysfs_close_attribute(devattr);
24
#define PATH_BUFFER_LENGTH 256
26
#define BLOCKPATH "/sys/block/"
27
#define DEVICE_LINK "device"
28
#define DEV_ATTRIBUTE "dev"
32
* Helper function that expects a file name and returns 1 if this
33
* is a directory or 0 otherwise.
35
static int isdir(char *name) {
39
if (lstat(name, &statbuf) < 0)
41
return S_ISDIR(statbuf.st_mode);
45
* Helper function that expects a directory name in sysfs of the form
46
* /sys/block/<devname>/ or /sys/block/<devname>/<partname>/.
47
* It will try to read the file "dev" in this directory and compare
48
* it's contents with the given dev string of the form <major>:<minor>.
49
* Trailing white space (newline) is ignored.
50
* The buffer name is expected to be long enough to hold the additional "dev".
51
* Returns 1 if the directory matches dev, 0 otherwise.
53
static int check_directory(char *name, char *dev) {
55
char buffer[DEV_BUFFER_LENGTH];
59
int dev_attr_len, dev_parm_len, namelen;
61
namelen = strlen(name);
62
if ((PATH_BUFFER_LENGTH - namelen) < sizeof(DEV_ATTRIBUTE))
65
strcpy(end, DEV_ATTRIBUTE);
66
fd = open(name, O_RDONLY);
70
count = read(fd, buffer, DEV_BUFFER_LENGTH);
74
dev_attr_len = strspn(buffer, "1234567890:");
75
dev_parm_len = strlen(dev);
76
if (dev_attr_len != dev_parm_len )
78
return (strncmp(dev, buffer, dev_parm_len) == 0);
82
* Helper function that expects a directory name in sysfs of the form
83
* /sys/block/<devname>/. It will try to read a link "device"
84
* in this directory and extract the busid, which is the last part
85
* of that link. The buffer name is expected to be long enough
86
* to hold the additional "device".
87
* name: block device path in sysfs.
88
* busid: buffer in which the busid string will be returned
89
* returns 0 for successfull operation and -1 in case of an error.
91
static int extract_busid(char *name, char *busid) {
94
char linkbuffer[PATH_BUFFER_LENGTH];
97
namelen = strlen(name);
98
if ((PATH_BUFFER_LENGTH - namelen) < sizeof(DEVICE_LINK))
100
end = name + namelen;
101
strcpy(end, DEVICE_LINK);
102
count = readlink(name, linkbuffer, PATH_BUFFER_LENGTH - 1);
105
linkbuffer[count] = 0;
106
start = strrchr(linkbuffer, '/');
110
strcpy(busid, start);
115
* Helper function that makes some basic checks on a directory entry.
116
* The function checks if there is still enough space left in the buffer
117
* for the new string, excludes '.' and '..', and verifies that the entry
118
* is actually a directory.
119
* buffer: the beginning of the name buffer
120
* oldend: the current end of the string in the name buffer
121
* dir: the dirent in question
122
* returns: a pointer to the new end of the string in buffer or NULL if
123
* one of the checks failed
126
static char *append_if_directory(char *buffer, char *oldend, struct dirent *dir) {
129
int oldlength, dirlength;
131
if (strcmp(dir->d_name, ".") == 0 ||
132
strcmp(dir->d_name, "..") == 0)
134
oldlength = strlen(buffer);
135
dirlength = strlen(dir->d_name);
136
if (PATH_BUFFER_LENGTH < oldlength + dirlength + 2)
138
strcpy(oldend, dir->d_name);
139
if (!isdir(buffer)) {
143
newend = oldend + dirlength;
54
151
* helper function that searches for a specific block device and returns
56
* sysfs: structure that represents the sysfs root directory
57
153
* dev: <major>:<minor> of the device
58
154
* busid: buffer in which the busid string will be returned
59
* returns 0 for successfull operation and -1 in case of an error.
155
* returns 0 for successfull operation and -1 in case of an error.
63
find_busid_in_sysfs(const char *sysfs, char *dev, char *busid) {
65
char *dir, *subdir, *blkdevdir;
66
struct dlist *blockdirs, *blocksubdirs;
67
char path[SYSFS_PATH_MAX], path1[SYSFS_PATH_MAX];
71
strcat(path, SYSFS_BLOCK_NAME);
73
blockdirs = sysfs_open_directory_list(path);
76
/* go through all directories and subdirectories in /sys/block
77
* e.g. /sys/block/dasda as well as /sys/block/dasda1 etc.
78
* match the attribute 'dev' against the string we build in
157
static int find_busid_in_sysfs(char *dev, char *busid) {
159
DIR *blockdir, *diskdir;
160
struct dirent *blockde, *diskde;
162
char namebuffer[PATH_BUFFER_LENGTH];
163
char *blockend, *diskend = NULL, *partend;
165
/* everything, including the other helper functions, works on the
166
* same buffer area 'namebuffer'. The pointers blockend, diskend
167
* and partend point to the end of the various names.
169
* "/sys/block/dasda/dasda1/"
82
dlist_for_each_data(blockdirs, dir, char) {
83
blocksubdirs = sysfs_open_directory_list(dir);
85
dlist_for_each_data(blocksubdirs, subdir, char) {
90
strcat(path1, subdir);
91
if (dir_matches_device(path1, dev)) {
102
if (dir_matches_device(path1, dev)) {
175
strcpy(namebuffer,BLOCKPATH);
176
blockdir = opendir(namebuffer);
179
blockend = namebuffer + strlen(namebuffer);
180
/* check each entry in /sys/block */
181
while ((blockde = readdir(blockdir))) {
182
diskend = append_if_directory(namebuffer, blockend, blockde);
185
found = check_directory(namebuffer, dev);
188
diskdir = opendir(namebuffer);
191
/* check each entry in /sys/block/<disk name> */
192
while ((diskde = readdir(diskdir))) {
193
partend = append_if_directory(
194
namebuffer, diskend, diskde);
197
found = check_directory(namebuffer, dev);
110
* now that we have the right block device, we can follow the
111
* link to the device and extract the busid
113
strcpy(path, blkdevdir);
114
strcat(path, "/device");
115
sysfs_get_link(path, path1, SYSFS_PATH_MAX);
116
if (sysfs_get_name_from_path(path1, busid, SYSFS_BUS_ID_SIZE))
207
*diskend = 0; /* remove partition directory from name */
208
return extract_busid(namebuffer, busid);