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