1 // SPDX-License-Identifier: GPL-2.0-or-later 2 3 #include "common.h" 4 5 #define BUFLEN 64 6 7 const char *const block_dir_name = "/sys/class/block"; 8 9 struct devpath { 10 char prefix[5]; 11 char device[11]; 12 }; 13 14 struct partname_volume { 15 struct volume v; 16 union { 17 char devpathstr[16]; 18 struct devpath devpath; 19 } dev; 20 21 union { 22 char devpathstr[16]; 23 struct devpath devpath; 24 } parent_dev; 25 }; 26 27 static struct driver partname_driver; 28 29 static int partname_volume_identify(struct volume *v) 30 { 31 struct partname_volume *p = container_of(v, struct partname_volume, v); 32 int ret = FS_NONE; 33 FILE *f; 34 35 f = fopen(p->dev.devpathstr, "r"); 36 if (!f) 37 return ret; 38 39 ret = block_file_identify(f, 0); 40 41 fclose(f); 42 43 return ret; 44 } 45 46 static int partname_volume_init(struct volume *v) 47 { 48 struct partname_volume *p = container_of(v, struct partname_volume, v); 49 char voldir[BUFLEN]; 50 unsigned int volsize; 51 52 snprintf(voldir, sizeof(voldir), "%s/%s", block_dir_name, p->dev.devpath.device); 53 54 if (read_uint_from_file(voldir, "size", &volsize)) 55 return -1; 56 57 v->type = BLOCKDEV; 58 v->size = volsize << 9; /* size is returned in sectors of 512 bytes */ 59 v->blk = p->dev.devpathstr; 60 61 return block_volume_format(v, 0, p->parent_dev.devpathstr); 62 } 63 64 /* adapted from procd/utils.c -> should go to libubox */ 65 static char* get_var_from_file(const char* filename, const char* name, char* out, int len) 66 { 67 char line[1024], *c, *sptr; 68 int fd = open(filename, O_RDONLY); 69 if (fd == -1) 70 return NULL; 71 72 ssize_t r = read(fd, line, sizeof(line) - 1); 73 close(fd); 74 75 if (r <= 0) 76 return NULL; 77 78 line[r] = 0; 79 80 for (c = strtok_r(line, " \t\n", &sptr); c; 81 c = strtok_r(NULL, " \t\n", &sptr)) { 82 char *sep = strchr(c, '='); 83 if (sep == NULL) 84 continue; 85 86 ssize_t klen = sep - c; 87 if (strncmp(name, c, klen) || name[klen] != 0) 88 continue; 89 90 strncpy(out, &sep[1], len); 91 out[len-1] = '\0'; 92 return out; 93 } 94 95 return NULL; 96 } 97 98 static char *rootdevname(char *devpath) { 99 int l; 100 101 l = strlen(devpath) - 1; 102 103 /* strip partition suffix from root=/dev/... string */ 104 while (l > 0 && (devpath[l] >= '' && devpath[l] <= '9')) 105 --l; 106 107 if (devpath[l] != 'p') 108 ++l; 109 110 devpath[l] = '\0'; 111 112 return basename(devpath); 113 } 114 115 static struct volume *partname_volume_find(char *name) 116 { 117 struct partname_volume *p; 118 char ueventgstr[BUFLEN]; 119 char namebuf[BUFLEN]; 120 char rootparam[BUFLEN]; 121 char *rootdev = NULL, *devname, *tmp; 122 int j; 123 bool found = false; 124 bool allow_fallback = false; 125 bool has_root = false; 126 glob_t gl; 127 128 if (get_var_from_file("/proc/cmdline", "fstools_ignore_partname", rootparam, sizeof(rootparam))) { 129 if (!strcmp("1", rootparam)) 130 return NULL; 131 } 132 133 /* 134 * Some device may contains a GPT partition named rootfs_data that may not be suitable. 135 * To save from regression with old implementation that doesn't use fstools_ignore_partname to 136 * explicitly say that that partname scan should be ignored, make explicit that scanning each 137 * partition should be done by providing fstools_partname_fallback_scan=1 and skip partname scan 138 * in every other case. 139 */ 140 if (get_var_from_file("/proc/cmdline", "fstools_partname_fallback_scan", rootparam, sizeof(rootparam))) { 141 if (!strcmp("1", rootparam)) 142 allow_fallback = true; 143 } 144 145 if (get_var_from_file("/proc/cmdline", "root", rootparam, sizeof(rootparam))) 146 has_root = true; 147 148 if (has_root && rootparam[0] == '/') { 149 rootdev = rootdevname(rootparam); 150 /* find partition on same device as rootfs */ 151 snprintf(ueventgstr, sizeof(ueventgstr), "%s/%s/*/uevent", block_dir_name, rootdev); 152 } else { 153 /* For compatibility, devices with root= params must explicitly opt into this fallback. */ 154 if (has_root && !allow_fallback) 155 return NULL; 156 157 /* no useful 'root=' kernel cmdline parameter, find on any block device */ 158 snprintf(ueventgstr, sizeof(ueventgstr), "%s/*/uevent", block_dir_name); 159 } 160 161 if (!glob(ueventgstr, GLOB_NOESCAPE, NULL, &gl)) 162 for (j = 0; j < gl.gl_pathc; j++) { 163 if (!get_var_from_file(gl.gl_pathv[j], "PARTNAME", namebuf, sizeof(namebuf))) 164 continue; 165 if (!strncmp(namebuf, name, sizeof(namebuf))) { 166 found = 1; 167 break; 168 } 169 } 170 171 if (!found) 172 return NULL; 173 174 devname = gl.gl_pathv[j]; 175 tmp = strrchr(devname, '/'); 176 if (!tmp) 177 return NULL; 178 179 *tmp = '\0'; 180 devname = strrchr(devname, '/') + 1; 181 182 p = calloc(1, sizeof(*p)); 183 memcpy(p->dev.devpath.prefix, "/dev/", sizeof(p->dev.devpath.prefix)); 184 strncpy(p->dev.devpath.device, devname, sizeof(p->dev.devpath.device) - 1); 185 p->dev.devpath.device[sizeof(p->dev.devpath.device)-1] = '\0'; 186 187 memcpy(p->parent_dev.devpath.prefix, "/dev/", sizeof(p->parent_dev.devpath.prefix)); 188 if (rootdev) 189 strncpy(p->parent_dev.devpath.device, rootdev, sizeof(p->parent_dev.devpath.device) - 1); 190 else 191 strncpy(p->parent_dev.devpath.device, rootdevname(devname), sizeof(p->parent_dev.devpath.device) - 1); 192 193 p->parent_dev.devpath.device[sizeof(p->parent_dev.devpath.device)-1] = '\0'; 194 195 p->v.drv = &partname_driver; 196 p->v.blk = p->dev.devpathstr; 197 p->v.name = name; 198 199 return &p->v; 200 } 201 202 static struct driver partname_driver = { 203 .name = "partname", 204 .find = partname_volume_find, 205 .init = partname_volume_init, 206 .identify = partname_volume_identify, 207 }; 208 209 DRIVER(partname_driver); 210
This page was automatically generated by LXR 0.3.1. • OpenWrt