summaryrefslogtreecommitdiffstats
path: root/init
diff options
context:
space:
mode:
authorAndrew Boie <andrew.p.boie@intel.com>2013-09-13 17:41:20 -0700
committerAndrew Boie <andrew.p.boie@intel.com>2014-05-13 11:23:34 -0700
commita885d04ec8c9dd013a3dfc4434ec4f2cd23ef1ff (patch)
tree5fd208ebaaa1c21231a3cd14ce9c43c80ab8231c /init
parent905874abe45279d7c668e590d404880dd91b1869 (diff)
downloadsystem_core-a885d04ec8c9dd013a3dfc4434ec4f2cd23ef1ff.zip
system_core-a885d04ec8c9dd013a3dfc4434ec4f2cd23ef1ff.tar.gz
system_core-a885d04ec8c9dd013a3dfc4434ec4f2cd23ef1ff.tar.bz2
ueventd: support by-name symlinks for PCI block devices
To ensure that well-crafted removable media can't spoof the internal partitions, for platform devices the controller id is inside the generated path. We now do the same for PCI devices. The generated path has two levels; the PCI domain/bus, and then the peripheral ID. This lets us get by-name symlinks for PCI media, such as the SATA controllers on PC-like hardware. The symlinks will be created under /dev/block/pci/. For example: /dev/block/pci/pci0000:00/0000:00:1f.2/by-name/ Change-Id: Icee3e86bef5569c2bbd94c26bc00d49028345e3b Signed-off-by: Andrew Boie <andrew.p.boie@intel.com>
Diffstat (limited to 'init')
-rw-r--r--init/devices.c50
1 files changed, 44 insertions, 6 deletions
diff --git a/init/devices.c b/init/devices.c
index 5d7ad3b..3119e8e 100644
--- a/init/devices.c
+++ b/init/devices.c
@@ -298,6 +298,37 @@ static void remove_platform_device(const char *path)
}
}
+/* Given a path that may start with a PCI device, populate the supplied buffer
+ * with the PCI domain/bus number and the peripheral ID and return 0.
+ * If it doesn't start with a PCI device, or there is some error, return -1 */
+static int find_pci_device_prefix(const char *path, char *buf, ssize_t buf_sz)
+{
+ const char *start, *end;
+
+ if (strncmp(path, "/devices/pci", 12))
+ return -1;
+
+ /* Beginning of the prefix is the initial "pci" after "/devices/" */
+ start = path + 9;
+
+ /* End of the prefix is two path '/' later, capturing the domain/bus number
+ * and the peripheral ID. Example: pci0000:00/0000:00:1f.2 */
+ end = strchr(start, '/');
+ if (!end)
+ return -1;
+ end = strchr(end + 1, '/');
+ if (!end)
+ return -1;
+
+ /* Make sure we have enough room for the string plus null terminator */
+ if (end - start + 1 > buf_sz)
+ return -1;
+
+ strncpy(buf, start, end - start);
+ buf[end - start] = '\0';
+ return 0;
+}
+
#if LOG_UEVENTS
static inline suseconds_t get_usecs(void)
@@ -422,11 +453,12 @@ err:
return NULL;
}
-static char **parse_platform_block_device(struct uevent *uevent)
+static char **get_block_device_symlinks(struct uevent *uevent)
{
const char *device;
struct platform_node *pdev;
char *slash;
+ const char *type;
int width;
char buf[256];
char link_path[256];
@@ -438,18 +470,24 @@ static char **parse_platform_block_device(struct uevent *uevent)
struct stat info;
pdev = find_platform_device(uevent->path);
- if (!pdev)
+ if (pdev) {
+ device = pdev->name;
+ type = "platform";
+ } else if (!find_pci_device_prefix(uevent->path, buf, sizeof(buf))) {
+ device = buf;
+ type = "pci";
+ } else {
return NULL;
- device = pdev->name;
+ }
char **links = malloc(sizeof(char *) * 4);
if (!links)
return NULL;
memset(links, 0, sizeof(char *) * 4);
- INFO("found platform device %s\n", device);
+ INFO("found %s device %s\n", type, device);
- snprintf(link_path, sizeof(link_path), "/dev/block/platform/%s", device);
+ snprintf(link_path, sizeof(link_path), "/dev/block/%s/%s", type, device);
if (uevent->partition_name) {
p = strdup(uevent->partition_name);
@@ -556,7 +594,7 @@ static void handle_block_device_event(struct uevent *uevent)
make_dir(base, 0755);
if (!strncmp(uevent->path, "/devices/", 9))
- links = parse_platform_block_device(uevent);
+ links = get_block_device_symlinks(uevent);
handle_device(uevent->action, devpath, uevent->path, 1,
uevent->major, uevent->minor, links);