1
0
mirror of https://github.com/systemd/systemd.git synced 2024-10-28 20:25:38 +03:00
systemd/udev-add.c
dsteklof@us.ibm.com 8e41d35d76 [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.
2005-04-26 21:01:40 -07:00

199 lines
4.6 KiB
C

/*
* udev-add.c
*
* Userspace devfs
*
* Copyright (C) 2003 Greg Kroah-Hartman <greg@kroah.com>
*
*
* 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.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include "udev.h"
#include "udev_version.h"
#include "namedev.h"
#include "udevdb.h"
#include "libsysfs/libsysfs.h"
/*
* Right now the major/minor of a device is stored in a file called
* "dev" in sysfs.
* The number is stored as:
* MMmm
* MM is the major
* mm is the minor
* The value is in hex.
* Yes, this will probably change when we go to a bigger major/minor
* range, and will have to be changed at that time.
*/
static int get_major_minor(struct sysfs_class_device *class_dev, int *major, int *minor)
{
int retval = -ENODEV;
char *dev;
dev = sysfs_get_value_from_attributes(class_dev->directory->attributes, "dev");
if (dev == NULL)
goto exit;
dbg("dev = %s", dev);
if (sscanf(dev, "%u:%u", major, minor) != 2)
goto exit;
dbg("found major = %d, minor = %d", *major, *minor);
retval = 0;
exit:
return retval;
}
/*
* We also want to add some permissions here, and possibly some symlinks
*/
static int create_node(char *name, char type, int major, int minor, int mode)
{
char filename[255];
int retval = 0;
strncpy(filename, UDEV_ROOT, sizeof(filename));
strncat(filename, name, sizeof(filename));
switch (type) {
case 'b':
mode |= S_IFBLK;
break;
case 'c':
case 'u':
mode |= S_IFCHR;
break;
case 'p':
mode |= S_IFIFO;
break;
default:
dbg("unknown node type %c\n", type);
return -EINVAL;
}
retval = mknod(filename,mode,makedev(major,minor));
if (retval)
dbg("mknod(%s, %#o, %u, %u) failed with error '%s'",
filename, mode, major, minor, strerror(errno));
return retval;
}
struct sysfs_class_device *get_class_dev(char *device_name)
{
char sysfs_path[SYSFS_PATH_MAX];
char dev_path[SYSFS_PATH_MAX];
int retval;
struct sysfs_class_device *class_dev = NULL;
retval = sysfs_get_mnt_path(sysfs_path, SYSFS_PATH_MAX);
dbg("sysfs_path = %s", sysfs_path);
if (retval) {
dbg("sysfs_get_mnt_path failed");
goto exit;
}
strcpy(dev_path, sysfs_path);
strcat(dev_path, device_name);
dbg("looking at %s", dev_path);
/* open up the sysfs class device for this thing... */
class_dev = sysfs_open_class_device(dev_path);
if (class_dev == NULL) {
dbg ("sysfs_open_class_device failed");
goto exit;
}
dbg("class_dev->name = %s", class_dev->name);
exit:
return class_dev;
}
int udev_add_device(char *device, char *subsystem)
{
struct sysfs_class_device *class_dev;
struct device_attr attr;
int major;
int minor;
char type;
int retval = -EINVAL;
/* for now, the block layer is the only place where block devices are */
if (strcmp(subsystem, "block") == 0)
type = 'b';
else
type = 'c';
/* sleep for a second or two to give the kernel a chance to
* create the dev file
*/
sleep(1);
class_dev = get_class_dev(device);
if (class_dev == NULL)
goto exit;
retval = namedev_name_device(class_dev, &attr);
if (retval)
return retval;
retval = get_major_minor(class_dev, &major, &minor);
if (retval) {
dbg ("get_major_minor failed");
goto exit;
}
memset(&dbdev, 0, sizeof(dbdev));
strncpy(dbdev.name, attr.name, NAME_SIZE);
strncpy(dbdev.sysfs_path, class_dev->sysdevice->directory->path,
PATH_SIZE);
strncpy(dbdev.class_dev_name, class_dev->name, NAME_SIZE);
if ((sysfs_get_name_from_path(subsystem, dbdev.class_name, NAME_SIZE))
!= 0)
strcpy(dbdev.class_name, "unkown");
strncpy(dbdev.bus_id, class_dev->sysdevice->bus_id, ID_SIZE);
strcpy(dbdev.bus_name, "unknown");
if (class_dev->driver != NULL)
strncpy(dbdev.driver, class_dev->driver->name, NAME_SIZE);
else
strcpy(dbdev.driver, "unkown");
dbdev.type = type;
dbdev.major = major;
dbdev.minor = minor;
dbdev.mode = attr.mode;
sysfs_close_class_device(class_dev);
retval = udevdb_add_udevice(&dbdev);
if (retval != 0)
goto exit;
return create_node(attr.name, type, major, minor, attr.mode);
exit:
return retval;
}