1
0
mirror of https://github.com/systemd/systemd.git synced 2024-10-28 20:25:38 +03:00
systemd/udev_remove.c

201 lines
4.6 KiB
C
Raw Normal View History

/*
* udev-remove.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 <stddef.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
2004-10-19 10:14:20 +04:00
#include <sys/stat.h>
#include "udev.h"
#include "udev_lib.h"
#include "udev_version.h"
#include "namedev.h"
2004-11-12 08:32:19 +03:00
#include "udev_db.h"
#include "logging.h"
static int delete_path(const char *path)
{
char *pos;
int retval;
pos = strrchr(path, '/');
while (1) {
*pos = '\0';
pos = strrchr(path, '/');
/* don't remove the last one */
if ((pos == path) || (pos == NULL))
break;
/* remove if empty */
retval = rmdir(path);
if (errno == ENOENT)
retval = 0;
if (retval) {
if (errno == ENOTEMPTY)
return 0;
dbg("rmdir(%s) failed with error '%s'",
path, strerror(errno));
break;
}
dbg("removed '%s'", path);
}
return 0;
}
/** Remove all permissions on the device node, before
* unlinking it. This fixes a security issue.
* If the user created a hard-link to the device node,
* he can't use it any longer, because he lost permission
* to do so.
*/
static int secure_unlink(const char *filename)
{
int retval;
retval = chown(filename, 0, 0);
if (retval) {
dbg("chown(%s, 0, 0) failed with error '%s'",
filename, strerror(errno));
/* We continue nevertheless.
* I think it's very unlikely for chown
* to fail here, if the file exists.
*/
}
retval = chmod(filename, 0000);
if (retval) {
dbg("chmod(%s, 0000) failed with error '%s'",
filename, strerror(errno));
/* We continue nevertheless. */
}
retval = unlink(filename);
if (errno == ENOENT)
retval = 0;
if (retval) {
dbg("unlink(%s) failed with error '%s'",
filename, strerror(errno));
}
return retval;
}
static int delete_node(struct udevice *udev)
{
char filename[NAME_SIZE];
char partitionname[NAME_SIZE];
int retval;
int i;
char *pos;
int len;
int num;
snprintf(filename, NAME_SIZE, "%s/%s", udev_root, udev->name);
filename[NAME_SIZE-1] = '\0';
info("removing device node '%s'", filename);
retval = secure_unlink(filename);
if (retval)
return retval;
/* remove all_partitions nodes */
num = udev->partitions;
if (num > 0) {
info("removing all_partitions '%s[1-%i]'", filename, num);
if (num > PARTITIONS_COUNT) {
info("garbage from udev database, skip all_partitions removal");
return -1;
}
for (i = 1; i <= num; i++) {
strfieldcpy(partitionname, filename);
strintcat(partitionname, i);
secure_unlink(partitionname);
}
}
/* remove subdirectories */
if (strchr(udev->name, '/'))
delete_path(filename);
foreach_strpart(udev->symlink, " ", pos, len) {
char linkname[NAME_SIZE];
strfieldcpymax(linkname, pos, len+1);
snprintf(filename, NAME_SIZE, "%s/%s", udev_root, linkname);
filename[NAME_SIZE-1] = '\0';
dbg("unlinking symlink '%s'", filename);
retval = unlink(filename);
if (errno == ENOENT)
retval = 0;
if (retval) {
dbg("unlink(%s) failed with error '%s'",
filename, strerror(errno));
return retval;
}
if (strchr(udev->symlink, '/')) {
delete_path(filename);
}
}
return retval;
}
/*
* look up the sysfs path in the database to get the node name to remove
* If we can't find it, use kernel name for lack of anything else to know to do
*/
int udev_remove_device(struct udevice *udev)
{
const char *temp;
int retval;
if (udev->type != 'b' && udev->type != 'c')
return 0;
2004-11-12 08:32:19 +03:00
retval = udev_db_get_device(udev);
if (retval) {
/* fall back to kernel name */
temp = strrchr(udev->devpath, '/');
[PATCH] netdev - udevdb+dev.d changes Here is a patch to change the netdev handling in the database and for the dev.d/ calls. I applies on top of the udevd.patch, cause klibc has no sysinfo(). o netdev's are also put into our database now. I want this for the udevruler gui to get a list of all handled devices. All devices in the db are stamped with the system uptime value at the creation time. 'udevinfo -d' prints it. o the DEVPATH value is the key for udevdb, but if we rename a netdev, the name is replaced in the kernel, so we add the changed name to the db to match with the remove event. NOTE: The dev.d/ scripts still get the original name from the hotplug call. Should we replace DEVPATH with the new name too? o We now only add a device to the db, if we have successfully created the main node or successfully renamed a netdev. This is the main part of the patch, cause I needed to clean the retval passing trough all the functions used for node creation. o DEVNODE sounds a bit ugly for netdev's so I exported DEVNAME too. Can we change the name? o I've added a UDEV_NO_DEVD to possibly skip the script execution and used it in udev-test.pl. udevstart is the same horror now, if you have scripts with logging statements in dev.d/ it takes minutes to finish, can we skip the scripts here too? o The get_device_type() function is changed to be more strict, cause 'udevinfo -a -p /block/' gets a class device for it and tries to print the major/minor values. o bugfix, the RESULT value has now a working newline removal and a test for this case.
2004-04-01 11:12:57 +04:00
if (temp == NULL)
return -ENODEV;
strfieldcpy(udev->name, &temp[1]);
dbg("'%s' not found in database, falling back on default name", udev->name);
[PATCH] netdev - udevdb+dev.d changes Here is a patch to change the netdev handling in the database and for the dev.d/ calls. I applies on top of the udevd.patch, cause klibc has no sysinfo(). o netdev's are also put into our database now. I want this for the udevruler gui to get a list of all handled devices. All devices in the db are stamped with the system uptime value at the creation time. 'udevinfo -d' prints it. o the DEVPATH value is the key for udevdb, but if we rename a netdev, the name is replaced in the kernel, so we add the changed name to the db to match with the remove event. NOTE: The dev.d/ scripts still get the original name from the hotplug call. Should we replace DEVPATH with the new name too? o We now only add a device to the db, if we have successfully created the main node or successfully renamed a netdev. This is the main part of the patch, cause I needed to clean the retval passing trough all the functions used for node creation. o DEVNODE sounds a bit ugly for netdev's so I exported DEVNAME too. Can we change the name? o I've added a UDEV_NO_DEVD to possibly skip the script execution and used it in udev-test.pl. udevstart is the same horror now, if you have scripts with logging statements in dev.d/ it takes minutes to finish, can we skip the scripts here too? o The get_device_type() function is changed to be more strict, cause 'udevinfo -a -p /block/' gets a class device for it and tries to print the major/minor values. o bugfix, the RESULT value has now a working newline removal and a test for this case.
2004-04-01 11:12:57 +04:00
}
[PATCH] D-BUS patch for udev-008 Attached is a patch against udev-008 to send out a D-BUS message when a device node is added or removed. Using D-BUS lingo, udev acquires the org.kernel.udev service and sends out a NodeCreated or NodeDeleted signal on the org.kernel.udev.NodeMonitor interface. Each signal carries two parameters: the node in question and the corresponding sysfs path. [Note: the D-BUS concepts of service, interface, object can be a bit confusing at first glance] An example program listening for these messages looks like this #!/usr/bin/python import dbus import gtk def udev_signal_received(dbus_iface, member, service, object_path, message): [filename, sysfs_path] = message.get_args_list() if member=='NodeCreated': print 'Node %s created for %s'%(filename, sysfs_path) elif member=='NodeDeleted': print 'Node %s deleted for %s'%(filename, sysfs_path) def main(): bus = dbus.Bus(dbus.Bus.TYPE_SYSTEM) bus.add_signal_receiver(udev_signal_received, 'org.kernel.udev.NodeMonitor', # interface 'org.kernel.udev', # service '/org/kernel/udev/NodeMonitor') # object gtk.mainloop() if __name__ == '__main__': main() and this is the output when hot-plugging some usb-storage. [david@laptop udev-008]$ ~/node_monitor.py Node /udev/sda created for /block/sda Node /udev/sda1 created for /block/sda/sda1 Node /udev/sda1 deleted for /block/sda/sda1 Node /udev/sda deleted for /block/sda The patch requires D-BUS 0.20 or later while the python example program requires D-BUS from CVS as I only recently applied a patch against the python bindings.
2003-12-08 20:19:19 +03:00
if (udev->ignore_remove) {
dbg("remove event for '%s' requested to be ignored by rule", udev->name);
return 0;
}
dbg("remove name='%s'", udev->name);
2004-11-12 08:32:19 +03:00
udev_db_delete_device(udev);
[PATCH] hmm, handle net devices with udev? Hmm, Arndt Bergmann sent a patch like this one a few weeks ago and I want to bring the question back, if we want to handle net device naming with udev. With this patch it is actually possible to specify something like this in udev.rules: KERNEL="dummy*", SYSFS{address}="00:00:00:00:00:00", SYSFS{features}="0x0", NAME="blind%n" KERNEL="eth*", SYSFS{address}="00:0d:60:77:30:91", NAME="private" and you will get: [root@pim udev.kay]# cat /proc/net/dev Inter-| Receive | Transmit face |bytes packets errs drop fifo frame compressed multicast|bytes packets errs drop fifo colls carrier compressed lo: 1500 30 0 0 0 0 0 0 1500 30 0 0 0 0 0 0 private: 278393 1114 0 0 0 0 0 0 153204 1468 0 0 0 0 0 0 sit0: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 blind0: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 The udevinfo program is also working: [root@pim udev.kay]# ./udevinfo -a -p /sys/class/net/private looking at class device '/sys/class/net/private': SYSFS{addr_len}="6" SYSFS{address}="00:0d:60:77:30:91" SYSFS{broadcast}="ff:ff:ff:ff:ff:ff" SYSFS{features}="0x3a9" SYSFS{flags}="0x1003" SYSFS{ifindex}="2" SYSFS{iflink}="2" SYSFS{mtu}="1500" SYSFS{tx_queue_len}="1000" SYSFS{type}="1" follow the class device's "device" looking at the device chain at '/sys/devices/pci0000:00/0000:00:1e.0/0000:02:01.0': BUS="pci" ID="0000:02:01.0" SYSFS{class}="0x020000" SYSFS{detach_state}="0" SYSFS{device}="0x101e" SYSFS{irq}="11" SYSFS{subsystem_device}="0x0549" SYSFS{subsystem_vendor}="0x1014" SYSFS{vendor}="0x8086" The matching device will be renamed to the given name. The device name will not be put into the udev database, cause the kernel renames the device and the sysfs name disappears. I like it, cause it plugs in nicely. We have all the naming features and sysfs queries and walks inside of udev. The sysfs timing races are already solved and the management tools are working for net devices too. nameif can only match the MAC address now. udev can match any sysfs value of the device tree the net device is connected to. But right, net devices do not have device nodes :)
2004-03-25 10:19:39 +03:00
/* use full path to the environment */
snprintf(udev->devname, NAME_SIZE, "%s/%s", udev_root, udev->name);
return delete_node(udev);
}