1
1
mirror of https://github.com/systemd/systemd-stable.git synced 2024-11-01 09:21:11 +03:00
systemd-stable/udev/udev_db.c

332 lines
8.9 KiB
C
Raw Normal View History

2003-10-17 12:40:02 +04:00
/*
* Copyright (C) 2003 Greg Kroah-Hartman <greg@kroah.com>
2005-02-21 15:48:10 +03:00
* Copyright (C) 2004-2005 Kay Sievers <kay.sievers@vrfy.org>
2003-10-17 12:40:02 +04:00
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation version 2 of the License.
*
* This program 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
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
2006-08-28 02:29:11 +04:00
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
2003-10-17 12:40:02 +04:00
*
*/
[PATCH] udevdb prototype Here's an "idea" of what I had in mind for udevdb. Let me preface the code with a few remarks: 1) I was expecting to write this udevdb for udev to keep track of devices. I was planning an external package that depends upon udev to provide an external API to the udevdb database. The calls for the interface would be read only access. Not sure how you want to do packaging, if having a separate package is ok or having it included in udev. 2) I created it as it is because udev isn't a daemon. So, the open database call doesn't take any parameters. My plan was to create a udevdb_init function that took arguments for initializing the db to start, where you could specify in memory only or a file location. This can all be filled in. 3) I hacked the Makefile to get it to work. Not sure how you'd want that in the future. 4) This assumes TDB has been installed elsewhere, you would need to edit your Makefile and point it to the header and library locations. How do you want to do TDB in udev? Do you want to just reference it and make udev dependent on that package being installed. Or should we do what samba does and include a limited tdb version in udev? 5) Again, I hacked udev into your existing code. In the future, I'd probably make a function around the filling out the udevice before calling the store command. Didn't know if you wanted to change your add device function to use struct udevice rather than having everything separate. 6) Not sure what we should include in the udevice structure that's stored by udev. I made a stab at a first shot - we can add and remove of course, this was a first pass. I've come to realize - with you including libsysfs in udev, the "external" interface that references udevdb could make use of getting information from through libsysfs from sysfs and doesn't need to be in udevdb. 7) I could write a namedevdb for namedev's device management if you wanted.
2003-08-06 10:57:23 +04:00
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stddef.h>
2005-03-06 14:16:32 +03:00
#include <unistd.h>
[PATCH] udevdb prototype Here's an "idea" of what I had in mind for udevdb. Let me preface the code with a few remarks: 1) I was expecting to write this udevdb for udev to keep track of devices. I was planning an external package that depends upon udev to provide an external API to the udevdb database. The calls for the interface would be read only access. Not sure how you want to do packaging, if having a separate package is ok or having it included in udev. 2) I created it as it is because udev isn't a daemon. So, the open database call doesn't take any parameters. My plan was to create a udevdb_init function that took arguments for initializing the db to start, where you could specify in memory only or a file location. This can all be filled in. 3) I hacked the Makefile to get it to work. Not sure how you'd want that in the future. 4) This assumes TDB has been installed elsewhere, you would need to edit your Makefile and point it to the header and library locations. How do you want to do TDB in udev? Do you want to just reference it and make udev dependent on that package being installed. Or should we do what samba does and include a limited tdb version in udev? 5) Again, I hacked udev into your existing code. In the future, I'd probably make a function around the filling out the udevice before calling the store command. Didn't know if you wanted to change your add device function to use struct udevice rather than having everything separate. 6) Not sure what we should include in the udevice structure that's stored by udev. I made a stab at a first shot - we can add and remove of course, this was a first pass. I've come to realize - with you including libsysfs in udev, the "external" interface that references udevdb could make use of getting information from through libsysfs from sysfs and doesn't need to be in udevdb. 7) I could write a namedevdb for namedev's device management if you wanted.
2003-08-06 10:57:23 +04:00
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <dirent.h>
2006-08-24 02:13:07 +04:00
#include <sys/stat.h>
#include <sys/types.h>
[PATCH] udevdb prototype Here's an "idea" of what I had in mind for udevdb. Let me preface the code with a few remarks: 1) I was expecting to write this udevdb for udev to keep track of devices. I was planning an external package that depends upon udev to provide an external API to the udevdb database. The calls for the interface would be read only access. Not sure how you want to do packaging, if having a separate package is ok or having it included in udev. 2) I created it as it is because udev isn't a daemon. So, the open database call doesn't take any parameters. My plan was to create a udevdb_init function that took arguments for initializing the db to start, where you could specify in memory only or a file location. This can all be filled in. 3) I hacked the Makefile to get it to work. Not sure how you'd want that in the future. 4) This assumes TDB has been installed elsewhere, you would need to edit your Makefile and point it to the header and library locations. How do you want to do TDB in udev? Do you want to just reference it and make udev dependent on that package being installed. Or should we do what samba does and include a limited tdb version in udev? 5) Again, I hacked udev into your existing code. In the future, I'd probably make a function around the filling out the udevice before calling the store command. Didn't know if you wanted to change your add device function to use struct udevice rather than having everything separate. 6) Not sure what we should include in the udevice structure that's stored by udev. I made a stab at a first shot - we can add and remove of course, this was a first pass. I've come to realize - with you including libsysfs in udev, the "external" interface that references udevdb could make use of getting information from through libsysfs from sysfs and doesn't need to be in udevdb. 7) I could write a namedevdb for namedev's device management if you wanted.
2003-08-06 10:57:23 +04:00
#include "udev.h"
2008-04-18 01:31:09 +04:00
#include "udev_selinux.h"
[PATCH] udevdb prototype Here's an "idea" of what I had in mind for udevdb. Let me preface the code with a few remarks: 1) I was expecting to write this udevdb for udev to keep track of devices. I was planning an external package that depends upon udev to provide an external API to the udevdb database. The calls for the interface would be read only access. Not sure how you want to do packaging, if having a separate package is ok or having it included in udev. 2) I created it as it is because udev isn't a daemon. So, the open database call doesn't take any parameters. My plan was to create a udevdb_init function that took arguments for initializing the db to start, where you could specify in memory only or a file location. This can all be filled in. 3) I hacked the Makefile to get it to work. Not sure how you'd want that in the future. 4) This assumes TDB has been installed elsewhere, you would need to edit your Makefile and point it to the header and library locations. How do you want to do TDB in udev? Do you want to just reference it and make udev dependent on that package being installed. Or should we do what samba does and include a limited tdb version in udev? 5) Again, I hacked udev into your existing code. In the future, I'd probably make a function around the filling out the udevice before calling the store command. Didn't know if you wanted to change your add device function to use struct udevice rather than having everything separate. 6) Not sure what we should include in the udevice structure that's stored by udev. I made a stab at a first shot - we can add and remove of course, this was a first pass. I've come to realize - with you including libsysfs in udev, the "external" interface that references udevdb could make use of getting information from through libsysfs from sysfs and doesn't need to be in udevdb. 7) I could write a namedevdb for namedev's device management if you wanted.
2003-08-06 10:57:23 +04:00
static size_t devpath_to_db_path(struct udev *udev, const char *devpath, char *filename, size_t len)
{
size_t start;
/* translate to location of db file */
strlcpy(filename, udev_get_dev_path(udev), len);
2008-07-30 03:45:23 +04:00
start = strlcat(filename, "/.udev/db/", len);
strlcat(filename, devpath, len);
return path_encode(&filename[start], len - start);
}
/* reverse mapping from the device file name to the devpath */
static int name_index(struct udev *udev, const char *devpath, const char *name, int add)
{
char device[PATH_SIZE];
char filename[PATH_SIZE * 2];
size_t start;
int fd;
/* directory with device name */
strlcpy(filename, udev_get_dev_path(udev), sizeof(filename));
2008-07-30 03:45:23 +04:00
start = strlcat(filename, "/.udev/names/", sizeof(filename));
strlcat(filename, name, sizeof(filename));
path_encode(&filename[start], sizeof(filename) - start);
/* entry with the devpath */
strlcpy(device, devpath, sizeof(device));
path_encode(device, sizeof(device));
strlcat(filename, "/", sizeof(filename));
strlcat(filename, device, sizeof(filename));
if (add) {
info(udev, "creating index: '%s'\n", filename);
create_path(udev, filename);
fd = open(filename, O_WRONLY|O_TRUNC|O_CREAT, 0644);
if (fd > 0)
close(fd);
} else {
info(udev, "removing index: '%s'\n", filename);
unlink(filename);
delete_path(udev, filename);
}
return 0;
}
int udev_db_get_devices_by_name(struct udev *udev, const char *name, struct list_head *name_list)
{
char dirname[PATH_MAX];
size_t start;
DIR *dir;
int rc = 0;
strlcpy(dirname, udev_get_dev_path(udev), sizeof(dirname));
2008-07-30 03:45:23 +04:00
start = strlcat(dirname, "/.udev/names/", sizeof(dirname));
strlcat(dirname, name, sizeof(dirname));
path_encode(&dirname[start], sizeof(dirname) - start);
dir = opendir(dirname);
if (dir == NULL) {
info(udev, "no index directory '%s': %s\n", dirname, strerror(errno));
rc = -1;
goto out;
}
info(udev, "found index directory '%s'\n", dirname);
while (1) {
struct dirent *ent;
char device[PATH_SIZE];
ent = readdir(dir);
if (ent == NULL || ent->d_name[0] == '\0')
break;
if (ent->d_name[0] == '.')
continue;
strlcpy(device, ent->d_name, sizeof(device));
path_decode(device);
name_list_add(udev, name_list, device, 0);
rc++;
}
closedir(dir);
out:
return rc;
}
int udev_db_rename(struct udev *udev, const char *devpath_old, const char *devpath)
{
char filename[PATH_SIZE];
char filename_old[PATH_SIZE];
devpath_to_db_path(udev, devpath_old, filename_old, sizeof(filename_old));
devpath_to_db_path(udev, devpath, filename, sizeof(filename));
return rename(filename_old, filename);
}
int udev_db_add_device(struct udevice *udevice)
{
char filename[PATH_SIZE];
if (udevice->test_run)
return 0;
devpath_to_db_path(udevice->udev, udevice->dev->devpath, filename, sizeof(filename));
create_path(udevice->udev, filename);
unlink(filename);
/*
* don't waste tmpfs memory pages, if we don't have any data to store
* create fake db-file; store the node-name in a symlink target
*/
if (list_empty(&udevice->symlink_list) && list_empty(&udevice->env_list) &&
!udevice->partitions && !udevice->ignore_remove) {
int ret;
dbg(udevice->udev, "nothing interesting to store, create symlink\n");
selinux_setfscreatecon(udevice->udev, filename, NULL, S_IFLNK);
ret = symlink(udevice->name, filename);
selinux_resetfscreatecon(udevice->udev);
if (ret != 0) {
err(udevice->udev, "unable to create db link '%s': %s\n", filename, strerror(errno));
return -1;
}
} else {
FILE *f;
struct name_entry *name_loop;
f = fopen(filename, "w");
if (f == NULL) {
err(udevice->udev, "unable to create db file '%s': %s\n", filename, strerror(errno));
return -1;
}
dbg(udevice->udev, "storing data for device '%s' in '%s'\n", udevice->dev->devpath, filename);
fprintf(f, "N:%s\n", udevice->name);
list_for_each_entry(name_loop, &udevice->symlink_list, node) {
fprintf(f, "S:%s\n", name_loop->name);
/* add symlink-name to index */
name_index(udevice->udev, udevice->dev->devpath, name_loop->name, 1);
}
fprintf(f, "M:%u:%u\n", major(udevice->devt), minor(udevice->devt));
if (udevice->link_priority != 0)
fprintf(f, "L:%u\n", udevice->link_priority);
if (udevice->event_timeout >= 0)
fprintf(f, "T:%u\n", udevice->event_timeout);
if (udevice->partitions != 0)
fprintf(f, "A:%u\n", udevice->partitions);
if (udevice->ignore_remove)
fprintf(f, "R:%u\n", udevice->ignore_remove);
list_for_each_entry(name_loop, &udevice->env_list, node)
fprintf(f, "E:%s\n", name_loop->name);
fclose(f);
}
/* add name to index */
name_index(udevice->udev, udevice->dev->devpath, udevice->name, 1);
return 0;
}
int udev_db_get_device(struct udevice *udevice, const char *devpath)
[PATCH] udevdb prototype Here's an "idea" of what I had in mind for udevdb. Let me preface the code with a few remarks: 1) I was expecting to write this udevdb for udev to keep track of devices. I was planning an external package that depends upon udev to provide an external API to the udevdb database. The calls for the interface would be read only access. Not sure how you want to do packaging, if having a separate package is ok or having it included in udev. 2) I created it as it is because udev isn't a daemon. So, the open database call doesn't take any parameters. My plan was to create a udevdb_init function that took arguments for initializing the db to start, where you could specify in memory only or a file location. This can all be filled in. 3) I hacked the Makefile to get it to work. Not sure how you'd want that in the future. 4) This assumes TDB has been installed elsewhere, you would need to edit your Makefile and point it to the header and library locations. How do you want to do TDB in udev? Do you want to just reference it and make udev dependent on that package being installed. Or should we do what samba does and include a limited tdb version in udev? 5) Again, I hacked udev into your existing code. In the future, I'd probably make a function around the filling out the udevice before calling the store command. Didn't know if you wanted to change your add device function to use struct udevice rather than having everything separate. 6) Not sure what we should include in the udevice structure that's stored by udev. I made a stab at a first shot - we can add and remove of course, this was a first pass. I've come to realize - with you including libsysfs in udev, the "external" interface that references udevdb could make use of getting information from through libsysfs from sysfs and doesn't need to be in udevdb. 7) I could write a namedevdb for namedev's device management if you wanted.
2003-08-06 10:57:23 +04:00
{
struct stat stats;
char filename[PATH_SIZE];
char line[PATH_SIZE];
unsigned int maj, min;
char *bufline;
char *buf;
size_t bufsize;
size_t cur;
size_t count;
sysfs_device_set_values(udevice->udev, udevice->dev, devpath, NULL, NULL);
devpath_to_db_path(udevice->udev, devpath, filename, sizeof(filename));
if (lstat(filename, &stats) != 0) {
info(udevice->udev, "no db file to read %s: %s\n", filename, strerror(errno));
return -1;
}
if ((stats.st_mode & S_IFMT) == S_IFLNK) {
char target[NAME_SIZE];
int target_len;
info(udevice->udev, "found a symlink as db file\n");
target_len = readlink(filename, target, sizeof(target));
if (target_len > 0)
target[target_len] = '\0';
else {
info(udevice->udev, "error reading db link %s: %s\n", filename, strerror(errno));
return -1;
}
dbg(udevice->udev, "db link points to '%s'\n", target);
strlcpy(udevice->name, target, sizeof(udevice->name));
return 0;
}
if (file_map(filename, &buf, &bufsize) != 0) {
info(udevice->udev, "error reading db file %s: %s\n", filename, strerror(errno));
return -1;
}
cur = 0;
while (cur < bufsize) {
count = buf_get_line(buf, bufsize, cur);
bufline = &buf[cur];
cur += count+1;
2008-04-21 22:22:56 +04:00
if (count > sizeof(line))
count = sizeof(line);
memcpy(line, &bufline[2], count-2);
line[count-2] = '\0';
switch(bufline[0]) {
case 'N':
strlcpy(udevice->name, line, sizeof(udevice->name));
break;
case 'M':
sscanf(line, "%u:%u", &maj, &min);
udevice->devt = makedev(maj, min);
break;
case 'S':
name_list_add(udevice->udev, &udevice->symlink_list, line, 0);
break;
case 'L':
udevice->link_priority = atoi(line);
break;
2008-04-21 22:22:56 +04:00
case 'T':
udevice->event_timeout = atoi(line);
2008-04-21 22:22:56 +04:00
break;
case 'A':
udevice->partitions = atoi(line);
break;
case 'R':
udevice->ignore_remove = atoi(line);
break;
case 'E':
name_list_add(udevice->udev, &udevice->env_list, line, 0);
break;
}
}
2005-03-05 04:33:31 +03:00
file_unmap(buf, bufsize);
if (udevice->name[0] == '\0')
return -1;
return 0;
[PATCH] udevdb prototype Here's an "idea" of what I had in mind for udevdb. Let me preface the code with a few remarks: 1) I was expecting to write this udevdb for udev to keep track of devices. I was planning an external package that depends upon udev to provide an external API to the udevdb database. The calls for the interface would be read only access. Not sure how you want to do packaging, if having a separate package is ok or having it included in udev. 2) I created it as it is because udev isn't a daemon. So, the open database call doesn't take any parameters. My plan was to create a udevdb_init function that took arguments for initializing the db to start, where you could specify in memory only or a file location. This can all be filled in. 3) I hacked the Makefile to get it to work. Not sure how you'd want that in the future. 4) This assumes TDB has been installed elsewhere, you would need to edit your Makefile and point it to the header and library locations. How do you want to do TDB in udev? Do you want to just reference it and make udev dependent on that package being installed. Or should we do what samba does and include a limited tdb version in udev? 5) Again, I hacked udev into your existing code. In the future, I'd probably make a function around the filling out the udevice before calling the store command. Didn't know if you wanted to change your add device function to use struct udevice rather than having everything separate. 6) Not sure what we should include in the udevice structure that's stored by udev. I made a stab at a first shot - we can add and remove of course, this was a first pass. I've come to realize - with you including libsysfs in udev, the "external" interface that references udevdb could make use of getting information from through libsysfs from sysfs and doesn't need to be in udevdb. 7) I could write a namedevdb for namedev's device management if you wanted.
2003-08-06 10:57:23 +04:00
}
int udev_db_delete_device(struct udevice *udevice)
[PATCH] udevdb prototype Here's an "idea" of what I had in mind for udevdb. Let me preface the code with a few remarks: 1) I was expecting to write this udevdb for udev to keep track of devices. I was planning an external package that depends upon udev to provide an external API to the udevdb database. The calls for the interface would be read only access. Not sure how you want to do packaging, if having a separate package is ok or having it included in udev. 2) I created it as it is because udev isn't a daemon. So, the open database call doesn't take any parameters. My plan was to create a udevdb_init function that took arguments for initializing the db to start, where you could specify in memory only or a file location. This can all be filled in. 3) I hacked the Makefile to get it to work. Not sure how you'd want that in the future. 4) This assumes TDB has been installed elsewhere, you would need to edit your Makefile and point it to the header and library locations. How do you want to do TDB in udev? Do you want to just reference it and make udev dependent on that package being installed. Or should we do what samba does and include a limited tdb version in udev? 5) Again, I hacked udev into your existing code. In the future, I'd probably make a function around the filling out the udevice before calling the store command. Didn't know if you wanted to change your add device function to use struct udevice rather than having everything separate. 6) Not sure what we should include in the udevice structure that's stored by udev. I made a stab at a first shot - we can add and remove of course, this was a first pass. I've come to realize - with you including libsysfs in udev, the "external" interface that references udevdb could make use of getting information from through libsysfs from sysfs and doesn't need to be in udevdb. 7) I could write a namedevdb for namedev's device management if you wanted.
2003-08-06 10:57:23 +04:00
{
char filename[PATH_SIZE];
struct name_entry *name_loop;
if (udevice->test_run)
2007-03-21 13:55:26 +03:00
return 0;
devpath_to_db_path(udevice->udev, udevice->dev->devpath, filename, sizeof(filename));
2005-02-21 15:48:10 +03:00
unlink(filename);
name_index(udevice->udev, udevice->dev->devpath, udevice->name, 0);
list_for_each_entry(name_loop, &udevice->symlink_list, node)
name_index(udevice->udev, udevice->dev->devpath, name_loop->name, 0);
2005-02-21 15:48:10 +03:00
return 0;
}
int udev_db_get_all_entries(struct udev *udev, struct list_head *name_list)
{
char dbpath[PATH_MAX];
DIR *dir;
strlcpy(dbpath, udev_get_dev_path(udev), sizeof(dbpath));
2008-07-30 03:45:23 +04:00
strlcat(dbpath, "/.udev/db", sizeof(dbpath));
dir = opendir(dbpath);
if (dir == NULL) {
info(udev, "no udev_db available '%s': %s\n", dbpath, strerror(errno));
return -1;
}
while (1) {
struct dirent *ent;
char device[PATH_SIZE];
ent = readdir(dir);
if (ent == NULL || ent->d_name[0] == '\0')
break;
if (ent->d_name[0] == '.')
continue;
strlcpy(device, ent->d_name, sizeof(device));
path_decode(device);
name_list_add(udev, name_list, device, 1);
dbg(udev, "added '%s'\n", device);
}
closedir(dir);
return 0;
}