/* 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, int test) { char device[UTIL_PATH_SIZE]; char filename[UTIL_PATH_SIZE * 2]; size_t devlen = strlen(udev_get_dev_path(udev))+1; size_t start; int fd; /* directory with device name */ util_strlcpy(filename, udev_get_dev_path(udev), sizeof(filename)); start = util_strlcat(filename, "/.udev/names/", sizeof(filename)); util_strlcat(filename, &name[devlen], sizeof(filename)); util_path_encode(&filename[start], sizeof(filename) - start); /* entry with the devpath */ util_strlcpy(device, devpath, sizeof(device)); util_path_encode(device, sizeof(device)); util_strlcat(filename, "/", sizeof(filename)); util_strlcat(filename, device, sizeof(filename)); if (add) { dbg(udev, "creating index: '%s'\n", filename); util_create_path(udev, filename); fd = open(filename, O_WRONLY|O_TRUNC|O_CREAT, 0644); if (fd > 0) close(fd); } else { dbg(udev, "removing index: '%s'\n", filename); unlink(filename); util_delete_path(udev, filename); } return 0; }
/* 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); } }
/* 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); } }
/* manage "stack of names" with possibly specified device priorities */ static int link_update(sd_device *dev, const char *slink, bool add) { _cleanup_free_ char *target = NULL, *filename = NULL, *dirname = NULL; char name_enc[PATH_MAX]; const char *id_filename; int r; assert(dev); assert(slink); r = device_get_id_filename(dev, &id_filename); if (r < 0) return log_device_debug_errno(dev, r, "Failed to get id_filename: %m"); util_path_encode(slink + STRLEN("/dev"), name_enc, sizeof(name_enc)); dirname = path_join("/run/udev/links/", name_enc); if (!dirname) return log_oom(); filename = path_join(dirname, id_filename); if (!filename) return log_oom(); if (!add && unlink(filename) == 0) (void) rmdir(dirname); r = link_find_prioritized(dev, add, dirname, &target); if (r < 0) { log_device_debug(dev, "No reference left, removing '%s'", slink); if (unlink(slink) == 0) (void) rmdir_parents(slink, "/"); } else (void) node_symlink(dev, target, slink); if (add) do { _cleanup_close_ int fd = -1; r = mkdir_parents(filename, 0755); if (!IN_SET(r, 0, -ENOENT)) break; fd = open(filename, O_WRONLY|O_CREAT|O_CLOEXEC|O_TRUNC|O_NOFOLLOW, 0444); if (fd < 0) r = -errno; } while (r == -ENOENT); return r; }
/* 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 name_index_get_devices(struct udev *udev, const char *name, struct udev_list_node *dev_list) { char dirname[PATH_MAX]; size_t devlen = strlen(udev_get_dev_path(udev))+1; size_t start; DIR *dir; int count = 0; util_strlcpy(dirname, udev_get_dev_path(udev), sizeof(dirname)); start = util_strlcat(dirname, "/.udev/names/", sizeof(dirname)); util_strlcat(dirname, &name[devlen], sizeof(dirname)); util_path_encode(&dirname[start], sizeof(dirname) - start); dir = opendir(dirname); if (dir == NULL) { dbg(udev, "no index directory '%s': %m\n", dirname); count = -1; goto out; } dbg(udev, "found index directory '%s'\n", dirname); while (1) { struct dirent *ent; char device[UTIL_PATH_SIZE]; ent = readdir(dir); if (ent == NULL || ent->d_name[0] == '\0') break; if (ent->d_name[0] == '.') continue; util_strlcpy(device, udev_get_sys_path(udev), sizeof(device)); util_strlcat(device, ent->d_name, sizeof(device)); util_path_decode(device); udev_list_entry_add(udev, dev_list, device, NULL, 1, 0); count++; } closedir(dir); out: return count; }
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 fwencpath[UTIL_PATH_SIZE]; char misspath[UTIL_PATH_SIZE]; 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\n\n"); rc = EXIT_FAILURE; goto exit; } /* lookup firmware file */ uname(&kernel); for (i = 0; i < ELEMENTSOF(searchpath); i++) { util_strscpyl(fwpath, sizeof(fwpath), searchpath[i], kernel.release, "/", firmware, NULL); fwfile = fopen(fwpath, "re"); if (fwfile != NULL) break; util_strscpyl(fwpath, sizeof(fwpath), searchpath[i], firmware, NULL); fwfile = fopen(fwpath, "re"); if (fwfile != NULL) break; } util_path_encode(firmware, fwencpath, sizeof(fwencpath)); util_strscpyl(misspath, sizeof(misspath), "/run/udev/firmware-missing/", fwencpath, NULL); util_strscpyl(loadpath, sizeof(loadpath), udev_device_get_syspath(dev), "/loading", NULL); if (fwfile == NULL) { int err; /* This link indicates the missing firmware file and the associated device */ log_debug("did not find firmware file '%s'\n", firmware); do { err = mkdir_parents(misspath, 0755); if (err != 0 && err != -ENOENT) break; err = symlink(udev_device_get_devpath(dev), misspath); if (err != 0) err = -errno; } while (err == -ENOENT); 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 (unlink(misspath) == 0) util_delete_path(udev, misspath); if (!set_loading(udev, loadpath, "1")) goto exit; util_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\n", firmware); set_loading(udev, loadpath, "-1"); rc = EXIT_FAILURE; goto exit; }; set_loading(udev, loadpath, "0"); exit: if (fwfile) fclose(fwfile); return rc; }