|
@@ -0,0 +1,163 @@
|
|
|
+// SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
+
|
|
|
+#include "common.h"
|
|
|
+
|
|
|
+#define BUFLEN 64
|
|
|
+
|
|
|
+const char *const block_dir_name = "/sys/class/block";
|
|
|
+
|
|
|
+struct partname_volume {
|
|
|
+ struct volume v;
|
|
|
+ char devname[16];
|
|
|
+ char parent_devname[16];
|
|
|
+};
|
|
|
+
|
|
|
+static struct driver partname_driver;
|
|
|
+
|
|
|
+static int partname_volume_identify(struct volume *v)
|
|
|
+{
|
|
|
+ int ret = FS_NONE;
|
|
|
+ FILE *f;
|
|
|
+
|
|
|
+ f = fopen(v->blk, "r");
|
|
|
+ if (!f)
|
|
|
+ return ret;
|
|
|
+
|
|
|
+ ret = block_file_identify(f, 0);
|
|
|
+
|
|
|
+ fclose(f);
|
|
|
+
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+static int partname_volume_init(struct volume *v)
|
|
|
+{
|
|
|
+ struct partname_volume *p = container_of(v, struct partname_volume, v);
|
|
|
+ char voldir[BUFLEN];
|
|
|
+ char voldev[BUFLEN];
|
|
|
+ char pdev[BUFLEN];
|
|
|
+ unsigned int volsize;
|
|
|
+
|
|
|
+ snprintf(voldir, sizeof(voldir), "%s/%s", block_dir_name, p->devname);
|
|
|
+
|
|
|
+ if (read_uint_from_file(voldir, "size", &volsize))
|
|
|
+ return -1;
|
|
|
+
|
|
|
+ snprintf(voldev, sizeof(voldev), "/dev/%s", p->devname);
|
|
|
+ snprintf(pdev, sizeof(pdev), "/dev/%s", p->parent_devname);
|
|
|
+
|
|
|
+ v->type = BLOCKDEV;
|
|
|
+ v->size = volsize << 9; /* size is returned in sectors of 512 bytes */
|
|
|
+ v->blk = strdup(voldev);
|
|
|
+
|
|
|
+ return block_volume_format(v, 0, pdev);
|
|
|
+}
|
|
|
+
|
|
|
+/* from procd/utils.c -> should go to libubox */
|
|
|
+static char* get_cmdline_val(const char* name, char* out, int len)
|
|
|
+{
|
|
|
+ char line[1024], *c, *sptr;
|
|
|
+ int fd = open("/proc/cmdline", O_RDONLY);
|
|
|
+ ssize_t r = read(fd, line, sizeof(line) - 1);
|
|
|
+ close(fd);
|
|
|
+
|
|
|
+ if (r <= 0)
|
|
|
+ return NULL;
|
|
|
+
|
|
|
+ line[r] = 0;
|
|
|
+
|
|
|
+ for (c = strtok_r(line, " \t\n", &sptr); c;
|
|
|
+ c = strtok_r(NULL, " \t\n", &sptr)) {
|
|
|
+ char *sep = strchr(c, '=');
|
|
|
+ if (sep == NULL)
|
|
|
+ continue;
|
|
|
+
|
|
|
+ ssize_t klen = sep - c;
|
|
|
+ if (strncmp(name, c, klen) || name[klen] != 0)
|
|
|
+ continue;
|
|
|
+
|
|
|
+ strncpy(out, &sep[1], len);
|
|
|
+ out[len-1] = 0;
|
|
|
+ return out;
|
|
|
+ }
|
|
|
+
|
|
|
+ return NULL;
|
|
|
+}
|
|
|
+
|
|
|
+static char *rootdevname(char *devpath) {
|
|
|
+ int l;
|
|
|
+
|
|
|
+ l = strlen(devpath) - 1;
|
|
|
+
|
|
|
+ /* strip partition suffix from root=/dev/... string */
|
|
|
+ while (l > 0 && (devpath[l] >= '0' && devpath[l] <= '9'))
|
|
|
+ --l;
|
|
|
+
|
|
|
+ if (devpath[l] != 'p')
|
|
|
+ ++l;
|
|
|
+
|
|
|
+ devpath[l] = '\0';
|
|
|
+
|
|
|
+ return basename(devpath);
|
|
|
+}
|
|
|
+
|
|
|
+static struct volume *partname_volume_find(char *name)
|
|
|
+{
|
|
|
+ struct partname_volume *p;
|
|
|
+ char volnamegstr[BUFLEN];
|
|
|
+ char namebuf[BUFLEN];
|
|
|
+ char rootparam[BUFLEN];
|
|
|
+ char *rootdev = NULL, *devname, *tmp;
|
|
|
+ int j;
|
|
|
+ bool found = false;
|
|
|
+ glob_t gl;
|
|
|
+
|
|
|
+ if (get_cmdline_val("root", rootparam, sizeof(rootparam))) {
|
|
|
+ rootdev = rootdevname(rootparam);
|
|
|
+ /* find partition on same device as rootfs */
|
|
|
+ snprintf(volnamegstr, sizeof(volnamegstr), "%s/%s/*/name", block_dir_name, rootdev);
|
|
|
+ } else {
|
|
|
+ /* no 'root=' kernel cmdline parameter, find on any block device */
|
|
|
+ snprintf(volnamegstr, sizeof(volnamegstr), "%s/*/name", block_dir_name);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!glob(volnamegstr, GLOB_NOESCAPE, NULL, &gl))
|
|
|
+ for (j = 0; j < gl.gl_pathc; j++) {
|
|
|
+ if (!read_string_from_file("", gl.gl_pathv[j], namebuf, sizeof(namebuf)))
|
|
|
+ continue;
|
|
|
+ if (!strncmp(namebuf, name, sizeof(namebuf))) {
|
|
|
+ found = 1;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!found)
|
|
|
+ return NULL;
|
|
|
+
|
|
|
+ devname = gl.gl_pathv[j];
|
|
|
+ tmp = strrchr(devname, '/');
|
|
|
+ *tmp = '\0';
|
|
|
+ devname = strrchr(devname, '/') + 1;
|
|
|
+
|
|
|
+ p = calloc(1, sizeof(*p));
|
|
|
+ strncpy(p->devname, devname, sizeof(p->devname));
|
|
|
+ if (rootdev)
|
|
|
+ strncpy(p->parent_devname, rootdev, sizeof(p->devname));
|
|
|
+ else
|
|
|
+ strncpy(p->parent_devname, rootdevname(devname), sizeof(p->devname));
|
|
|
+
|
|
|
+ p->devname[sizeof(p->devname)-1] = '\0';
|
|
|
+ p->v.drv = &partname_driver;
|
|
|
+ p->v.name = strdup(namebuf);
|
|
|
+
|
|
|
+ return &p->v;
|
|
|
+}
|
|
|
+
|
|
|
+static struct driver partname_driver = {
|
|
|
+ .name = "partname",
|
|
|
+ .find = partname_volume_find,
|
|
|
+ .init = partname_volume_init,
|
|
|
+ .identify = partname_volume_identify,
|
|
|
+};
|
|
|
+
|
|
|
+DRIVER(partname_driver);
|