today we use <varname>-<guid as %pUl>

such as Boot0000-8be4df61-93ca-11d2-aa0d-00e098032b8c

now we will use a different approach where will represent first the vendor
as a directory and then inside the associates variable.

But also create symlink on the vendor with readable name.

so it will look like this:

barebox@barebox EFI payload:/ ls -l /efivars/
drwxrwxrwx             36 04b37fe8-f6ae-480b-bdd5-37d98c5e89aa
drwxrwxrwx             36 4a67b082-0a4c-41cf-b6c7-440b29bb8c4f
drwxrwxrwx             36 4c19049f-4137-4dd3-9c10-8b97a83ffdfa
drwxrwxrwx             36 5b446ed1-e30b-4faa-871a-3654eca36080
drwxrwxrwx             36 5b91f69c-8b88-4a2b-9269-5f1d802b5175
drwxrwxrwx             36 8be4df61-93ca-11d2-aa0d-00e098032b8c
lrwxrwxrwx              3 Efi -> 8be4df61-93ca-11d2-aa0d-00e098032b8c
lrwxrwxrwx              7 barebox -> 5b91f69c-8b88-4a2b-9269-5f1d802b5175
drwxrwxrwx             36 eb704011-1402-11d3-8e77-00a0c969723b
lrwxrwxrwx              7 systemd -> 4a67b082-0a4c-41cf-b6c7-440b29bb8c4f
barebox@barebox EFI payload:/ ls -l /efivars/Efi/
-rw-rw-rw-             62 Boot0000
-rw-rw-rw-             80 Boot0001
-rw-rw-rw-             84 Boot0002
-rw-rw-rw-            106 Boot0003
-rw-rw-rw-            108 Boot0004
-rw-rw-rw-            141 Boot0005
-rw-rw-rw-             88 Boot0006
-rw-rw-rw-              2 BootCurrent
-rw-rw-rw-              4 BootOptionSupport
-rw-rw-rw-             14 BootOrder
-rw-rw-rw-            107 ConIn
-rw-rw-rw-           1567 ConInDev
-rw-rw-rw-            103 ConOut
-rw-rw-rw-           1855 ConOutDev
-rw-rw-rw-             73 ErrOut
-rw-rw-rw-           1563 ErrOutDev
-rw-rw-rw-             14 Key0000
-rw-rw-rw-             14 Key0001
-rw-rw-rw-              4 Lang
-rw-rw-rw-             13 LangCodes
-rw-rw-rw-              8 OsIndicationsSupported
-rw-rw-rw-              3 PlatformLang
-rw-rw-rw-             18 PlatformLangCodes
-rw-rw-rw-            108 PlatformRecovery0000
-rw-rw-rw-              2 Timeout
barebox@barebox EFI payload:/ ls -l /efivars/barebox/
barebox@barebox EFI payload:/ ls -l /efivars/systemd/
-rw-rw-rw-             14 LoaderTimeInitUSec

Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <[email protected]>
---
 common/efi-guid.c |  17 ++-
 common/efi/efi.c  |   2 +-
 fs/efivarfs.c     | 379 ++++++++++++++++++++++++++++++++++++++++++------------
 include/efi.h     |   1 +
 4 files changed, 312 insertions(+), 87 deletions(-)

diff --git a/common/efi-guid.c b/common/efi-guid.c
index 71aa21ddd..6908012df 100644
--- a/common/efi-guid.c
+++ b/common/efi-guid.c
@@ -14,11 +14,21 @@ efi_guid_t efi_systemd_vendor_guid = 
EFI_SYSTEMD_VENDOR_GUID;
 
 #define EFI_GUID_STRING(guid, short, long) do {        \
        if (!efi_guidcmp(guid, *g))             \
-               return long;                    \
+               return is_long ? long : short;                  \
        } while(0)
 
+
 const char *efi_guid_string(efi_guid_t *g)
 {
+       const char *name;
+
+       name = efi_guid_string_type(g, 1);
+
+       return name ? name : "Unknown";
+}
+
+const char *efi_guid_string_type(efi_guid_t *g, int is_long)
+{
        EFI_GUID_STRING(EFI_NULL_GUID, "NULL", "NULL GUID");
        EFI_GUID_STRING(EFI_MPS_TABLE_GUID, "MPS Table", "MPS Table GUID in EFI 
System Table");
        EFI_GUID_STRING(EFI_ACPI_TABLE_GUID, "ACPI Table", "ACPI 1.0 Table GUID 
in EFI System Table");
@@ -88,5 +98,8 @@ const char *efi_guid_string(efi_guid_t *g)
        EFI_GUID_STRING(EFI_ISCSIDXE_INF_GUID, "IScsiDxe.inf", "EFI 
IScsiDxe.inf File GUID");
        EFI_GUID_STRING(EFI_VLANCONFIGDXE_INF_GUID, "VlanConfigDxe.inf", "EFI 
VlanConfigDxe.inf File GUID");
 
-       return "unknown";
+       EFI_GUID_STRING(EFI_BAREBOX_VENDOR_GUID, "barebox", "Barebox 
Bootloader");
+       EFI_GUID_STRING(EFI_SYSTEMD_VENDOR_GUID, "systemd", "Linux systemd");
+
+       return NULL;
 }
diff --git a/common/efi/efi.c b/common/efi/efi.c
index 05c58250f..b4a5bb88e 100644
--- a/common/efi/efi.c
+++ b/common/efi/efi.c
@@ -299,7 +299,7 @@ static int efi_init(void)
 
        defaultenv_append_directory(env_efi);
 
-       env = xasprintf("/efivars/barebox-env-%pUl", &efi_barebox_vendor_guid);
+       env = xasprintf("/efivars/%pUl/barebox-env", &efi_barebox_vendor_guid);
        default_environment_path_set(env);
 
        return 0;
diff --git a/fs/efivarfs.c b/fs/efivarfs.c
index bf7351e6d..90aa3cfcf 100644
--- a/fs/efivarfs.c
+++ b/fs/efivarfs.c
@@ -27,6 +27,7 @@
 #include <linux/stat.h>
 #include <xfuncs.h>
 #include <fcntl.h>
+#include <libgen.h>
 #include <efi.h>
 #include <wchar.h>
 #include <linux/err.h>
@@ -35,21 +36,99 @@
 #include <efi/efi-device.h>
 
 struct efivarfs_inode {
+       int is_dir;
+       int is_symlink;
        s16 *name;
        efi_guid_t vendor;
        char *full_name; /* name including vendor namespacing */
+       struct efivarfs_inode *parent;
        struct list_head node;
-};
-
-struct efivarfs_dir {
-       struct list_head *current;
-       DIR dir;
+       struct list_head childs;
 };
 
 struct efivarfs_priv {
        struct list_head inodes;
 };
 
+static struct efivarfs_inode *efivarfs_get_by_name(
+       struct list_head *inodes, const char *full_name)
+{
+       struct efivarfs_inode *inode, *tmp;
+
+       list_for_each_entry_safe(inode, tmp, inodes, node) {
+               if (!strcmp(inode->full_name, full_name))
+                       return inode;
+       }
+
+       return NULL;
+}
+
+static struct efivarfs_inode *efivarfs_get_by_vendor(
+       struct efivarfs_priv *priv, efi_guid_t *guid)
+{
+       struct efivarfs_inode *inode, *tmp;
+
+       list_for_each_entry_safe(inode, tmp, &priv->inodes, node) {
+               if (!efi_guidcmp(inode->vendor, *guid))
+                       return inode;
+       }
+
+       return NULL;
+}
+
+static struct efivarfs_inode *efivarfs_add_vendor(
+       struct efivarfs_priv *priv, efi_guid_t *guid)
+{
+       struct efivarfs_inode *vendor;
+       struct efivarfs_inode *symlink;
+       const char *name;
+
+       vendor = efivarfs_get_by_vendor(priv, guid);
+
+       if (vendor)
+               return vendor;
+
+       vendor = xzalloc(sizeof(*vendor));
+       vendor->is_dir = 1;
+       vendor->full_name = basprintf("%pUl", guid);
+       vendor->vendor = *guid;
+
+       list_add_tail(&vendor->node, &priv->inodes);
+       INIT_LIST_HEAD(&vendor->childs);
+
+       name = efi_guid_string_type(guid, 0);
+       if (!name)
+               goto out;
+
+       /* add symlink if we can resolv it */
+       symlink = xzalloc(sizeof(*symlink));
+       symlink->is_symlink = 1;
+       symlink->full_name = xstrdup(name);
+       symlink->vendor = *guid;
+       symlink->parent = vendor;
+       list_add_tail(&symlink->node, &priv->inodes);
+
+out:
+       return vendor;
+}
+
+static struct efivarfs_inode *efivarfs_add_var(
+       struct efivarfs_inode *v_inode, s16 *name)
+{      
+       struct efivarfs_inode *inode;
+
+       inode = xzalloc(sizeof(*inode));
+       inode->name = xstrdup_wchar(name);
+
+       inode->vendor = v_inode->vendor;
+
+       inode->full_name = xstrdup_wchar_to_char(inode->name);
+
+       list_add_tail(&inode->node, &v_inode->childs);
+
+       return inode;
+}
+
 static int char_to_nibble(char c)
 {
        int ret = tolower(c);
@@ -93,47 +172,74 @@ int efi_guid_parse(const char *str, efi_guid_t *guid)
        return 0;
 }
 
-static int efivarfs_parse_filename(const char *filename, efi_guid_t *vendor, 
s16 **name)
+static struct efivarfs_inode *efivarfs_parse_path(struct efivarfs_priv *priv,
+               const char *filename, s16 **name, char **full_name)
 {
-       int len, ret;
-       const char *guidstr;
-       s16 *varname;
-       int i;
+       char *dir, *file;
+       char *tmp = xstrdup(filename);
+       char *tmp2 = xstrdup(filename);
+       const char *vendor_str;
+       s16 *varname = NULL;
+       int len;
+       void *ret = ERR_PTR(-EINVAL);
+       struct efivarfs_inode *inode;
+
+       dir = dirname(tmp);
+       file = basename(tmp2);
 
-       if (*filename == '/')
+       if (filename[0] == '/')
                filename++;
 
-       len = strlen(filename);
+       if (dir[0] == '/')
+               dir++;
 
-       if (len < sizeof("-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"))
-               return -EINVAL;
+       if (!strlen(dir)) {
+               vendor_str = filename;
+               *name = NULL;
+               *full_name = NULL;
+       } else {
+               int i;
 
-       guidstr = filename + len - 
sizeof("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx");
-       if (*guidstr != '-')
-               return -EINVAL;
+               vendor_str = dir;
+               if (name) {
+                       len = strlen(file);
+
+                       varname = xzalloc((len + 1) * sizeof(s16));
+
+                       for (i = 0; i < len; i++)
+                               varname[i] = file[i];
 
-       guidstr++;
+                       *name = varname;
+               }
 
-       ret = efi_guid_parse(guidstr, vendor);
+               if (full_name)
+                       *full_name = xstrdup(file);
+       }
 
-       varname = xzalloc((guidstr - filename) * sizeof(s16));
+       inode = efivarfs_get_by_name(&priv->inodes, vendor_str);
+       if (!inode)
+               goto err;
 
-       for (i = 0; i < guidstr - filename - 1; i++)
-               varname[i] = filename[i];
+       ret = inode;
+       goto out;
 
-       *name = varname;
+err:
+       free(varname);
+       *name = NULL;
+out:
+       free(tmp);
+       free(tmp2);
 
-       return 0;
+       return ret;
 }
 
 static int efivars_create(struct device_d *dev, const char *pathname, mode_t 
mode)
 {
        struct efivarfs_priv *priv = dev->priv;
        struct efivarfs_inode *inode;
-       efi_guid_t vendor;
+       struct efivarfs_inode *vendor;
        efi_status_t efiret;
        u8 dummydata;
-       char *name8;
        s16 *name;
        int ret;
 
@@ -141,58 +247,73 @@ static int efivars_create(struct device_d *dev, const 
char *pathname, mode_t mod
                pathname++;
 
        /* deny creating files with other vendor GUID than our own */
-       ret = efivarfs_parse_filename(pathname, &vendor, &name);
-       if (ret)
+       vendor = efivarfs_parse_path(priv, pathname, &name, NULL);
+       if (IS_ERR(vendor))
                return -ENOENT;
 
-       if (memcmp(&vendor, &EFI_BAREBOX_VENDOR_GUID, sizeof(efi_guid_t)))
-               return -EPERM;
-
-       inode = xzalloc(sizeof(*inode));
-       inode->name = name;
-       inode->vendor = vendor;
-
-
-       name8 = xstrdup_wchar_to_char(inode->name);
-       inode->full_name = basprintf("%s-%pUl", name8, &inode->vendor);
-       free(name8);
+       if (memcmp(&vendor->vendor, &EFI_BAREBOX_VENDOR_GUID, 
sizeof(efi_guid_t))) {
+               ret =  -EPERM;
+               goto out;
+       }
 
-       efiret = RT->set_variable(inode->name, &inode->vendor,
+       efiret = RT->set_variable(name, &vendor->vendor,
                                  EFI_VARIABLE_NON_VOLATILE |
                                  EFI_VARIABLE_BOOTSERVICE_ACCESS |
                                  EFI_VARIABLE_RUNTIME_ACCESS,
                                  1, &dummydata);
        if (EFI_ERROR(efiret)) {
-               free(inode);
-               return -efi_errno(efiret);
+               ret = -efi_errno(efiret);
+               goto out;
        }
 
-       list_add_tail(&inode->node, &priv->inodes);
+       inode = efivarfs_add_var(vendor, name);
+       ret = 0;
 
-       return 0;
+out:
+       free(name);
+
+       return ret;
 }
 
 static int efivars_unlink(struct device_d *dev, const char *pathname)
 {
        struct efivarfs_priv *priv = dev->priv;
-       struct efivarfs_inode *inode, *tmp;
+       struct efivarfs_inode *vendor, *inode;
        efi_status_t efiret;
+       s16 *name;
+       char *full_name;
+       int ret;
 
        if (pathname[0] == '/')
                pathname++;
 
-       list_for_each_entry_safe(inode, tmp, &priv->inodes, node) {
-               if (!strcmp(inode->full_name, pathname)) {
-                       efiret = RT->set_variable(inode->name, &inode->vendor,
-                                                 0, 0, NULL);
-                       if (EFI_ERROR(efiret))
-                               return -efi_errno(efiret);
-                       list_del(&inode->node);
-                       free(inode);
-               }
+       vendor = efivarfs_parse_path(priv, pathname, &name, &full_name);
+       if (IS_ERR(vendor)) {
+               ret = PTR_ERR(vendor);
+               goto out;
        }
 
-       return 0;
+       inode = efivarfs_get_by_name(&vendor->childs, full_name);
+       if (IS_ERR(inode)) {
+               ret = PTR_ERR(inode);
+               goto out;
+       }
+
+       efiret = RT->set_variable(inode->name, &inode->vendor,  0, 0, NULL);
+       if (EFI_ERROR(efiret)) {
+               ret = -efi_errno(efiret);
+               goto out;
+       }
+
+       list_del(&inode->node);
+       free(inode);
+       ret = 0;
+
+out:
+       free(full_name);
+       free(name);
+
+       return ret;
 }
 
 struct efivars_file {
@@ -206,14 +327,20 @@ struct efivars_file {
 static int efivarfs_open(struct device_d *dev, FILE *f, const char *filename)
 {
        struct efivars_file *efile;
+       struct efivarfs_priv *priv = dev->priv;
+       struct efivarfs_inode *vendor;
        efi_status_t efiret;
        int ret;
 
        efile = xzalloc(sizeof(*efile));
 
-       ret = efivarfs_parse_filename(filename, &efile->vendor, &efile->name);
-       if (ret)
-               return -ENOENT;
+       vendor = efivarfs_parse_path(priv, filename, &efile->name, NULL);
+       if (IS_ERR(vendor)) {
+               ret = PTR_ERR(vendor);
+               goto out;
+       }
+
+       efile->vendor = vendor->vendor;
 
        efiret = RT->get_variable(efile->name, &efile->vendor,
                                  NULL, &efile->size, NULL);
@@ -243,6 +370,7 @@ static int efivarfs_open(struct device_d *dev, FILE *f, 
const char *filename)
 
 out:
        free(efile->buf);
+       free(efile->name);
        free(efile);
 
        return ret;
@@ -253,6 +381,7 @@ static int efivarfs_close(struct device_d *dev, FILE *f)
        struct efivars_file *efile = f->priv;
 
        free(efile->buf);
+       free(efile->name);
        free(efile);
 
        return 0;
@@ -314,31 +443,75 @@ static loff_t efivarfs_lseek(struct device_d *dev, FILE 
*f, loff_t pos)
        return f->pos;
 }
 
+struct efivarfs_dir {
+       struct efivarfs_inode *vendor;
+       struct efivarfs_inode *var;
+       int empty;
+       DIR dir;
+};
+
 static DIR *efivarfs_opendir(struct device_d *dev, const char *pathname)
 {
        struct efivarfs_priv *priv = dev->priv;
        struct efivarfs_dir *edir;
+       DIR *dir;
 
        edir = xzalloc(sizeof(*edir));
-       edir->current = priv->inodes.next;
+       dir = &edir->dir;
+       dir->priv = edir;
+
+       if (pathname[0] == '/')
+               pathname++;
+
+       if (!strlen(pathname)) {
+               if (list_empty(&priv->inodes))
+                       return dir;
 
-       return &edir->dir;
+               edir->vendor = list_first_entry(&priv->inodes,
+                                       struct efivarfs_inode, node);
+       } else {
+               struct efivarfs_inode *inode;
+
+               inode = efivarfs_get_by_name(&priv->inodes, pathname);
+               edir->vendor = inode->is_symlink ? inode->parent : inode;
+               if (!edir->vendor)
+                       return dir;
+
+               if (list_empty(&edir->vendor->childs)) {
+                       edir->empty = 1;
+                       return dir;
+               }
+
+               edir->var = list_first_entry(&edir->vendor->childs,
+                                       struct efivarfs_inode, node);
+       }
+
+       return dir;
 }
 
 static struct dirent *efivarfs_readdir(struct device_d *dev, DIR *dir)
 {
        struct efivarfs_priv *priv = dev->priv;
        struct efivarfs_dir *edir = container_of(dir, struct efivarfs_dir, dir);
-       struct efivarfs_inode *inode;
+       struct efivarfs_inode *vendor = edir->vendor;
+       struct efivarfs_inode *var = edir->var;
 
-       if (edir->current == &priv->inodes)
+       if (!vendor)
                return NULL;
 
-       inode = list_entry(edir->current, struct efivarfs_inode, node);
+       if (!var) {
+               if (edir->empty || &vendor->node == &priv->inodes)
+                       return NULL;
 
-       strcpy(dir->d.d_name, inode->full_name);
+               strcpy(dir->d.d_name, vendor->full_name);
+               edir->vendor = list_entry(vendor->node.next, struct 
efivarfs_inode, node);
+       } else {
+               if (&var->node == &vendor->childs)
+                       return NULL;
 
-       edir->current = edir->current->next;
+               strcpy(dir->d.d_name, var->full_name);
+               edir->var = list_entry(var->node.next, struct efivarfs_inode, 
node);
+       }
 
        return &dir->d;
 }
@@ -354,26 +527,69 @@ static int efivarfs_closedir(struct device_d *dev, DIR 
*dir)
 
 static int efivarfs_stat(struct device_d *dev, const char *filename, struct 
stat *s)
 {
-       efi_guid_t vendor;
+       struct efivarfs_priv *priv = dev->priv;
+       struct efivarfs_inode *vendor;
        s16 *name;
        efi_status_t efiret;
        unsigned long size = 0;
-       int ret;
+       int ret = -EINVAL;
 
-       ret = efivarfs_parse_filename(filename, &vendor, &name);
-       if (ret)
-               return -ENOENT;
+       vendor = efivarfs_parse_path(priv, filename, &name, NULL);
+       if (IS_ERR(vendor))
+               return PTR_ERR(vendor);
+
+       if (filename[0] == '/')
+               filename++;
+
+       if (!name) {
+               s->st_size = strlen(filename);
+               if (vendor->is_dir)
+                       s->st_mode = S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO;
+               else
+                       s->st_mode = S_IFLNK | S_IRWXU | S_IRWXG | S_IRWXO;
+
+               ret = 0;
+
+               goto out;
+       }
 
-       efiret = RT->get_variable(name, &vendor, NULL, &size, NULL);
+       efiret = RT->get_variable(name, &vendor->vendor, NULL, &size, NULL);
 
        free(name);
 
-       if (EFI_ERROR(efiret) && efiret != EFI_BUFFER_TOO_SMALL)
-               return -efi_errno(efiret);
+       if (EFI_ERROR(efiret) && efiret != EFI_BUFFER_TOO_SMALL) {
+               ret = -efi_errno(efiret);
+               goto out;
+       }
 
        s->st_mode = 00666 | S_IFREG;
        s->st_size = size;
 
+       ret = 0;
+
+out:
+       return ret;
+}
+
+static int efivarfs_readlink(struct device_d *dev, const char *pathname,
+                       char *buf, size_t bufsiz)
+{
+       struct efivarfs_priv *priv = dev->priv;
+       struct efivarfs_inode *node;
+       int len;
+
+       if (pathname[0] == '/')
+               pathname++;
+
+       node = efivarfs_get_by_name(&priv->inodes, pathname);
+
+       if (!node || !node->parent)
+               return -ENOENT;
+
+       len = min(bufsiz, strlen(node->parent->full_name));
+
+       memcpy(buf, node->parent->full_name, len);
+
        return 0;
 }
 
@@ -382,7 +598,6 @@ static int efivarfs_probe(struct device_d *dev)
        efi_status_t efiret;
        efi_guid_t vendor;
        s16 name[1024];
-       char *name8;
        unsigned long size;
        struct efivarfs_priv *priv;
 
@@ -391,24 +606,19 @@ static int efivarfs_probe(struct device_d *dev)
        priv = xzalloc(sizeof(*priv));
        INIT_LIST_HEAD(&priv->inodes);
 
+       efivarfs_add_vendor(priv, &efi_barebox_vendor_guid);
+
        while (1) {
                struct efivarfs_inode *inode;
+               struct efivarfs_inode *v_inode;
 
                size = sizeof(name);
                efiret = RT->get_next_variable(&size, name, &vendor);
                if (EFI_ERROR(efiret))
                        break;
 
-               inode = xzalloc(sizeof(*inode));
-               inode->name = xstrdup_wchar(name);
-
-               inode->vendor = vendor;
-
-               name8 = xstrdup_wchar_to_char(inode->name);
-               inode->full_name = basprintf("%s-%pUl", name8, &vendor);
-               free(name8);
-
-               list_add_tail(&inode->node, &priv->inodes);
+               v_inode = efivarfs_add_vendor(priv, &vendor);
+               inode = efivarfs_add_var(v_inode, name);
        }
 
        dev->priv = priv;
@@ -442,6 +652,7 @@ static struct fs_driver_d efivarfs_driver = {
        .readdir   = efivarfs_readdir,
        .closedir  = efivarfs_closedir,
        .stat      = efivarfs_stat,
+       .readlink  = efivarfs_readlink,
        .drv = {
                .probe  = efivarfs_probe,
                .remove = efivarfs_remove,
diff --git a/include/efi.h b/include/efi.h
index e1fc134ee..afad26314 100644
--- a/include/efi.h
+++ b/include/efi.h
@@ -668,6 +668,7 @@ char *device_path_to_str(struct efi_device_path *dev_path);
 u8 device_path_to_type(struct efi_device_path *dev_path);
 char *device_path_to_partuuid(struct efi_device_path *dev_path);
 
+const char *efi_guid_string_type(efi_guid_t *g, int is_long);
 const char *efi_guid_string(efi_guid_t *g);
 
 #endif /* _LINUX_EFI_H */
-- 
2.11.0


_______________________________________________
barebox mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/barebox

Reply via email to