--- /dev/null
+// 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);