1 // SPDX-License-Identifier: GPL-2.0-or-later
12 struct partname_volume
{
16 struct devpath devpath
;
21 struct devpath devpath
;
25 static struct driver partname_driver
;
27 static int partname_volume_identify(struct volume
*v
)
29 struct partname_volume
*p
= container_of(v
, struct partname_volume
, v
);
33 f
= fopen(p
->dev
.devpathstr
, "r");
37 ret
= block_file_identify(f
, 0);
44 static int partname_volume_init(struct volume
*v
)
46 struct partname_volume
*p
= container_of(v
, struct partname_volume
, v
);
50 snprintf(voldir
, sizeof(voldir
), "%s/%s", block_dir_name
, p
->dev
.devpath
.device
);
52 if (read_uint_from_file(voldir
, "size", &volsize
))
56 v
->size
= volsize
<< 9; /* size is returned in sectors of 512 bytes */
57 v
->blk
= p
->dev
.devpathstr
;
59 return block_volume_format(v
, 0, p
->parent_dev
.devpathstr
);
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
)
65 char line
[1024], *c
, *sptr
;
66 int fd
= open(filename
, O_RDONLY
);
70 ssize_t r
= read(fd
, line
, sizeof(line
) - 1);
78 for (c
= strtok_r(line
, " \t\n", &sptr
); c
;
79 c
= strtok_r(NULL
, " \t\n", &sptr
)) {
80 char *sep
= strchr(c
, '=');
84 ssize_t klen
= sep
- c
;
85 if (strncmp(name
, c
, klen
) || name
[klen
] != 0)
88 strncpy(out
, &sep
[1], len
);
96 static char *rootdevname(char *devpath
) {
99 l
= strlen(devpath
) - 1;
101 /* strip partition suffix from root=/dev/... string */
102 while (l
> 0 && (devpath
[l
] >= '0' && devpath
[l
] <= '9'))
105 if (devpath
[l
] != 'p')
110 return basename(devpath
);
113 static struct volume
*partname_volume_find(char *name
)
115 struct partname_volume
*p
;
116 char ueventgstr
[BUFLEN
];
117 char namebuf
[BUFLEN
];
118 char rootparam
[BUFLEN
];
119 char *rootdev
= NULL
, *devname
, *tmp
;
122 bool allow_fallback
= false;
123 bool has_root
= false;
126 if (get_var_from_file("/proc/cmdline", "fstools_ignore_partname", rootparam
, sizeof(rootparam
))) {
127 if (!strcmp("1", rootparam
))
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.
138 if (get_var_from_file("/proc/cmdline", "fstools_partname_fallback_scan", rootparam
, sizeof(rootparam
))) {
139 if (!strcmp("1", rootparam
))
140 allow_fallback
= true;
143 if (get_var_from_file("/proc/cmdline", "root", rootparam
, sizeof(rootparam
)))
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
);
151 /* For compatibility, devices with root= params must explicitly opt into this fallback. */
152 if (has_root
&& !allow_fallback
)
155 /* no useful 'root=' kernel cmdline parameter, find on any block device */
156 snprintf(ueventgstr
, sizeof(ueventgstr
), "%s/*/uevent", block_dir_name
);
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
)))
163 if (!strncmp(namebuf
, name
, sizeof(namebuf
))) {
172 devname
= gl
.gl_pathv
[j
];
173 tmp
= strrchr(devname
, '/');
178 devname
= strrchr(devname
, '/') + 1;
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';
185 memcpy(p
->parent_dev
.devpath
.prefix
, "/dev/", sizeof(p
->parent_dev
.devpath
.prefix
));
187 strncpy(p
->parent_dev
.devpath
.device
, rootdev
, sizeof(p
->parent_dev
.devpath
.device
) - 1);
189 strncpy(p
->parent_dev
.devpath
.device
, rootdevname(devname
), sizeof(p
->parent_dev
.devpath
.device
) - 1);
191 p
->parent_dev
.devpath
.device
[sizeof(p
->parent_dev
.devpath
.device
)-1] = '\0';
193 p
->v
.drv
= &partname_driver
;
194 p
->v
.blk
= p
->dev
.devpathstr
;
200 static struct driver partname_driver
= {
203 .find
= partname_volume_find
,
204 .init
= partname_volume_init
,
205 .identify
= partname_volume_identify
,
208 DRIVER(partname_driver
);