void udev_node_add(struct udev_device *dev, mode_t mode, uid_t uid, gid_t gid) { struct udev *udev = udev_device_get_udev(dev); char filename[UTIL_PATH_SIZE]; struct udev_list_entry *list_entry; int err = 0; info(udev, "handling device node '%s', devnum=%s, mode=%#o, uid=%d, gid=%d\n", udev_device_get_devnode(dev), udev_device_get_id_filename(dev), mode, uid, gid); if (node_fixup(dev, mode, uid, gid) < 0) return; /* always add /dev/{block,char}/$major:$minor */ snprintf(filename, sizeof(filename), "%s/%s/%u:%u", udev_get_dev_path(udev), strcmp(udev_device_get_subsystem(dev), "block") == 0 ? "block" : "char", major(udev_device_get_devnum(dev)), minor(udev_device_get_devnum(dev))); node_symlink(udev, udev_device_get_devnode(dev), filename); /* create/update symlinks, add symlinks to name index */ udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(dev)) { if (udev_list_entry_get_num(list_entry)) /* simple unmanaged link name */ node_symlink(udev, udev_device_get_devnode(dev), udev_list_entry_get_name(list_entry)); else link_update(dev, udev_list_entry_get_name(list_entry), 1); } }
void udev_node_update_old_links(struct udev_device *dev, struct udev_device *dev_old) { struct udev *udev = udev_device_get_udev(dev); struct udev_list_entry *list_entry; /* update possible left-over symlinks */ udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(dev_old)) { const char *name = udev_list_entry_get_name(list_entry); struct udev_list_entry *list_entry_current; int found; /* check if old link name still belongs to this device */ found = 0; udev_list_entry_foreach(list_entry_current, udev_device_get_devlinks_list_entry(dev)) { const char *name_current = udev_list_entry_get_name(list_entry_current); if (strcmp(name, name_current) == 0) { found = 1; break; } } if (found) continue; info(udev, "update old name, '%s' no longer belonging to '%s'\n", name, udev_device_get_devpath(dev)); link_update(dev, name, 0); } }
static struct udev_device *handle_scsi_fibre_channel(struct udev_device *parent, char **path) { struct udev *udev = udev_device_get_udev(parent); struct udev_device *targetdev; struct udev_device *fcdev = NULL; const char *port; unsigned int lun; targetdev = udev_device_get_parent_with_subsystem_devtype(parent, "scsi", "scsi_target"); if (targetdev == NULL) return NULL; fcdev = udev_device_new_from_subsystem_sysname(udev, "fc_transport", udev_device_get_sysname(targetdev)); if (fcdev == NULL) return NULL; port = udev_device_get_sysattr_value(fcdev, "port_name"); if (port == NULL) { parent = NULL; goto out; } lun = strtoul(udev_device_get_sysnum(parent), NULL, 10); path_prepend(path, "fc-%s:0x%04x%04x00000000", port, lun & 0xffff, (lun >> 16) & 0xffff); out: udev_device_unref(fcdev); return parent; }
UdevContext UdevDevice::getContext(void) { /* Get the udev context and reference it: */ udev* context=udev_device_get_udev(device); udev_ref(context); /* Return a context object: */ return UdevContext(context); }
static struct udev_device *handle_scsi_iscsi(struct udev_device *parent, char **path) { struct udev *udev = udev_device_get_udev(parent); struct udev_device *transportdev; struct udev_device *sessiondev = NULL; const char *target; char *connname; struct udev_device *conndev = NULL; const char *addr; const char *port; /* find iscsi session */ transportdev = parent; while (1) { transportdev = udev_device_get_parent(transportdev); if (transportdev == NULL) return NULL; if (strncmp(udev_device_get_sysname(transportdev), "session", 7) == 0) break; } if (transportdev == NULL) return NULL; /* find iscsi session device */ sessiondev = udev_device_new_from_subsystem_sysname(udev, "iscsi_session", udev_device_get_sysname(transportdev)); if (sessiondev == NULL) return NULL; target = udev_device_get_sysattr_value(sessiondev, "targetname"); if (target == NULL) { parent = NULL; goto out; } if (asprintf(&connname, "connection%s:0", udev_device_get_sysnum(transportdev)) < 0) { parent = NULL; goto out; } conndev = udev_device_new_from_subsystem_sysname(udev, "iscsi_connection", connname); free(connname); if (conndev == NULL) { parent = NULL; goto out; } addr = udev_device_get_sysattr_value(conndev, "persistent_address"); port = udev_device_get_sysattr_value(conndev, "persistent_port"); if (addr == NULL || port == NULL) { parent = NULL; goto out; } path_prepend(path, "ip-%s:%s-iscsi-%s-lun-%s", addr, port, target, udev_device_get_sysnum(parent)); out: udev_device_unref(sessiondev); udev_device_unref(conndev); return parent; }
int udev_builtin_run(struct udev_device *dev, enum udev_builtin_cmd cmd, const char *command, bool test) { char arg[UTIL_PATH_SIZE]; int argc; char *argv[128]; optind = 0; util_strscpy(arg, sizeof(arg), command); udev_build_argv(udev_device_get_udev(dev), arg, &argc, argv); return builtins[cmd]->cmd(dev, argc, argv, test); }
/* find device node of device with highest priority */ static const char *link_find_prioritized(struct udev_device *dev, bool add, const char *stackdir, char *buf, size_t bufsize) { struct udev *udev = udev_device_get_udev(dev); DIR *dir; int priority = 0; const char *target = NULL; if (add) { priority = udev_device_get_devlink_priority(dev); util_strscpy(buf, bufsize, udev_device_get_devnode(dev)); target = buf; } dir = opendir(stackdir); if (dir == NULL) return target; for (;;) { struct udev_device *dev_db; struct dirent *dent; dent = readdir(dir); if (dent == NULL || dent->d_name[0] == '\0') break; if (dent->d_name[0] == '.') continue; info(udev, "found '%s' claiming '%s'\n", dent->d_name, stackdir); /* did we find ourself? */ if (strcmp(dent->d_name, udev_device_get_id_filename(dev)) == 0) continue; dev_db = udev_device_new_from_device_id(udev, dent->d_name); if (dev_db != NULL) { const char *devnode; devnode = udev_device_get_devnode(dev_db); if (devnode != NULL) { dbg(udev, "compare priority of '%s'(%i) > '%s'(%i)\n", target, priority, udev_device_get_devnode(dev_db), udev_device_get_devlink_priority(dev_db)); if (target == NULL || udev_device_get_devlink_priority(dev_db) > priority) { info(udev, "'%s' claims priority %i for '%s'\n", udev_device_get_syspath(dev_db), udev_device_get_devlink_priority(dev_db), stackdir); priority = udev_device_get_devlink_priority(dev_db); util_strscpy(buf, bufsize, devnode); target = buf; } } udev_device_unref(dev_db); } } closedir(dir); return target; }
int udev_builtin_run(struct udev_device *dev, enum udev_builtin_cmd cmd, const char *command, bool test) { char arg[UTIL_PATH_SIZE]; int argc; char *argv[128]; /* we need '0' here to reset the internal state */ optind = 0; strscpy(arg, sizeof(arg), command); udev_build_argv(udev_device_get_udev(dev), arg, &argc, argv); return builtins[cmd]->cmd(dev, argc, argv, test); }
int udev_node_remove(struct udev_device *dev) { struct udev *udev = udev_device_get_udev(dev); struct udev_list_entry *list_entry; const char *devnode; struct stat stats; struct udev_device *dev_check; char filename[UTIL_PATH_SIZE]; int err = 0; /* remove/update symlinks, remove symlinks from name index */ udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(dev)) link_update(dev, udev_list_entry_get_name(list_entry), 0); devnode = udev_device_get_devnode(dev); if (devnode == NULL) goto out; if (stat(devnode, &stats) != 0) { info(udev, "device node '%s' not found\n", devnode); goto out; } if (stats.st_rdev != udev_device_get_devnum(dev)) { info(udev, "device node '%s' points to a different device, skip removal\n", devnode); err = -1; goto out; } dev_check = udev_device_new_from_syspath(udev, udev_device_get_syspath(dev)); if (dev_check != NULL) { /* do not remove device node if the same sys-device is re-created in the meantime */ info(udev, "keeping device node of existing device'%s'\n", devnode); udev_device_unref(dev_check); goto out; } info(udev, "removing device node '%s'\n", devnode); err = util_unlink_secure(udev, devnode); if (err == 0) util_delete_path(udev, devnode); /* remove /dev/{block,char}/$major:$minor */ snprintf(filename, sizeof(filename), "%s/%s/%u:%u", udev_get_dev_path(udev), strcmp(udev_device_get_subsystem(dev), "block") == 0 ? "block" : "char", major(udev_device_get_devnum(dev)), minor(udev_device_get_devnum(dev))); unlink(filename); out: return err; }
/* find device node of device with highest priority */ static const char *link_find_prioritized(struct udev_device *dev, bool add, const char *stackdir, char *buf, size_t bufsize) { struct udev *udev = udev_device_get_udev(dev); DIR *dir; struct dirent *dent; int priority = 0; const char *target = NULL; if (add) { priority = udev_device_get_devlink_priority(dev); strscpy(buf, bufsize, udev_device_get_devnode(dev)); target = buf; } dir = opendir(stackdir); if (dir == NULL) return target; FOREACH_DIRENT_ALL(dent, dir, break) { struct udev_device *dev_db; if (dent->d_name[0] == '\0') break; if (dent->d_name[0] == '.') continue; log_debug("found '%s' claiming '%s'", dent->d_name, stackdir); /* did we find ourself? */ if (streq(dent->d_name, udev_device_get_id_filename(dev))) continue; dev_db = udev_device_new_from_device_id(udev, dent->d_name); if (dev_db != NULL) { const char *devnode; devnode = udev_device_get_devnode(dev_db); if (devnode != NULL) { if (target == NULL || udev_device_get_devlink_priority(dev_db) > priority) { log_debug("'%s' claims priority %i for '%s'", udev_device_get_syspath(dev_db), udev_device_get_devlink_priority(dev_db), stackdir); priority = udev_device_get_devlink_priority(dev_db); strscpy(buf, bufsize, devnode); target = buf; } } udev_device_unref(dev_db); } } closedir(dir); return target; }
/* manage "stack of names" with possibly specified device priorities */ static void link_update(struct udev_device *dev, const char *slink, bool add) { struct udev *udev = udev_device_get_udev(dev); char name_enc[UTIL_PATH_SIZE]; char filename[UTIL_PATH_SIZE * 2]; char dirname[UTIL_PATH_SIZE]; const char *target; char buf[UTIL_PATH_SIZE]; dbg(udev, "update symlink '%s' of '%s'\n", slink, udev_device_get_syspath(dev)); util_path_encode(&slink[strlen(udev_get_dev_path(udev))+1], name_enc, sizeof(name_enc)); util_strscpyl(dirname, sizeof(dirname), udev_get_run_path(udev), "/links/", name_enc, NULL); util_strscpyl(filename, sizeof(filename), dirname, "/", udev_device_get_id_filename(dev), NULL); if (!add) { dbg(udev, "removing index: '%s'\n", filename); if (unlink(filename) == 0) rmdir(dirname); } target = link_find_prioritized(dev, add, dirname, buf, sizeof(buf)); if (target == NULL) { info(udev, "no reference left, remove '%s'\n", slink); if (unlink(slink) == 0) util_delete_path(udev, slink); } else { info(udev, "creating link '%s' to '%s'\n", slink, target); node_symlink(udev, target, slink); } if (add) { int err; dbg(udev, "creating index: '%s'\n", filename); do { int fd; err = util_create_path(udev, filename); if (err != 0 && err != -ENOENT) break; fd = open(filename, O_WRONLY|O_CREAT|O_CLOEXEC|O_TRUNC|O_NOFOLLOW, 0444); if (fd >= 0) close(fd); else err = -errno; } while (err == -ENOENT); } }
struct udev_event *udev_event_new(struct udev_device *dev) { struct udev *udev = udev_device_get_udev(dev); struct udev_event *event; event = new0(struct udev_event, 1); if (event == NULL) return NULL; event->dev = dev; event->udev = udev; udev_list_init(udev, &event->run_list, false); udev_list_init(udev, &event->seclabel_list, false); event->fd_signal = -1; event->birth_usec = now(CLOCK_MONOTONIC); return event; }
static int node_fixup(struct udev_device *dev, mode_t mode, uid_t uid, gid_t gid) { struct udev *udev = udev_device_get_udev(dev); const char *devnode = udev_device_get_devnode(dev); dev_t devnum = udev_device_get_devnum(dev); struct stat stats; int err = 0; if (strcmp(udev_device_get_subsystem(dev), "block") == 0) mode |= S_IFBLK; else mode |= S_IFCHR; if (lstat(devnode, &stats) != 0) { err = -errno; info(udev, "can not stat() node '%s' (%m)\n", devnode); goto out; } if (((stats.st_mode & S_IFMT) != (mode & S_IFMT)) || (stats.st_rdev != devnum)) { err = -EEXIST; info(udev, "found node '%s' with non-matching devnum %s, skip handling\n", udev_device_get_devnode(dev), udev_device_get_id_filename(dev)); goto out; } if ((stats.st_mode & 0777) != (mode & 0777) || stats.st_uid != uid || stats.st_gid != gid) { info(udev, "set permissions %s, %#o, uid=%u, gid=%u\n", devnode, mode, uid, gid); chmod(devnode, mode); chown(devnode, uid, gid); } else { info(udev, "preserve permissions %s, %#o, uid=%u, gid=%u\n", devnode, mode, uid, gid); } /* * Set initial selinux file context only on add events. * We set the proper context on bootup (triger) or for newly * added devices, but we don't change it later, in case * something else has set a custom context in the meantime. */ if (strcmp(udev_device_get_action(dev), "add") == 0) udev_selinux_lsetfilecon(udev, devnode, mode); /* always update timestamp when we re-use the node, like on media change events */ utimensat(AT_FDCWD, devnode, NULL, 0); out: return err; }
struct udev_event *udev_event_new(struct udev_device *dev) { struct udev *udev = udev_device_get_udev(dev); struct udev_event *event; event = calloc(1, sizeof(struct udev_event)); if (event == NULL) return NULL; event->dev = dev; event->udev = udev; udev_list_init(udev, &event->run_list, false); event->fd_signal = -1; event->birth_usec = now(CLOCK_MONOTONIC); event->timeout_usec = 30 * 1000 * 1000; return event; }
int udev_node_remove(struct udev_device *dev) { struct udev *udev = udev_device_get_udev(dev); struct udev_list_entry *list_entry; const char *devnode; char partitionname[UTIL_PATH_SIZE]; struct stat stats; int err = 0; int num; /* remove,update symlinks, remove symlinks from name index */ udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(dev)) link_update(dev, udev_list_entry_get_name(list_entry), 0); devnode = udev_device_get_devnode(dev); if (devnode == NULL) return 0; if (stat(devnode, &stats) != 0) { info(udev, "device node '%s' not found\n", devnode); return 0; } if (stats.st_rdev != udev_device_get_devnum(dev)) { info(udev, "device node '%s' points to a different device, skip removal\n", devnode); return -1; } info(udev, "removing device node '%s'\n", devnode); err = util_unlink_secure(udev, devnode); if (err) return err; num = udev_device_get_num_fake_partitions(dev); if (num > 0) { int i; info(udev, "removing all_partitions '%s[1-%i]'\n", devnode, num); if (num > 255) return -1; for (i = 1; i <= num; i++) { snprintf(partitionname, sizeof(partitionname), "%s%d", devnode, i); partitionname[sizeof(partitionname)-1] = '\0'; util_unlink_secure(udev, partitionname); } } util_delete_path(udev, devnode); return err; }
/* manage "stack of names" with possibly specified device priorities */ static void link_update(struct udev_device *dev, const char *slink, bool add) { struct udev *udev = udev_device_get_udev(dev); char name_enc[UTIL_PATH_SIZE]; char filename[UTIL_PATH_SIZE * 2]; char dirname[UTIL_PATH_SIZE]; const char *target; char buf[UTIL_PATH_SIZE]; dbg(udev, "update symlink '%s' of '%s'\n", slink, udev_device_get_syspath(dev)); util_path_encode(&slink[strlen(udev_get_dev_path(udev))+1], name_enc, sizeof(name_enc)); snprintf(dirname, sizeof(dirname), "%s/.udev/links/%s", udev_get_dev_path(udev), name_enc); snprintf(filename, sizeof(filename), "%s/%c%u:%u", dirname, strcmp(udev_device_get_subsystem(dev), "block") == 0 ? 'b' : 'c', major(udev_device_get_devnum(dev)), minor(udev_device_get_devnum(dev))); if (!add) { dbg(udev, "removing index: '%s'\n", filename); unlink(filename); util_delete_path(udev, filename); } target = link_find_prioritized(dev, add, dirname, buf, sizeof(buf)); if (target == NULL) { info(udev, "no reference left, remove '%s'\n", slink); unlink(slink); util_delete_path(udev, slink); } else { info(udev, "creating link '%s' to '%s'\n", slink, target); node_symlink(udev, target, slink); } if (add) { int err; dbg(udev, "creating index: '%s'\n", filename); do { err = util_create_path(udev, filename); if (err != 0 && err != -ENOENT) break; err = symlink(udev_device_get_devpath(dev), filename); if (err != 0) err = -errno; } while (err == -ENOENT); } }
int udev_node_add(struct udev_device *dev, mode_t mode, uid_t uid, gid_t gid, int test) { struct udev *udev = udev_device_get_udev(dev); int i; int num; struct udev_list_entry *list_entry; int err = 0; info(udev, "creating device node '%s', devnum=%d:%d, mode=%#o, uid=%d, gid=%d\n", udev_device_get_devnode(dev), major(udev_device_get_devnum(dev)), minor(udev_device_get_devnum(dev)), mode, uid, gid); util_create_path(udev, udev_device_get_devnode(dev)); if (!test) if (udev_node_mknod(dev, NULL, makedev(0,0), mode, uid, gid) != 0) { err = -1; goto exit; } /* create all_partitions if requested */ num = udev_device_get_num_fake_partitions(dev); if (num > 0) { info(udev, "creating device partition nodes '%s[1-%i]'\n", udev_device_get_devnode(dev), num); if (!test) { for (i = 1; i <= num; i++) { char partitionname[UTIL_PATH_SIZE]; dev_t part_devnum; snprintf(partitionname, sizeof(partitionname), "%s%d", udev_device_get_devnode(dev), i); partitionname[sizeof(partitionname)-1] = '\0'; part_devnum = makedev(major(udev_device_get_devnum(dev)), minor(udev_device_get_devnum(dev)) + i); udev_node_mknod(dev, partitionname, part_devnum, mode, uid, gid); } } } /* add node to name index */ name_index(udev, udev_device_get_devpath(dev), udev_device_get_devnode(dev), 1, test); /* create/update symlinks, add symlinks to name index */ udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(dev)) { name_index(udev, udev_device_get_devpath(dev), udev_list_entry_get_name(list_entry), 1, test); update_link(dev, udev_list_entry_get_name(list_entry), test); }
int udev_node_add(struct udev_device *dev, mode_t mode, uid_t uid, gid_t gid) { struct udev *udev = udev_device_get_udev(dev); int i; int num; struct udev_list_entry *list_entry; int err = 0; info(udev, "creating device node '%s', devnum=%d:%d, mode=%#o, uid=%d, gid=%d\n", udev_device_get_devnode(dev), major(udev_device_get_devnum(dev)), minor(udev_device_get_devnum(dev)), mode, uid, gid); if (udev_node_mknod(dev, NULL, makedev(0,0), mode, uid, gid) != 0) { err = -1; goto exit; } /* create all_partitions if requested */ num = udev_device_get_num_fake_partitions(dev); if (num > 0) { info(udev, "creating device partition nodes '%s[1-%i]'\n", udev_device_get_devnode(dev), num); for (i = 1; i <= num; i++) { char partitionname[UTIL_PATH_SIZE]; dev_t part_devnum; snprintf(partitionname, sizeof(partitionname), "%s%d", udev_device_get_devnode(dev), i); partitionname[sizeof(partitionname)-1] = '\0'; part_devnum = makedev(major(udev_device_get_devnum(dev)), minor(udev_device_get_devnum(dev)) + i); udev_node_mknod(dev, partitionname, part_devnum, mode, uid, gid); } } /* create/update symlinks, add symlinks to name index */ udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(dev)) { if (udev_list_entry_get_flag(list_entry)) /* simple unmanaged link name */ node_symlink(udev, udev_device_get_devnode(dev), udev_list_entry_get_name(list_entry)); else link_update(dev, udev_list_entry_get_name(list_entry), 1); } exit: return err; }
void udev_node_update_old_links(struct udev_device *dev, struct udev_device *dev_old, int test) { struct udev *udev = udev_device_get_udev(dev); struct udev_list_entry *list_entry; const char *devnode_old; /* update possible left-over symlinks */ udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(dev_old)) { const char *name = udev_list_entry_get_name(list_entry); struct udev_list_entry *list_entry_current; int found; /* check if old link name is now our node name */ if (strcmp(name, udev_device_get_devnode(dev)) == 0) continue; /* check if old link name still belongs to this device */ found = 0; udev_list_entry_foreach(list_entry_current, udev_device_get_devlinks_list_entry(dev)) { const char *name_current = udev_list_entry_get_name(list_entry_current); if (strcmp(name, name_current) == 0) { found = 1; break; } } if (found) continue; info(udev, "update old symlink '%s' no longer belonging to '%s'\n", name, udev_device_get_devpath(dev)); name_index(udev, udev_device_get_devpath(dev), name, 0, test); update_link(dev, name, test); } /* * if the node name has changed, delete the node, * and possibly restore a symlink of another device */ devnode_old = udev_device_get_devnode(dev_old); if (devnode_old != NULL) { const char *devnode = udev_device_get_devnode(dev); if (devnode != NULL && strcmp(devnode_old, devnode) != 0) update_link(dev, devnode_old, test); } }
extern int udev_node_remove(struct udev_device *dev, int test) { struct udev *udev = udev_device_get_udev(dev); struct udev_list_entry *list_entry; const char *devnode; char partitionname[UTIL_PATH_SIZE]; struct stat stats; int err = 0; int num; /* remove node from name index */ name_index(udev, udev_device_get_devpath(dev), udev_device_get_devnode(dev), 0, test); /* remove,update symlinks, remove symlinks from name index */ udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(dev)) { name_index(udev, udev_device_get_devpath(dev), udev_list_entry_get_name(list_entry), 0, test); update_link(dev, udev_list_entry_get_name(list_entry), test); }
/* manage "stack of names" with possibly specified device priorities */ static void link_update(struct udev_device *dev, const char *slink, bool add) { struct udev *udev = udev_device_get_udev(dev); char name_enc[UTIL_PATH_SIZE]; char filename[UTIL_PATH_SIZE * 2]; char dirname[UTIL_PATH_SIZE]; const char *target; char buf[UTIL_PATH_SIZE]; util_path_encode(slink + strlen("/dev"), name_enc, sizeof(name_enc)); strscpyl(dirname, sizeof(dirname), "/run/udev/links/", name_enc, NULL); strscpyl(filename, sizeof(filename), dirname, "/", udev_device_get_id_filename(dev), NULL); if (!add && unlink(filename) == 0) rmdir(dirname); target = link_find_prioritized(dev, add, dirname, buf, sizeof(buf)); if (target == NULL) { log_debug("no reference left, remove '%s'", slink); if (unlink(slink) == 0) util_delete_path(udev, slink); } else { log_debug("creating link '%s' to '%s'", slink, target); node_symlink(dev, target, slink); } if (add) { int err; do { int fd; err = mkdir_parents(filename, 0755); if (err != 0 && err != -ENOENT) break; fd = open(filename, O_WRONLY|O_CREAT|O_CLOEXEC|O_TRUNC|O_NOFOLLOW, 0444); if (fd >= 0) close(fd); else err = -errno; } while (err == -ENOENT); } }
static int builtin_kmod(struct udev_device *dev, int argc, char *argv[], bool test) { struct udev *udev = udev_device_get_udev(dev); int i; if (!ctx) return 0; if (argc < 3 || !streq(argv[1], "load")) { log_error("expect: %s load <module>", argv[0]); return EXIT_FAILURE; } for (i = 2; argv[i]; i++) { log_debug("execute '%s' '%s'", argv[1], argv[i]); load_module(udev, argv[i]); } return EXIT_SUCCESS; }
/* * Read a capability attribute and return bitmask. * @param dev udev_device * @param attr sysfs attribute name (e. g. "capabilities/key") * @param bitmask: Output array which has a sizeof of bitmask_size */ static void get_cap_mask(struct udev_device *dev, struct udev_device *pdev, const char* attr, unsigned long *bitmask, size_t bitmask_size, bool test) { struct udev *udev = udev_device_get_udev(dev); char text[4096]; unsigned i; char* word; unsigned long val; snprintf(text, sizeof(text), "%s", udev_device_get_sysattr_value(pdev, attr)); info(udev, "%s raw kernel attribute: %s\n", attr, text); memset (bitmask, 0, bitmask_size); i = 0; while ((word = strrchr(text, ' ')) != NULL) { val = strtoul (word+1, NULL, 16); if (i < bitmask_size/sizeof(unsigned long)) bitmask[i] = val; else info(udev, "ignoring %s block %lX which is larger than maximum size\n", attr, val); *word = '\0'; ++i; } val = strtoul (text, NULL, 16); if (i < bitmask_size / sizeof(unsigned long)) bitmask[i] = val; else info(udev, "ignoring %s block %lX which is larger than maximum size\n", attr, val); if (test) { /* printf pattern with the right unsigned long number of hex chars */ snprintf(text, sizeof(text), " bit %%4u: %%0%zilX\n", 2 * sizeof(unsigned long)); info(udev, "%s decoded bit map:\n", attr); val = bitmask_size / sizeof (unsigned long); /* skip over leading zeros */ while (bitmask[val-1] == 0 && val > 0) --val; for (i = 0; i < val; ++i) info(udev, text, i * BITS_PER_LONG, bitmask[i]); } }
/* key like devices */ static void test_key (struct udev_device *dev, const unsigned long* bitmask_ev, const unsigned long* bitmask_key, bool test) { struct udev *udev = udev_device_get_udev(dev); unsigned i; unsigned long found; unsigned long mask; /* do we have any KEY_* capability? */ if (!test_bit (EV_KEY, bitmask_ev)) { info(udev, "test_key: no EV_KEY capability\n"); return; } /* only consider KEY_* here, not BTN_* */ found = 0; for (i = 0; i < BTN_MISC/BITS_PER_LONG; ++i) { found |= bitmask_key[i]; info(udev, "test_key: checking bit block %lu for any keys; found=%i\n", i*BITS_PER_LONG, found > 0); } /* If there are no keys in the lower block, check the higher block */ if (!found) { for (i = KEY_OK; i < BTN_TRIGGER_HAPPY; ++i) { if (test_bit (i, bitmask_key)) { info(udev, "test_key: Found key %x in high block\n", i); found = 1; break; } } } if (found > 0) udev_builtin_add_property(dev, test, "ID_INPUT_KEY", "1"); /* the first 32 bits are ESC, numbers, and Q to D; if we have all of * those, consider it a full keyboard; do not test KEY_RESERVED, though */ mask = 0xFFFFFFFE; if ((bitmask_key[0] & mask) == mask) udev_builtin_add_property(dev, test, "ID_INPUT_KEYBOARD", "1"); }
void udev_node_remove(struct udev_device *dev) { struct udev *udev = udev_device_get_udev(dev); struct udev_list_entry *list_entry; const char *devnode; struct stat stats; struct udev_device *dev_check; char filename[UTIL_PATH_SIZE]; /* remove/update symlinks, remove symlinks from name index */ udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(dev)) link_update(dev, udev_list_entry_get_name(list_entry), 0); /* remove /dev/{block,char}/$major:$minor */ snprintf(filename, sizeof(filename), "%s/%s/%u:%u", udev_get_dev_path(udev), strcmp(udev_device_get_subsystem(dev), "block") == 0 ? "block" : "char", major(udev_device_get_devnum(dev)), minor(udev_device_get_devnum(dev))); unlink(filename); }
///////////////////////////////////////////////////////////////////////////// /// calculate disk indices using scsi_host unique_id int DeviceMonitor::scsiHostIndex_( udev_device* device ) { udev* udev = udev_device_get_udev(device); std::string device_sys_path (udev_device_get_syspath(device)); std::string bus_prefix (""); bool use_ata = false; int host_index = 0; int bus_index_correction = 0; size_t index_of = device_sys_path.find("/ata"); if (index_of != std::string::npos) { bus_prefix.append(device_sys_path.substr(0, index_of + 4)); host_index = device_sys_path.at(index_of + 10) - '0'; bus_index_correction = device_sys_path.at(index_of + 4) - '0' - host_index; use_ata = true; } else { index_of = device_sys_path.find("/host"); bus_prefix.append(device_sys_path.substr(0, index_of)); host_index = device_sys_path.at(index_of) - '0'; } int scsi_host_index = -1; for (int i = 0; i <= host_index; i++) { std::string dev_path (bus_prefix); if (use_ata) { dev_path.append(1, '0' + bus_index_correction + i); } dev_path.append("/host"); dev_path.append(1, '0' + i); udev_device* dev_host = udev_device_new_from_syspath(udev, dev_path.c_str()); if (dev_host) { scsi_host_index++; } } return scsi_host_index; }
static char *get_leds_syspath_prefix(struct udev_device *udevice) { struct udev_list_entry *dev_list_entry; struct udev_enumerate *enumerate; struct udev_device *hid_parent; const char *syspath; char *syspath_prefix; hid_parent = udev_device_get_parent_with_subsystem_devtype(udevice, "hid", NULL); enumerate = udev_enumerate_new(udev_device_get_udev(udevice)); udev_enumerate_add_match_parent(enumerate, hid_parent); udev_enumerate_add_match_subsystem(enumerate, "leds"); udev_enumerate_scan_devices(enumerate); dev_list_entry = udev_enumerate_get_list_entry(enumerate); if (!dev_list_entry) { syspath_prefix = NULL; goto out; } syspath = udev_list_entry_get_name(dev_list_entry); /* * All the sysfs paths of the LEDs have the same structure, just the * number changes, so strip it and store only the common prefix. * * Subtracting 1 here means assuming that the LED number is a single * digit, this is safe as the kernel driver only exposes 4 LEDs. */ syspath_prefix = strndup(syspath, strlen(syspath) - 1); out: udev_enumerate_unref(enumerate); return syspath_prefix; }
static int dev_pci_slot(struct udev_device *dev, struct netnames *names) { struct udev *udev = udev_device_get_udev(names->pcidev); unsigned domain, bus, slot, func, dev_port = 0; size_t l; char *s; const char *attr; struct udev_device *pci = NULL; char slots[256], str[256]; _cleanup_closedir_ DIR *dir = NULL; struct dirent *dent; int hotplug_slot = 0, err = 0; if (sscanf(udev_device_get_sysname(names->pcidev), "%x:%x:%x.%u", &domain, &bus, &slot, &func) != 4) return -ENOENT; /* kernel provided port index for multiple ports on a single PCI function */ attr = udev_device_get_sysattr_value(dev, "dev_port"); if (attr) dev_port = strtol(attr, NULL, 10); /* compose a name based on the raw kernel's PCI bus, slot numbers */ s = names->pci_path; l = sizeof(names->pci_path); if (domain > 0) l = strpcpyf(&s, l, "P%u", domain); l = strpcpyf(&s, l, "p%us%u", bus, slot); if (func > 0 || is_pci_multifunction(names->pcidev)) l = strpcpyf(&s, l, "f%u", func); if (dev_port > 0) l = strpcpyf(&s, l, "d%u", dev_port); if (l == 0) names->pci_path[0] = '\0'; /* ACPI _SUN — slot user number */ pci = udev_device_new_from_subsystem_sysname(udev, "subsystem", "pci"); if (!pci) { err = -ENOENT; goto out; } xsprintf(slots, "%s/slots", udev_device_get_syspath(pci)); dir = opendir(slots); if (!dir) { err = -errno; goto out; } for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) { int i; char *rest; char *address; if (dent->d_name[0] == '.') continue; i = strtol(dent->d_name, &rest, 10); if (rest[0] != '\0') continue; if (i < 1) continue; xsprintf(str, "%s/%s/address", slots, dent->d_name); if (read_one_line_file(str, &address) >= 0) { /* match slot address with device by stripping the function */ if (strneq(address, udev_device_get_sysname(names->pcidev), strlen(address))) hotplug_slot = i; free(address); } if (hotplug_slot > 0) break; } if (hotplug_slot > 0) { s = names->pci_slot; l = sizeof(names->pci_slot); if (domain > 0) l = strpcpyf(&s, l, "P%d", domain); l = strpcpyf(&s, l, "s%d", hotplug_slot); if (func > 0 || is_pci_multifunction(names->pcidev)) l = strpcpyf(&s, l, "f%d", func); if (dev_port > 0) l = strpcpyf(&s, l, "d%d", dev_port); if (l == 0) names->pci_slot[0] = '\0'; } out: udev_device_unref(pci); return err; }
static int builtin_firmware(struct udev_device *dev, int argc, char *argv[], bool test) { struct udev *udev = udev_device_get_udev(dev); static const char *searchpath[] = { FIRMWARE_PATH }; char loadpath[UTIL_PATH_SIZE]; char datapath[UTIL_PATH_SIZE]; char fwpath[UTIL_PATH_SIZE]; const char *firmware; FILE *fwfile = NULL; struct utsname kernel; struct stat statbuf; unsigned int i; int rc = EXIT_SUCCESS; firmware = udev_device_get_property_value(dev, "FIRMWARE"); if (firmware == NULL) { log_error("firmware parameter missing"); rc = EXIT_FAILURE; goto exit; } /* lookup firmware file */ uname(&kernel); for (i = 0; i < ELEMENTSOF(searchpath); i++) { strscpyl(fwpath, sizeof(fwpath), searchpath[i], kernel.release, "/", firmware, NULL); fwfile = fopen(fwpath, "re"); if (fwfile != NULL) break; strscpyl(fwpath, sizeof(fwpath), searchpath[i], firmware, NULL); fwfile = fopen(fwpath, "re"); if (fwfile != NULL) break; } strscpyl(loadpath, sizeof(loadpath), udev_device_get_syspath(dev), "/loading", NULL); if (fwfile == NULL) { log_debug("did not find firmware file '%s'", firmware); rc = EXIT_FAILURE; /* * Do not cancel the request in the initrd, the real root might have * the firmware file and the 'coldplug' run in the real root will find * this pending request and fulfill or cancel it. * */ if (!in_initrd()) set_loading(udev, loadpath, "-1"); goto exit; } if (stat(fwpath, &statbuf) < 0 || statbuf.st_size == 0) { if (!in_initrd()) set_loading(udev, loadpath, "-1"); rc = EXIT_FAILURE; goto exit; } if (!set_loading(udev, loadpath, "1")) goto exit; strscpyl(datapath, sizeof(datapath), udev_device_get_syspath(dev), "/data", NULL); if (!copy_firmware(udev, fwpath, datapath, statbuf.st_size)) { log_error("error sending firmware '%s' to device", firmware); set_loading(udev, loadpath, "-1"); rc = EXIT_FAILURE; goto exit; }; set_loading(udev, loadpath, "0"); exit: if (fwfile) fclose(fwfile); return rc; }
static int dev_pci_slot(struct udev_device *dev, struct netnames *names) { struct udev *udev = udev_device_get_udev(names->pcidev); unsigned int bus; unsigned int slot; unsigned int func; unsigned int dev_id = 0; size_t l; char *s; const char *attr; struct udev_device *pci = NULL; char slots[256]; DIR *dir; struct dirent *dent; char str[256]; int hotplug_slot = 0; int err = 0; if (sscanf(udev_device_get_sysname(names->pcidev), "0000:%x:%x.%d", &bus, &slot, &func) != 3) return -ENOENT; /* kernel provided multi-device index */ attr = udev_device_get_sysattr_value(dev, "dev_id"); if (attr) dev_id = strtol(attr, NULL, 16); /* compose a name based on the raw kernel's PCI bus, slot numbers */ s = names->pci_path; l = util_strpcpyf(&s, sizeof(names->pci_path), "p%ds%d", bus, slot); if (func > 0 || is_pci_multifunction(names->pcidev)) l = util_strpcpyf(&s, l, "f%d", func); if (dev_id > 0) l = util_strpcpyf(&s, l, "d%d", dev_id); if (l == 0) names->pci_path[0] = '\0'; /* ACPI _SUN -- slot user number */ pci = udev_device_new_from_subsystem_sysname(udev, "subsystem", "pci"); if (!pci) { err = -ENOENT; goto out; } snprintf(slots, sizeof(slots), "%s/slots", udev_device_get_syspath(pci)); dir = opendir(slots); if (!dir) { err = -errno; goto out; } for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) { int i; char *rest; char *address; if (dent->d_name[0] == '.') continue; i = strtol(dent->d_name, &rest, 10); if (rest[0] != '\0') continue; if (i < 1) continue; snprintf(str, sizeof(str), "%s/%s/address", slots, dent->d_name); if (read_one_line_file(str, &address) >= 0) { /* match slot address with device by stripping the function */ if (strncmp(address, udev_device_get_sysname(names->pcidev), strlen(address)) == 0) hotplug_slot = i; free(address); } if (hotplug_slot > 0) break; } closedir(dir); if (hotplug_slot > 0) { s = names->pci_slot; l = util_strpcpyf(&s, sizeof(names->pci_slot), "s%d", hotplug_slot); if (func > 0 || is_pci_multifunction(names->pcidev)) l = util_strpcpyf(&s, l, "f%d", func); if (dev_id > 0) l = util_strpcpyf(&s, l, "d%d", dev_id); if (l == 0) names->pci_path[0] = '\0'; } out: udev_device_unref(pci); return err; }