static int get_dev_mtd(const char *fdt_flash_path, char **mtd_path) { struct dirent **namelist; char fdt_node_path[PATH_MAX]; int count, i, rc, fd; bool done; if (!fdt_flash_path) return -1; fd = open(fdt_flash_path, O_RDONLY); if (fd == -1) { fprintf(stderr, "Couldn't open '%s' FDT attribute to determine which flash device to use\n", fdt_flash_path); fprintf(stderr, "Does your skiboot new enough to expose the flash through the device tree?\n"); hint_root(); return -1; } rc = read(fd, fdt_node_path, sizeof(fdt_node_path)); close(fd); if (rc == -1) { fprintf(stderr, "Couldn't read flash FDT node from '%s'\n", fdt_flash_path); hint_root(); return -1; } count = scandir(SYSFS_MTD_PATH, &namelist, NULL, alphasort); if (count == -1) { fprintf(stderr, "Couldn't scan '%s' for MTD\n", SYSFS_MTD_PATH); hint_root(); return -1; } rc = 0; done = false; for (i = 0; i < count; i++) { struct dirent *dirent; char *dev_path; char fdt_node_path_tmp[PATH_MAX]; dirent = namelist[i]; /* * The call to asprintf must happen last as when it succeeds it * will allocate dev_path */ if (dirent->d_name[0] == '.' || rc || done || asprintf(&dev_path, "%s/%s/device/of_node", SYSFS_MTD_PATH, dirent->d_name) < 0) { free(namelist[i]); continue; } rc = readlink(dev_path, fdt_node_path_tmp, sizeof(fdt_node_path_tmp) - 1); free(dev_path); if (rc == -1) { /* * This might fail because it could not exist if the system has flash * devices that present as mtd but don't have corresponding FDT * nodes, just continue silently. */ free(namelist[i]); /* Should still try the next dir so reset rc */ rc = 0; continue; } fdt_node_path_tmp[rc] = '\0'; if (strstr(fdt_node_path_tmp, fdt_node_path)) { uint32_t flags, size; /* * size and flags could perhaps have be gotten another way but this * method is super unlikely to fail so it will do. */ /* Check to see if device is writeable */ rc = get_dev_attr(dirent->d_name, "flags", &flags); if (rc) { free(namelist[i]); continue; } /* Get the size of the mtd device while we're at it */ rc = get_dev_attr(dirent->d_name, "size", &size); if (rc) { free(namelist[i]); continue; } rc = asprintf(&dev_path, "/dev/%s", dirent->d_name); if (rc < 0) { free(namelist[i]); continue; } rc = 0; *mtd_path = dev_path; done = true; } free(namelist[i]); } free(namelist); if (!done) { fprintf(stderr, "Couldn't find '%s' corresponding MTD\n", fdt_flash_path); fprintf(stderr, "Is your kernel new enough to expose MTD?\n"); } /* explicit negative value so as to not return a libflash code */ return done ? rc : -1; }
static int open_from_dev(struct gard_ctx *ctx, const char *fdt_flash_path) { struct dirent **namelist; char fdt_node_path[PATH_MAX]; int count, i, rc, fd; bool done; if (!fdt_flash_path) return -1; fd = open(fdt_flash_path, O_RDONLY); if (fd == -1) { fprintf(stderr, "Couldn't open '%s' FDT attribute to determine which flash device to use\n", fdt_flash_path); return -1; } rc = read(fd, fdt_node_path, sizeof(fdt_node_path)); close(fd); if (rc == -1) { fprintf(stderr, "Couldn't read flash FDT node from '%s'\n", fdt_flash_path); return -1; } count = scandir(SYSFS_MTD_PATH, &namelist, NULL, alphasort); if (count == -1) { fprintf(stderr, "Couldn't scan '%s' for MTD devices\n", SYSFS_MTD_PATH); return -1; } rc = 0; done = false; for (i = 0; i < count; i++) { struct dirent *dirent; char dev_path[PATH_MAX] = SYSFS_MTD_PATH; char fdt_node_path_tmp[PATH_MAX]; dirent = namelist[i]; if (dirent->d_name[0] == '.' || rc || done) { free(namelist[i]); continue; } strncat(dev_path, dirent->d_name, sizeof(dev_path) - strlen(dev_path) - 2); strncat(dev_path, "/device/of_node", sizeof(dev_path) - strlen(dev_path) - 2); rc = readlink(dev_path, fdt_node_path_tmp, sizeof(fdt_node_path_tmp) - 1); if (rc == -1) { /* * This might fail because it could not exist if the system has flash * devices that present as mtd but don't have corresponding FDT * nodes, just continue silently. */ free(namelist[i]); /* Should still try the next dir so reset rc */ rc = 0; continue; } fdt_node_path_tmp[rc] = '\0'; if (strstr(fdt_node_path_tmp, fdt_node_path)) { uint32_t flags, size; /* * size and flags could perhaps have be gotten another way but this * method is super unlikely to fail so it will do. */ /* Check to see if device is writeable */ rc = get_dev_attr(dirent->d_name, "flags", &flags); if (rc) { free(namelist[i]); continue; } /* Get the size of the mtd device while we're at it */ rc = get_dev_attr(dirent->d_name, "size", &size); if (rc) { free(namelist[i]); continue; } strcpy(dev_path, "/dev/"); strncat(dev_path, dirent->d_name, sizeof(dev_path) - strlen(dev_path) - 2); ctx->readonly = !(flags && MTD_WRITEABLE); ctx->f_size = size; ctx->fd = open(dev_path, ctx->readonly ? O_RDONLY : O_RDWR); if (ctx->fd == -1) { fprintf(stderr, "Couldn't open MTD device '%s' for %s as the system flash device\n", dev_path, ctx->readonly ? "reading" : "read/write"); rc = -1; } done = true; } free(namelist[i]); } free(namelist); if (!done) fprintf(stderr, "Couldn't find '%s' corresponding MTD\n", fdt_flash_path); /* explicit negative value so as to not return a libflash code */ return done ? rc : -1; }