• 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 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