libmount: improve conversion from root= to the devname
Currently the code supports /dev/name or PARTUUID= only. We also need to support 'maj:min' and 'hexhex' notations. Reported-by: George Spelvin <linux@horizon.com> Signed-off-by: Karel Zak <kzak@redhat.com>
This commit is contained in:
parent
12f5cbe159
commit
40f00b4f8e
5 changed files with 132 additions and 9 deletions
|
@ -36,6 +36,7 @@ extern void strtotimeval_or_err(const char *str, struct timeval *tv,
|
||||||
const char *errmesg);
|
const char *errmesg);
|
||||||
|
|
||||||
extern int isdigit_string(const char *str);
|
extern int isdigit_string(const char *str);
|
||||||
|
extern int isxdigit_string(const char *str);
|
||||||
|
|
||||||
extern int parse_switch(const char *arg, const char *errmesg, ...);
|
extern int parse_switch(const char *arg, const char *errmesg, ...);
|
||||||
|
|
||||||
|
|
|
@ -183,6 +183,15 @@ int isdigit_string(const char *str)
|
||||||
return p && p > str && !*p;
|
return p && p > str && !*p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int isxdigit_string(const char *str)
|
||||||
|
{
|
||||||
|
const char *p;
|
||||||
|
|
||||||
|
for (p = str; p && *p && isxdigit((unsigned char) *p); p++);
|
||||||
|
|
||||||
|
return p && p > str && !*p;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* parse_switch(argv[i], "on", "off", "yes", "no", NULL);
|
* parse_switch(argv[i], "on", "off", "yes", "no", NULL);
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -101,6 +101,7 @@ extern int mnt_get_filesystems(char ***filesystems, const char *pattern);
|
||||||
extern void mnt_free_filesystems(char **filesystems);
|
extern void mnt_free_filesystems(char **filesystems);
|
||||||
|
|
||||||
extern char *mnt_get_kernel_cmdline_option(const char *name);
|
extern char *mnt_get_kernel_cmdline_option(const char *name);
|
||||||
|
extern int mnt_guess_system_root(dev_t devno, struct libmnt_cache *cache, char **path);
|
||||||
extern int mnt_stat_mountpoint(const char *target, struct stat *st);
|
extern int mnt_stat_mountpoint(const char *target, struct stat *st);
|
||||||
|
|
||||||
/* tab.c */
|
/* tab.c */
|
||||||
|
|
|
@ -580,19 +580,16 @@ static int kernel_fs_postparse(struct libmnt_table *tb,
|
||||||
* Convert obscure /dev/root to something more usable
|
* Convert obscure /dev/root to something more usable
|
||||||
*/
|
*/
|
||||||
if (src && strcmp(src, "/dev/root") == 0) {
|
if (src && strcmp(src, "/dev/root") == 0) {
|
||||||
char *spec = mnt_get_kernel_cmdline_option("root=");
|
|
||||||
char *real = NULL;
|
char *real = NULL;
|
||||||
|
|
||||||
DBG(TAB, ul_debugobj(tb, "root FS: %s", spec));
|
rc = mnt_guess_system_root(fs->devno, tb->cache, &real);
|
||||||
if (spec)
|
if (rc < 0)
|
||||||
real = mnt_resolve_spec(spec, tb->cache);
|
return rc;
|
||||||
if (real) {
|
|
||||||
|
if (rc == 0 && real) {
|
||||||
DBG(TAB, ul_debugobj(tb, "canonical root FS: %s", real));
|
DBG(TAB, ul_debugobj(tb, "canonical root FS: %s", real));
|
||||||
rc = mnt_fs_set_source(fs, real);
|
rc = __mnt_fs_set_source_ptr(fs, real);
|
||||||
if (!tb->cache)
|
|
||||||
free(real);
|
|
||||||
}
|
}
|
||||||
free(spec);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#include "match.h"
|
#include "match.h"
|
||||||
#include "fileutils.h"
|
#include "fileutils.h"
|
||||||
#include "statfs_magic.h"
|
#include "statfs_magic.h"
|
||||||
|
#include "sysfs.h"
|
||||||
|
|
||||||
int append_string(char **a, const char *b)
|
int append_string(char **a, const char *b)
|
||||||
{
|
{
|
||||||
|
@ -1095,6 +1096,92 @@ char *mnt_get_kernel_cmdline_option(const char *name)
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Converts @devno to the real device name if devno major number is greater
|
||||||
|
* than zero, otherwise use root= kernel cmdline option to get device name.
|
||||||
|
*
|
||||||
|
* The function uses /sys to convert devno to device name.
|
||||||
|
*
|
||||||
|
* Returns: 0 = success, 1 = not found, <0 = error
|
||||||
|
*/
|
||||||
|
int mnt_guess_system_root(dev_t devno, struct libmnt_cache *cache, char **path)
|
||||||
|
{
|
||||||
|
char buf[PATH_MAX];
|
||||||
|
char *dev = NULL, *spec;
|
||||||
|
unsigned int x, y;
|
||||||
|
int allocated = 0;
|
||||||
|
|
||||||
|
assert(path);
|
||||||
|
|
||||||
|
DBG(UTILS, ul_debug("guessing system root [devno %u:%u]", major(devno), minor(devno)));
|
||||||
|
|
||||||
|
/* The pseudo-fs, net-fs or btrfs devno is useless, otherwise it
|
||||||
|
* usually matches with the source device, let's try to use it.
|
||||||
|
*/
|
||||||
|
if (major(devno) > 0) {
|
||||||
|
dev = sysfs_devno_to_devpath(devno, buf, sizeof(buf));
|
||||||
|
if (dev) {
|
||||||
|
DBG(UTILS, ul_debug(" devno converted to %s", dev));
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Let's try to use root= kernel command line option
|
||||||
|
*/
|
||||||
|
spec = mnt_get_kernel_cmdline_option("root=");
|
||||||
|
if (!spec)
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
/* maj:min notation */
|
||||||
|
if (sscanf(spec, "%u:%u", &x, &y) == 2) {
|
||||||
|
dev = sysfs_devno_to_devpath(makedev(x, y), buf, sizeof(buf));
|
||||||
|
if (dev) {
|
||||||
|
DBG(UTILS, ul_debug(" root=%s converted to %s", spec, dev));
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* hexhex notation */
|
||||||
|
} else if (isxdigit_string(spec)) {
|
||||||
|
char *end = NULL;
|
||||||
|
uint32_t n;
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
|
n = strtoul(spec, &end, 16);
|
||||||
|
|
||||||
|
if (errno || spec == end || (end && *end))
|
||||||
|
DBG(UTILS, ul_debug(" failed to parse root='%s'", spec));
|
||||||
|
else {
|
||||||
|
/* kernel new_decode_dev() */
|
||||||
|
x = (n & 0xfff00) >> 8;
|
||||||
|
y = (n & 0xff) | ((n >> 12) & 0xfff00);
|
||||||
|
dev = sysfs_devno_to_devpath(makedev(x, y), buf, sizeof(buf));
|
||||||
|
if (dev) {
|
||||||
|
DBG(UTILS, ul_debug(" root=%s converted to %s", spec, dev));
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* devname or PARTUUID= etc. */
|
||||||
|
} else {
|
||||||
|
DBG(UTILS, ul_debug(" converting root='%s'", spec));
|
||||||
|
|
||||||
|
dev = mnt_resolve_spec(spec, cache);
|
||||||
|
if (dev && !cache)
|
||||||
|
allocated = 1;
|
||||||
|
}
|
||||||
|
free(spec);
|
||||||
|
done:
|
||||||
|
if (dev) {
|
||||||
|
*path = allocated ? dev : strdup(dev);
|
||||||
|
if (!path)
|
||||||
|
return -ENOMEM;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifdef TEST_PROGRAM
|
#ifdef TEST_PROGRAM
|
||||||
static int test_match_fstype(struct libmnt_test *ts, int argc, char *argv[])
|
static int test_match_fstype(struct libmnt_test *ts, int argc, char *argv[])
|
||||||
{
|
{
|
||||||
|
@ -1207,6 +1294,33 @@ static int test_kernel_cmdline(struct libmnt_test *ts, int argc, char *argv[])
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int test_guess_root(struct libmnt_test *ts, int argc, char *argv[])
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
char *real;
|
||||||
|
dev_t devno = 0;
|
||||||
|
|
||||||
|
if (argc) {
|
||||||
|
unsigned int x, y;
|
||||||
|
|
||||||
|
if (sscanf(argv[1], "%u:%u", &x, &y) != 2)
|
||||||
|
return -EINVAL;
|
||||||
|
devno = makedev(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = mnt_guess_system_root(devno, NULL, &real);
|
||||||
|
if (rc < 0)
|
||||||
|
return rc;
|
||||||
|
if (rc == 1)
|
||||||
|
fputs("not found\n", stdout);
|
||||||
|
else {
|
||||||
|
printf("%s\n", real);
|
||||||
|
free(real);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int test_mkdir(struct libmnt_test *ts, int argc, char *argv[])
|
static int test_mkdir(struct libmnt_test *ts, int argc, char *argv[])
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
|
@ -1247,6 +1361,7 @@ int main(int argc, char *argv[])
|
||||||
{ "--mountpoint", test_mountpoint, "<path>" },
|
{ "--mountpoint", test_mountpoint, "<path>" },
|
||||||
{ "--cd-parent", test_chdir, "<path>" },
|
{ "--cd-parent", test_chdir, "<path>" },
|
||||||
{ "--kernel-cmdline",test_kernel_cmdline, "<option> | <option>=" },
|
{ "--kernel-cmdline",test_kernel_cmdline, "<option> | <option>=" },
|
||||||
|
{ "--guess-root", test_guess_root, "[<maj:min>]" },
|
||||||
{ "--mkdir", test_mkdir, "<path>" },
|
{ "--mkdir", test_mkdir, "<path>" },
|
||||||
{ "--statfs-type", test_statfs_type, "<path>" },
|
{ "--statfs-type", test_statfs_type, "<path>" },
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue