]> git.kernelconcepts.de Git - karo-tx-uboot.git/blobdiff - common/env_flags.c
Merge remote-tracking branch 'u-boot/master' into test
[karo-tx-uboot.git] / common / env_flags.c
index ed0857cf9e7a42cec3364f5d9a425b562a188a2d..985f92e50e91dda81ad36fec5447ed4cffe30907 100644 (file)
@@ -2,23 +2,7 @@
  * (C) Copyright 2012
  * Joe Hershberger, National Instruments, joe.hershberger@ni.com
  *
- * See file CREDITS for list of people who contributed to this
- * project.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
+ * SPDX-License-Identifier:    GPL-2.0+
  */
 
 #include <linux/string.h>
 #endif
 
 static const char env_flags_vartype_rep[] = "sdxb" ENV_FLAGS_NET_VARTYPE_REPS;
+static const char env_flags_varaccess_rep[] = "aroc";
+static const int env_flags_varaccess_mask[] = {
+       0,
+       ENV_FLAGS_VARACCESS_PREVENT_DELETE |
+               ENV_FLAGS_VARACCESS_PREVENT_CREATE |
+               ENV_FLAGS_VARACCESS_PREVENT_OVERWR,
+       ENV_FLAGS_VARACCESS_PREVENT_DELETE |
+               ENV_FLAGS_VARACCESS_PREVENT_OVERWR,
+       ENV_FLAGS_VARACCESS_PREVENT_DELETE |
+               ENV_FLAGS_VARACCESS_PREVENT_NONDEF_OVERWR};
+
+#ifdef CONFIG_CMD_ENV_FLAGS
+static const char * const env_flags_vartype_names[] = {
+       "string",
+       "decimal",
+       "hexadecimal",
+       "boolean",
+#ifdef CONFIG_CMD_NET
+       "IP address",
+       "MAC address",
+#endif
+};
+static const char * const env_flags_varaccess_names[] = {
+       "any",
+       "read-only",
+       "write-once",
+       "change-default",
+};
+
+/*
+ * Print the whole list of available type flags.
+ */
+void env_flags_print_vartypes(void)
+{
+       enum env_flags_vartype curtype = (enum env_flags_vartype)0;
+
+       while (curtype != env_flags_vartype_end) {
+               printf("\t%c   -\t%s\n", env_flags_vartype_rep[curtype],
+                       env_flags_vartype_names[curtype]);
+               curtype++;
+       }
+}
+
+/*
+ * Print the whole list of available access flags.
+ */
+void env_flags_print_varaccess(void)
+{
+       enum env_flags_varaccess curaccess = (enum env_flags_varaccess)0;
+
+       while (curaccess != env_flags_varaccess_end) {
+               printf("\t%c   -\t%s\n", env_flags_varaccess_rep[curaccess],
+                       env_flags_varaccess_names[curaccess]);
+               curaccess++;
+       }
+}
+
+/*
+ * Return the name of the type.
+ */
+const char *env_flags_get_vartype_name(enum env_flags_vartype type)
+{
+       return env_flags_vartype_names[type];
+}
+
+/*
+ * Return the name of the access.
+ */
+const char *env_flags_get_varaccess_name(enum env_flags_varaccess access)
+{
+       return env_flags_varaccess_names[access];
+}
+#endif /* CONFIG_CMD_ENV_FLAGS */
 
 /*
  * Parse the flags string from a .flags attribute list into the vartype enum.
@@ -66,6 +123,46 @@ enum env_flags_vartype env_flags_parse_vartype(const char *flags)
        return env_flags_vartype_string;
 }
 
+/*
+ * Parse the flags string from a .flags attribute list into the varaccess enum.
+ */
+enum env_flags_varaccess env_flags_parse_varaccess(const char *flags)
+{
+       char *access;
+
+       if (strlen(flags) <= ENV_FLAGS_VARACCESS_LOC)
+               return env_flags_varaccess_any;
+
+       access = strchr(env_flags_varaccess_rep,
+               flags[ENV_FLAGS_VARACCESS_LOC]);
+
+       if (access != NULL)
+               return (enum env_flags_varaccess)
+                       (access - &env_flags_varaccess_rep[0]);
+
+       printf("## Warning: Unknown environment variable access method '%c'\n",
+               flags[ENV_FLAGS_VARACCESS_LOC]);
+       return env_flags_varaccess_any;
+}
+
+/*
+ * Parse the binary flags from a hash table entry into the varaccess enum.
+ */
+enum env_flags_varaccess env_flags_parse_varaccess_from_binflags(int binflags)
+{
+       int i;
+
+       for (i = 0; i < sizeof(env_flags_varaccess_mask); i++)
+               if (env_flags_varaccess_mask[i] ==
+                   (binflags & ENV_FLAGS_VARACCESS_BIN_MASK))
+                       return (enum env_flags_varaccess)i;
+
+       printf("Warning: Non-standard access flags. (0x%x)\n",
+               binflags & ENV_FLAGS_VARACCESS_BIN_MASK);
+
+       return env_flags_varaccess_any;
+}
+
 static inline int is_hex_prefix(const char *value)
 {
        return value[0] == '0' && (value[1] == 'x' || value[1] == 'X');
@@ -207,6 +304,23 @@ enum env_flags_vartype env_flags_get_type(const char *name)
        return env_flags_parse_vartype(flags);
 }
 
+/*
+ * Look up the access of a variable directly from the .flags var.
+ */
+enum env_flags_varaccess env_flags_get_varaccess(const char *name)
+{
+       const char *flags_list = getenv(ENV_FLAGS_VAR);
+       char flags[ENV_FLAGS_ATTR_MAX_LEN + 1];
+
+       if (env_flags_lookup(flags_list, name, flags))
+               return env_flags_varaccess_any;
+
+       if (strlen(flags) <= ENV_FLAGS_VARACCESS_LOC)
+               return env_flags_varaccess_any;
+
+       return env_flags_parse_varaccess(flags);
+}
+
 /*
  * Validate that the proposed new value for "name" is valid according to the
  * defined flags for that variable, if any.
@@ -227,6 +341,21 @@ int env_flags_validate_type(const char *name, const char *value)
        return 0;
 }
 
+/*
+ * Validate that the proposed access to variable "name" is valid according to
+ * the defined flags for that variable, if any.
+ */
+int env_flags_validate_varaccess(const char *name, int check_mask)
+{
+       enum env_flags_varaccess access;
+       int access_mask;
+
+       access = env_flags_get_varaccess(name);
+       access_mask = env_flags_varaccess_mask[access];
+
+       return (check_mask & access_mask) != 0;
+}
+
 /*
  * Validate the parameters to "env set" directly
  */
@@ -258,9 +387,17 @@ int env_flags_validate_env_set_params(int argc, char * const argv[])
  */
 static int env_parse_flags_to_bin(const char *flags)
 {
-       return env_flags_parse_vartype(flags) & ENV_FLAGS_VARTYPE_BIN_MASK;
+       int binflags;
+
+       binflags = env_flags_parse_vartype(flags) & ENV_FLAGS_VARTYPE_BIN_MASK;
+       binflags |= env_flags_varaccess_mask[env_flags_parse_varaccess(flags)];
+
+       return binflags;
 }
 
+static int first_call = 1;
+static const char *flags_list;
+
 /*
  * Look for possible flags for a newly added variable
  * This is called specifically when the variable did not exist in the hash
@@ -269,10 +406,13 @@ static int env_parse_flags_to_bin(const char *flags)
 void env_flags_init(ENTRY *var_entry)
 {
        const char *var_name = var_entry->key;
-       const char *flags_list = getenv(ENV_FLAGS_VAR);
        char flags[ENV_FLAGS_ATTR_MAX_LEN + 1] = "";
        int ret = 1;
 
+       if (first_call) {
+               flags_list = getenv(ENV_FLAGS_VAR);
+               first_call = 0;
+       }
        /* look in the ".flags" and static for a reference to this variable */
        ret = env_flags_lookup(flags_list, var_name, flags);
 
@@ -343,38 +483,16 @@ int env_flags_validate(const ENTRY *item, const char *newval, enum env_op op,
        int flag)
 {
        const char *name;
-#if !defined(CONFIG_ENV_OVERWRITE) && defined(CONFIG_OVERWRITE_ETHADDR_ONCE) \
-&& defined(CONFIG_ETHADDR)
        const char *oldval = NULL;
 
        if (op != env_op_create)
                oldval = item->data;
-#endif
 
        name = item->key;
 
        /* Default value for NULL to protect string-manipulating functions */
        newval = newval ? : "";
 
-#ifndef CONFIG_ENV_OVERWRITE
-       /*
-        * Some variables like "ethaddr" and "serial#" can be set only once and
-        * cannot be deleted, unless CONFIG_ENV_OVERWRITE is defined.
-        */
-       if (op != env_op_create &&              /* variable exists */
-               (flag & H_FORCE) == 0) {        /* and we are not forced */
-               if (strcmp(name, "serial#") == 0 ||
-                   (strcmp(name, "ethaddr") == 0
-#if defined(CONFIG_OVERWRITE_ETHADDR_ONCE) && defined(CONFIG_ETHADDR)
-                    && strcmp(oldval, __stringify(CONFIG_ETHADDR)) != 0
-#endif /* CONFIG_OVERWRITE_ETHADDR_ONCE && CONFIG_ETHADDR */
-                       )) {
-                       printf("Can't overwrite \"%s\"\n", name);
-                       return 1;
-               }
-       }
-#endif
-
        /* validate the value to match the variable type */
        if (op != env_op_delete) {
                enum env_flags_vartype type = (enum env_flags_vartype)
@@ -388,6 +506,44 @@ int env_flags_validate(const ENTRY *item, const char *newval, enum env_op op,
                }
        }
 
+       /* check for access permission */
+#ifndef CONFIG_ENV_ACCESS_IGNORE_FORCE
+       if (flag & H_FORCE)
+               return 0;
+#endif
+       switch (op) {
+       case env_op_delete:
+               if (item->flags & ENV_FLAGS_VARACCESS_PREVENT_DELETE) {
+                       printf("## Error: Can't delete \"%s\"\n", name);
+                       return 1;
+               }
+               break;
+       case env_op_overwrite:
+               if (item->flags & ENV_FLAGS_VARACCESS_PREVENT_OVERWR) {
+                       printf("## Error: Can't overwrite \"%s\"\n", name);
+                       return 1;
+               } else if (item->flags &
+                   ENV_FLAGS_VARACCESS_PREVENT_NONDEF_OVERWR) {
+                       const char *defval = getenv_default(name);
+
+                       if (defval == NULL)
+                               defval = "";
+                       printf("oldval: %s  defval: %s\n", oldval, defval);
+                       if (strcmp(oldval, defval) != 0) {
+                               printf("## Error: Can't overwrite \"%s\"\n",
+                                       name);
+                               return 1;
+                       }
+               }
+               break;
+       case env_op_create:
+               if (item->flags & ENV_FLAGS_VARACCESS_PREVENT_CREATE) {
+                       printf("## Error: Can't create \"%s\"\n", name);
+                       return 1;
+               }
+               break;
+       }
+
        return 0;
 }