• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/fstools/libfstools/partname.c

  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