diff mbox

[U-Boot,v0,1/4] Groundwork for generalization of env interface

Message ID 1319647072-17504-2-git-send-email-gerlando.falauto@keymile.com
State Changes Requested
Headers show

Commit Message

Gerlando Falauto Oct. 26, 2011, 4:37 p.m. UTC
Signed-off-by: Gerlando Falauto <gerlando.falauto@keymile.com>
---
 common/cmd_nvedit.c   |  152 +++++++++++++++++++++++++++++++------------------
 common/env_common.c   |   15 ++++-
 include/environment.h |    7 ++
 include/search.h      |   13 ++++
 lib/hashtable.c       |   50 ++++++++++++++++
 5 files changed, 179 insertions(+), 58 deletions(-)

Comments

Wolfgang Denk Nov. 5, 2011, 4:09 p.m. UTC | #1
Dear Gerlando Falauto,

In message <1319647072-17504-2-git-send-email-gerlando.falauto@keymile.com> you wrote:
> Signed-off-by: Gerlando Falauto <gerlando.falauto@keymile.com>
> ---
>  common/cmd_nvedit.c   |  152 +++++++++++++++++++++++++++++++------------------
>  common/env_common.c   |   15 ++++-
>  include/environment.h |    7 ++
>  include/search.h      |   13 ++++
>  lib/hashtable.c       |   50 ++++++++++++++++
>  5 files changed, 179 insertions(+), 58 deletions(-)
...
> -int _do_env_set (int flag, int argc, char * const argv[])
> +int env_check_apply(const char *name, const char *oldval,
> +		    const char *newval, int flag)

Please use only TAB for indentation.  Please fix globally.


> -	if (ep) {		/* variable exists */
> +	if ((oldval != NULL) /* variable exists */
> +	 && ((flag & H_FORCE) == 0)) { /* and we are not forced */

Incorrect indentation.


> +/*
> + * Set a new environment variable,
> + * or replace or delete an existing one.
> +*/

Incorrect multiline comment style.

> +	/* Perform requested checks. Notice how since we are overwriting
> +	 * a single variable, we need to set H_NOCLEAR */

Incorrect multiline comment style.

>  void set_default_env(const char *s)
>  {
> +	/* By default, do not apply changes as they will eventually
> +	 * be applied by someone else */

Incorrect multiline comment style.

Please fix globally!

> +	if (himport_ex(&env_htab, (char *)default_environment,
> +		    sizeof(default_environment), '\0', 0,
> +		      0, NULL, apply_function) == 0) {

Incorrect / inconsistent indentation.  Please fix globally.


Best regards,

Wolfgang Denk
Wolfgang Denk Nov. 5, 2011, 4:34 p.m. UTC | #2
Dear Gerlando Falauto,

In message <1319647072-17504-2-git-send-email-gerlando.falauto@keymile.com> you wrote:
> Signed-off-by: Gerlando Falauto <gerlando.falauto@keymile.com>
> ---
>  common/cmd_nvedit.c   |  152 +++++++++++++++++++++++++++++++------------------
>  common/env_common.c   |   15 ++++-
>  include/environment.h |    7 ++
>  include/search.h      |   13 ++++
>  lib/hashtable.c       |   50 ++++++++++++++++
>  5 files changed, 179 insertions(+), 58 deletions(-)

This patch introduces new build warnings:

cmd_nvedit.c: In function 'env_check_apply':
cmd_nvedit.c:242:3: warning: passing argument 1 of 'serial_assign'
discards 'const' qualifier from pointer target type [enabled by
default]
/home/wd/git/u-boot/env-substitute/include/serial.h:95:12: note:
expected 'char *' but argument is of type 'const char *'

Please fix.

Best regards,

Wolfgang Denk
Gerlando Falauto Nov. 7, 2011, 9:06 p.m. UTC | #3
On 11/05/2011 05:09 PM, Wolfgang Denk wrote:

[NOTE: I removed the quoting from the hunks as it would not make any sense]

-int _do_env_set (int flag, int argc, char * const argv[])
+int env_check_apply(const char *name, const char *oldval,
+		    const char *newval, int flag)

> Please use only TAB for indentation.  Please fix globally.

 From fs/ubibfs/ubifs.h:

int ubifs_decompress(const void *buf, int len, void *out, int *out_len,
		     int compr_type);

Here there are 2 tabs + 5 spaces to align arguments from the first line 
with those on the second line. I did the same (except that in a patch 
hunk the plus sign before the first tab shifts it to the right).

Could you please provide some examples as to what would be the correct 
coding style for function declarations and/or function calls that spawn 
on multiple lines? I could not find anything on the topic.

As for:

-	if (ep) {		/* variable exists */
+	if ((oldval != NULL) /* variable exists */
+	 && ((flag & H_FORCE) == 0)) { /* and we are not forced */

Ditto. Here I was trying to align parentheses. Could you please provide 
an example? In my opinion, using only tabs would definitely make the two 
lines not aligned and make the code much harder to read.

As for:

+	if (himport_ex(&env_htab, (char *)default_environment,
+		    sizeof(default_environment), '\0', 0,
+		      0, NULL, apply_function) == 0) {

What should be the right indentation?

Perhaps for function calls you would want something like:

+	if (himport_ex(&env_htab, (char *)default_environment,
+		sizeof(default_environment), '\0', 0,
+		0, NULL, apply_function) == 0) {

As soon as I have these questions answered, I will apply all the other 
changes you requested, and submit a new patchset.
I would very much appreciate some feedback about the idea though.

Thank you,
Gerlando Falauto
Wolfgang Denk Nov. 7, 2011, 10:05 p.m. UTC | #4
Dear Gerlando Falauto,

In message <4EB84859.6000906@keymile.com> you wrote:
> 
> -int _do_env_set (int flag, int argc, char * const argv[])
> +int env_check_apply(const char *name, const char *oldval,
> +		    const char *newval, int flag)
> 
> > Please use only TAB for indentation.  Please fix globally.
> 
>  From fs/ubibfs/ubifs.h:

Never ever use examples from other code to argument your's was right -
the example you chose might be wrong as well.

> Could you please provide some examples as to what would be the correct 
> coding style for function declarations and/or function calls that spawn 
> on multiple lines? I could not find anything on the topic.

http://www.denx.de/wiki/U-Boot/CodingStyle:

	Use TAB characters for indentation and vertical alignment, not
	spaces 

> +	if (himport_ex(&env_htab, (char *)default_environment,
> +		    sizeof(default_environment), '\0', 0,
> +		      0, NULL, apply_function) == 0) {
> 
> What should be the right indentation?

In any case it makse no sense to have the 2nd and 3rd line indented
differently, right?

Best regards,

Wolfgang Denk
Scott Wood Nov. 7, 2011, 11:02 p.m. UTC | #5
On 11/07/2011 04:05 PM, Wolfgang Denk wrote:
> Dear Gerlando Falauto,
> 
> In message <4EB84859.6000906@keymile.com> you wrote:
>>
>> -int _do_env_set (int flag, int argc, char * const argv[])
>> +int env_check_apply(const char *name, const char *oldval,
>> +		    const char *newval, int flag)
>>
>>> Please use only TAB for indentation.  Please fix globally.
>>
>>  From fs/ubibfs/ubifs.h:
> 
> Never ever use examples from other code to argument your's was right -
> the example you chose might be wrong as well.
> 
>> Could you please provide some examples as to what would be the correct 
>> coding style for function declarations and/or function calls that spawn 
>> on multiple lines? I could not find anything on the topic.
> 
> http://www.denx.de/wiki/U-Boot/CodingStyle:
> 
> 	Use TAB characters for indentation and vertical alignment, not
> 	spaces 

It is impossible to align this nicely with tabs alone.  Such alignment
is not just an isolated example, but quite common in both the Linux
kernel and U-Boot.

Grep for a tab followed by a space...

>> +	if (himport_ex(&env_htab, (char *)default_environment,
>> +		    sizeof(default_environment), '\0', 0,
>> +		      0, NULL, apply_function) == 0) {
>>
>> What should be the right indentation?
> 
> In any case it makse no sense to have the 2nd and 3rd line indented
> differently, right?

They generally shouldn't be different from each other, but that doesn't
answer the question of what it should look like.

Documentation/CodingStyle calls for something like this:

	if (himport_ex(&env_htab, (char *)default_environment,
				sizeof(default_environment), '\0',
				0, 0, NULL, apply_function) == 0) {

...but judging by how common it is, many people find this nicer:

	if (himport_ex(&env_htab, (char *)default_environment,
		       sizeof(default_environment), '\0',
		       0, 0, NULL, apply_function) == 0) {

I vote for allowing it, if anyone's counting.

-Scott
Gerlando Falauto Nov. 7, 2011, 11:05 p.m. UTC | #6
On 11/07/2011 11:05 PM, Wolfgang Denk wrote:
> Dear Gerlando Falauto,
>
> In message<4EB84859.6000906@keymile.com>  you wrote:
>>
>> -int _do_env_set (int flag, int argc, char * const argv[])
>> +int env_check_apply(const char *name, const char *oldval,
>> +		    const char *newval, int flag)
>>
>>> Please use only TAB for indentation.  Please fix globally.
>>
>>    From fs/ubibfs/ubifs.h:
>
> Never ever use examples from other code to argument your's was right -
> the example you chose might be wrong as well.

The purpose was not to argument mine was right.

>> Could you please provide some examples as to what would be the correct
>> coding style for function declarations and/or function calls that spawn
>> on multiple lines? I could not find anything on the topic.
>
> http://www.denx.de/wiki/U-Boot/CodingStyle:
>
> 	Use TAB characters for indentation and vertical alignment, not
> 	spaces

That's exactly what you told me in your reply, and doesn't answer my 
question.
The only way I could think of to achieve vertical alignment in a complex 
if statement without recurring to spaces is by adding extra tabs between 
parentheses, with an enormous waste of space.
Your answer might as well be: "forget about alignment altogether, nobody 
wants that, just indent it somehow".

>> +	if (himport_ex(&env_htab, (char *)default_environment,
>> +		    sizeof(default_environment), '\0', 0,
>> +		      0, NULL, apply_function) == 0) {
>>
>> What should be the right indentation?
>
> In any case it makse no sense to have the 2nd and 3rd line indented
> differently, right?

That's absolutely right.
Once again, though, you did not help me understand what The Right Thing 
(tm) is. I also made a shy attempt, but you're not telling me whether 
it's good or not.
It's hard to follow some guidelines when they're not clearly stated.

Thank you,
Gerlando Falauto
Wolfgang Denk Nov. 7, 2011, 11:30 p.m. UTC | #7
Dear Gerlando Falauto,

In message <4EB86424.7000508@keymile.com> you wrote:
>
> > http://www.denx.de/wiki/U-Boot/CodingStyle:
> >
> > 	Use TAB characters for indentation and vertical alignment, not
> > 	spaces
> 
> That's exactly what you told me in your reply, and doesn't answer my 
> question.

Sory, but I don;t know how else to put it.

> The only way I could think of to achieve vertical alignment in a complex 
> if statement without recurring to spaces is by adding extra tabs between 
> parentheses, with an enormous waste of space.

In the first step you should try and avoid complex if statements.

> Your answer might as well be: "forget about alignment altogether, nobody 
> wants that, just indent it somehow".
> 
> >> +	if (himport_ex(&env_htab, (char *)default_environment,
> >> +		    sizeof(default_environment), '\0', 0,
> >> +		      0, NULL, apply_function) == 0) {
> >>
> >> What should be the right indentation?
> >
> > In any case it makse no sense to have the 2nd and 3rd line indented
> > differently, right?
> 
> That's absolutely right.
> Once again, though, you did not help me understand what The Right Thing 
> (tm) is. I also made a shy attempt, but you're not telling me whether 
> it's good or not.
> It's hard to follow some guidelines when they're not clearly stated.

Well, my suggestion is to align by TABs:

	if (himport_ex(&env_htab, (char *)default_environment,
			sizeof(default_environment), '\0', 0,
			0, NULL, apply_function) == 0) {
		...
	}

Yes, the 's' and the '0' don't start exactly below the '&'.  But who
says they should?  We also don't align the closing ')' below the
opeing '(' ...

And does above code look difficult to read? 

Best regards,

Wolfgang Denk
Gerlando Falauto Nov. 7, 2011, 11:32 p.m. UTC | #8
On 11/08/2011 12:02 AM, Scott Wood wrote:
> On 11/07/2011 04:05 PM, Wolfgang Denk wrote:
>> Dear Gerlando Falauto,
>>
>> In message<4EB84859.6000906@keymile.com>  you wrote:
>>>
>>> -int _do_env_set (int flag, int argc, char * const argv[])
>>> +int env_check_apply(const char *name, const char *oldval,
>>> +		    const char *newval, int flag)
>>>
>>>> Please use only TAB for indentation.  Please fix globally.
>>>
>>>    From fs/ubibfs/ubifs.h:
>>
>> Never ever use examples from other code to argument your's was right -
>> the example you chose might be wrong as well.
>>
>>> Could you please provide some examples as to what would be the correct
>>> coding style for function declarations and/or function calls that spawn
>>> on multiple lines? I could not find anything on the topic.
>>
>> http://www.denx.de/wiki/U-Boot/CodingStyle:
>>
>> 	Use TAB characters for indentation and vertical alignment, not
>> 	spaces
>
> It is impossible to align this nicely with tabs alone.  Such alignment
> is not just an isolated example, but quite common in both the Linux
> kernel and U-Boot.
>
> Grep for a tab followed by a space...
>
>>> +	if (himport_ex(&env_htab, (char *)default_environment,
>>> +		    sizeof(default_environment), '\0', 0,
>>> +		      0, NULL, apply_function) == 0) {
>>>
>>> What should be the right indentation?
>>
>> In any case it makse no sense to have the 2nd and 3rd line indented
>> differently, right?
>
> They generally shouldn't be different from each other, but that doesn't
> answer the question of what it should look like.

Thank you! :-)

> Documentation/CodingStyle calls for something like this:
>
> 	if (himport_ex(&env_htab, (char *)default_environment,
> 				sizeof(default_environment), '\0',
> 				0, 0, NULL, apply_function) == 0) {

I would have thought this would make more sense (offset by 1, not 9):

	if (himport_ex(&env_htab, (char *)default_environment,
			sizeof(default_environment), '\0',
			0, 0, NULL, apply_function) == 0) {

Or maybe even:

	if (himport_ex(&env_htab, (char *)default_environment,
		sizeof(default_environment), '\0',
		0, 0, NULL, apply_function) == 0) {

which would save a lot of screen real estate.
Now we can also argue that the argument list is really too big...

 > ...but judging by how common it is, many people find this nicer:
>
> 	if (himport_ex(&env_htab, (char *)default_environment,
> 		       sizeof(default_environment), '\0',
> 		       0, 0, NULL, apply_function) == 0) {

Actually I don't have that much of a preference in this case, it's just 
a matter of aesthetics, and I think it doesn't affect readabilty that 
much. As long as we agree on what is OK and what is not (or, rather, 
what is the preferred way).

What bothers me more is, for instance, the condition under which my 
smartphone will work correctly:

	if (((day_of_week() % 2 == 0) &&
	     (temperature() < 14.4 || temperature() > 15.3))
           || ((sky_color() == E_BLUE) && (sim_credit() % 100 != 27))
	  || (uptime() < 3600) ) {
		work = 1;
	} else if (  ((received_calls() > 1) &&
		      (zenith_angle() == 0))
                   || (call_is_important())
		  ) {
		work = 0;
	} else {
		udelay(rand());
		work = ((rand() % 2) == 1);
	}

Any ideas how to align that? Please don't answer: get a real phone. :-)

Thanks!
Gerlando Falauto
Scott Wood Nov. 7, 2011, 11:44 p.m. UTC | #9
On 11/07/2011 05:32 PM, Gerlando Falauto wrote:
> On 11/08/2011 12:02 AM, Scott Wood wrote:
>> Documentation/CodingStyle calls for something like this:
>>
>> 	if (himport_ex(&env_htab, (char *)default_environment,
>> 				sizeof(default_environment), '\0',
>> 				0, 0, NULL, apply_function) == 0) {
> 
> I would have thought this would make more sense (offset by 1, not 9):
> 
> 	if (himport_ex(&env_htab, (char *)default_environment,
> 			sizeof(default_environment), '\0',
> 			0, 0, NULL, apply_function) == 0) {

Documentation/CodingStyle simply says continuation lines "are always
substantially shorter than the parent and are placed substantially to
the right".

> Or maybe even:
> 
> 	if (himport_ex(&env_htab, (char *)default_environment,
> 		sizeof(default_environment), '\0',
> 		0, 0, NULL, apply_function) == 0) {
> 
> which would save a lot of screen real estate.

It would also make it harder to distinguish the continuation lines from
the if-body:

	if (himport_ex(...
		sizeof(...
		0, 0, ...) {
		body goes here, at the same column
		have to look for the brace to distinguish
	}

-Scott
Scott Wood Nov. 7, 2011, 11:58 p.m. UTC | #10
On 11/07/2011 05:32 PM, Gerlando Falauto wrote:
> What bothers me more is, for instance, the condition under which my 
> smartphone will work correctly:
> 
> 	if (((day_of_week() % 2 == 0) &&
> 	     (temperature() < 14.4 || temperature() > 15.3))
>            || ((sky_color() == E_BLUE) && (sim_credit() % 100 != 27))
> 	  || (uptime() < 3600) ) {
> 		work = 1;
> 	} else if (  ((received_calls() > 1) &&
> 		      (zenith_angle() == 0))
>                    || (call_is_important())
> 		  ) {
> 		work = 0;
> 	} else {
> 		udelay(rand());
> 		work = ((rand() % 2) == 1);
> 	}

I like aligning based on which level of nested parens the line break is
in (and removing unnecessary parens when precedence is obvious, to make
it easier to track the relevant ones):

	if ((day_of_week() % 2 == 0 &&
	     (temperature() < 14.4 || temperature() > 15.3)) ||
	    (sky_color() == E_BLUE && sim_credit() % 100 != 27) ||
	    uptime() < 3600) {
		work = 1;
	} else if ((received_calls() > 1 &&
		    zenith_angle() == 0) ||
		   call_is_important()) {
		work = 0;
	} else {
		udelay(rand());
		work = ((rand() % 2) == 1);
	}

-Scott
Gerlando Falauto Nov. 8, 2011, 10:20 a.m. UTC | #11
On 11/08/2011 12:58 AM, Scott Wood wrote:
 > I like aligning based on which level of nested parens the line break is
 > in (and removing unnecessary parens when precedence is obvious, to make
 > it easier to track the relevant ones):
 >
 > 	if ((day_of_week() % 2 == 0&&
 > 	(temperature()<  14.4 || temperature()>  15.3)) ||
 > 	    (sky_color() == E_BLUE&&  sim_credit() % 100 != 27) ||
 > 	    uptime()<  3600) {
 > 		work = 1;
 > 	} else if ((received_calls()>  1&&
 > 		zenith_angle() == 0) ||
 > 		   call_is_important()) {
 > 		work = 0;
 > 	} else {
 > 		udelay(rand());
 > 		work = ((rand() % 2) == 1);
 > 	}

I like that too.

Anyway... Are there are any guidelines for indenting comments on the 
right side of the code? Like:

	if ((day_of_week() % 2 == 0 &&		/* even days are OK */
	     (temperature() < 14.4 || temperature() > 15.3)) ||
						/*
						 * but only outside of a
						 * certain temp. range
						 */
	    (sky_color() == E_BLUE && sim_credit() % 100 != 27) ||
						/*
						 * or, it's a nice a day
						 * but balance does not
						 * have 27 cents as
						 * decimal part
						 */
	    uptime() < 3600) {			/* work 4 the 1st hr! */
		work = 1;
	} else if ((received_calls() > 1 &&
		    zenith_angle() == 0) ||
		   call_is_important()) {
		work = 0;
	} else {
		udelay(rand());
		work = ((rand() % 2) == 1);
	}

... becuase git-gui will interpret all tabs which are on the right of 
some non-whitespace text in a very weird way.
Is using tabs on the right of text forbidden/not recommended for some 
reason?

Thanks!
Gerlando Falauto
diff mbox

Patch

diff --git a/common/cmd_nvedit.c b/common/cmd_nvedit.c
index fa99c44..10b9552 100644
--- a/common/cmd_nvedit.c
+++ b/common/cmd_nvedit.c
@@ -194,32 +194,23 @@  static int do_env_grep (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[
 #endif
 
 /*
- * Set a new environment variable,
- * or replace or delete an existing one.
+ * Performs consistency checking before setting, replacing,
+ * or deleting an environment variable, then (if successful)
+ * apply the changes to internals so to make them effective.
+ * Code for this function was taken out of _do_env_set(),
+ * which now calls it.
+ * Also called as a callback function by himport_ex().
+ * Returns 0 in case of success, 1 in case of failure.
+ * When (flag & H_FORCE) is set, force overwriting of
+ * write-once variables.
  */
 
-int _do_env_set (int flag, int argc, char * const argv[])
+int env_check_apply(const char *name, const char *oldval,
+		    const char *newval, int flag)
 {
 	bd_t  *bd = gd->bd;
-	int   i, len;
+	int   i;
 	int   console = -1;
-	char  *name, *value, *s;
-	ENTRY e, *ep;
-
-	name = argv[1];
-
-	if (strchr(name, '=')) {
-		printf("## Error: illegal character '=' in variable name \"%s\"\n", name);
-		return 1;
-	}
-
-	env_id++;
-	/*
-	 * search if variable with this name already exists
-	 */
-	e.key = name;
-	e.data = NULL;
-	hsearch_r(e, FIND, &ep, &env_htab);
 
 	/* Check for console redirection */
 	if (strcmp(name, "stdin") == 0)
@@ -230,22 +221,23 @@  int _do_env_set (int flag, int argc, char * const argv[])
 		console = stderr;
 
 	if (console != -1) {
-		if (argc < 3) {		/* Cannot delete it! */
+		if ((newval == NULL) || (*newval == '\0')) {
+			/* We cannot delete stdin/stdout/stderr */
 			printf("Can't delete \"%s\"\n", name);
 			return 1;
 		}
 
 #ifdef CONFIG_CONSOLE_MUX
-		i = iomux_doenv(console, argv[2]);
+		i = iomux_doenv(console, newval);
 		if (i)
 			return i;
 #else
 		/* Try assigning specified device */
-		if (console_assign(console, argv[2]) < 0)
+		if (console_assign(console, newval) < 0)
 			return 1;
 
 #ifdef CONFIG_SERIAL_MULTI
-		if (serial_assign(argv[2]) < 0)
+		if (serial_assign(newval) < 0)
 			return 1;
 #endif
 #endif /* CONFIG_CONSOLE_MUX */
@@ -255,23 +247,29 @@  int _do_env_set (int flag, int argc, char * const argv[])
 	 * Some variables like "ethaddr" and "serial#" can be set only
 	 * once and cannot be deleted; also, "ver" is readonly.
 	 */
-	if (ep) {		/* variable exists */
+	if ((oldval != NULL) /* variable exists */
+	 && ((flag & H_FORCE) == 0)) { /* and we are not forced */
 #ifndef CONFIG_ENV_OVERWRITE
 		if ((strcmp(name, "serial#") == 0) ||
 		    ((strcmp(name, "ethaddr") == 0)
 #if defined(CONFIG_OVERWRITE_ETHADDR_ONCE) && defined(CONFIG_ETHADDR)
-		     && (strcmp(ep->data, MK_STR(CONFIG_ETHADDR)) != 0)
+		     && (strcmp(oldval, MK_STR(CONFIG_ETHADDR)) != 0)
 #endif	/* CONFIG_OVERWRITE_ETHADDR_ONCE && CONFIG_ETHADDR */
 		    ) ) {
 			printf("Can't overwrite \"%s\"\n", name);
 			return 1;
 		}
 #endif
+	}
+	/* if variable exists... */
+	if ((oldval != NULL)
+	/* or we are in a scratched-out environment */
+	|| ((flag & H_NOCLEAR) == 0)) {
 		/*
 		 * Switch to new baudrate if new baudrate is supported
 		 */
 		if (strcmp(name, "baudrate") == 0) {
-			int baudrate = simple_strtoul(argv[2], NULL, 10);
+			int baudrate = simple_strtoul(newval, NULL, 10);
 			int i;
 			for (i = 0; i < N_BAUDRATES; ++i) {
 				if (baudrate == baudrate_table[i])
@@ -282,6 +280,10 @@  int _do_env_set (int flag, int argc, char * const argv[])
 					baudrate);
 				return 1;
 			}
+			if (gd->baudrate == baudrate) {
+				/* If unchanged, we just say it's OK */
+				return 0;
+			}
 			printf ("## Switch baudrate to %d bps and press ENTER ...\n",
 				baudrate);
 			udelay(50000);
@@ -299,6 +301,72 @@  int _do_env_set (int flag, int argc, char * const argv[])
 		}
 	}
 
+	/*
+	 * Some variables should be updated when the corresponding
+	 * entry in the environment is changed
+	 */
+
+	if (strcmp(name, "ipaddr") == 0) {
+		const char *s = newval;	/* always use only one arg */
+		char *e;
+		unsigned long addr;
+		bd->bi_ip_addr = 0;
+		for (addr = 0, i = 0; i < 4; ++i) {
+			ulong val = s ? simple_strtoul(s, &e, 10) : 0;
+			addr <<= 8;
+			addr  |= (val & 0xFF);
+			if (s)
+				s = (*e) ? e+1 : e;
+		}
+		bd->bi_ip_addr = htonl(addr);
+		return 0;
+	} else if (strcmp(newval, "loadaddr") == 0) {
+		load_addr = simple_strtoul(newval, NULL, 16);
+		return 0;
+	}
+#if defined(CONFIG_CMD_NET)
+	else if (strcmp(newval, "bootfile") == 0) {
+		copy_filename(BootFile, newval, sizeof(BootFile));
+		return 0;
+	}
+#endif
+	return 0;
+}
+
+/*
+ * Set a new environment variable,
+ * or replace or delete an existing one.
+*/
+int _do_env_set(int flag, int argc, char * const argv[])
+{
+	int   i, len;
+	char  *name, *value, *s;
+	ENTRY e, *ep;
+
+	name = argv[1];
+	value = argv[2];
+
+	if (strchr(name, '=')) {
+		printf("## Error: illegal character '='"
+		       "in variable name \"%s\"\n", name);
+		return 1;
+	}
+
+	env_id++;
+	/*
+	 * search if variable with this name already exists
+	 */
+	e.key = name;
+	e.data = NULL;
+	hsearch_r(e, FIND, &ep, &env_htab);
+
+	/* Perform requested checks. Notice how since we are overwriting
+	 * a single variable, we need to set H_NOCLEAR */
+	if (env_check_apply(name, ep ? ep->data : NULL, value, H_NOCLEAR)) {
+		debug("check function did not approve, refusing\n");
+		return 1;
+	}
+
 	/* Delete only ? */
 	if ((argc < 3) || argv[2] == NULL) {
 		int rc = hdelete_r(name, &env_htab);
@@ -336,34 +404,6 @@  int _do_env_set (int flag, int argc, char * const argv[])
 		return 1;
 	}
 
-	/*
-	 * Some variables should be updated when the corresponding
-	 * entry in the environment is changed
-	 */
-
-	if (strcmp(name, "ipaddr") == 0) {
-		char *s = argv[2];	/* always use only one arg */
-		char *e;
-		unsigned long addr;
-		bd->bi_ip_addr = 0;
-		for (addr = 0, i = 0; i < 4; ++i) {
-			ulong val = s ? simple_strtoul(s, &e, 10) : 0;
-			addr <<= 8;
-			addr  |= (val & 0xFF);
-			if (s) s = (*e) ? e+1 : e;
-		}
-		bd->bi_ip_addr = htonl(addr);
-		return 0;
-	} else if (strcmp(argv[1], "loadaddr") == 0) {
-		load_addr = simple_strtoul(argv[2], NULL, 16);
-		return 0;
-	}
-#if defined(CONFIG_CMD_NET)
-	else if (strcmp(argv[1], "bootfile") == 0) {
-		copy_filename(BootFile, argv[2], sizeof(BootFile));
-		return 0;
-	}
-#endif
 	return 0;
 }
 
diff --git a/common/env_common.c b/common/env_common.c
index c7e9bea..db607e1 100644
--- a/common/env_common.c
+++ b/common/env_common.c
@@ -172,6 +172,9 @@  const uchar *env_get_addr (int index)
 
 void set_default_env(const char *s)
 {
+	/* By default, do not apply changes as they will eventually
+	 * be applied by someone else */
+	apply_cb apply_function = NULL;
 	if (sizeof(default_environment) > ENV_SIZE) {
 		puts("*** Error - default environment is too large\n\n");
 		return;
@@ -183,14 +186,22 @@  void set_default_env(const char *s)
 				"using default environment\n\n",
 				s+1);
 		} else {
+			/* This set_to_default was explicitly asked for
+			 * by the user, as opposed to being a recovery
+			 * mechanism. Therefore we chack every single
+			 * variable and apply changes to the system
+			 * right away (e.g. baudrate, console).
+			 */
+			apply_function = env_check_apply;
 			puts(s);
 		}
 	} else {
 		puts("Using default environment\n\n");
 	}
 
-	if (himport_r(&env_htab, (char *)default_environment,
-		    sizeof(default_environment), '\0', 0) == 0) {
+	if (himport_ex(&env_htab, (char *)default_environment,
+		    sizeof(default_environment), '\0', 0,
+		      0, NULL, apply_function) == 0) {
 		error("Environment import failed: errno = %d\n", errno);
 	}
 	gd->flags |= GD_FLG_ENV_READY;
diff --git a/include/environment.h b/include/environment.h
index 6394a96..cd98f91 100644
--- a/include/environment.h
+++ b/include/environment.h
@@ -174,6 +174,13 @@  void set_default_env(const char *s);
 /* Import from binary representation into hash table */
 int env_import(const char *buf, int check);
 
+/*
+ * Check if variable "name" can be changed from oldval to newval,
+ * and if so, apply the changes (e.g. baudrate)
+ */
+int env_check_apply(const char *name, const char *oldval,
+		    const char *newval, int flag);
+
 #endif
 
 #endif	/* _ENVIRONMENT_H_ */
diff --git a/include/search.h b/include/search.h
index b4edd43..4ac7171 100644
--- a/include/search.h
+++ b/include/search.h
@@ -46,6 +46,11 @@  typedef struct entry {
 /* Opaque type for internal use.  */
 struct _ENTRY;
 
+/* Callback function to be called for checking whether the given change may
+ * be applied or not. Must return 0 for approval, 1 for denial. */
+typedef int (*apply_cb)(const char *name, const char *oldval,
+			const char *newval, int flag);
+
 /*
  * Family of hash table handling functions.  The functions also
  * have reentrant counterparts ending with _r.  The non-reentrant
@@ -97,7 +102,15 @@  extern int himport_r(struct hsearch_data *__htab,
 		     const char *__env, size_t __size, const char __sep,
 		     int __flag);
 
+extern int himport_ex(struct hsearch_data *__htab,
+		     const char *__env, size_t __size, const char __sep,
+		     int __flag,
+		     int __argc, char * const __argv[],
+		     apply_cb apply);
+
+
 /* Flags for himport_r() */
 #define	H_NOCLEAR	1	/* do not clear hash table before importing */
+#define H_FORCE		2	/* overwrite read-only/write-once variables */
 
 #endif /* search.h */
diff --git a/lib/hashtable.c b/lib/hashtable.c
index 6895550..a2c268f 100644
--- a/lib/hashtable.c
+++ b/lib/hashtable.c
@@ -630,6 +630,33 @@  ssize_t hexport_r(struct hsearch_data *htab, const char sep,
 int himport_r(struct hsearch_data *htab,
 	      const char *env, size_t size, const char sep, int flag)
 {
+	return himport_ex(htab, env, size, sep, flag, 0, NULL, NULL);
+}
+
+/* Check whether variable name is amongst vars[] */
+static int process_var(const char *name, int nvars, char * const vars[])
+{
+	int i = 0;
+	/* No variables specified means process all of them*/
+	if (nvars == 0)
+		return 1;
+
+	for (i = 0; i < nvars; i++) {
+		if (!strcmp(name, vars[i]))
+			return 1;
+	}
+	debug("Skipping non-listed variable %s\n", name);
+	return 0;
+}
+
+
+
+int himport_ex(struct hsearch_data *htab,
+	      const char *env, size_t size, const char sep, int flag,
+	      int nvars, char * const vars[],
+	      int(*apply)(const char *, const char *, const char *, int)
+	      )
+{
 	char *data, *sp, *dp, *name, *value;
 
 	/* Test for correct arguments.  */
@@ -715,6 +742,8 @@  int himport_r(struct hsearch_data *htab,
 			*dp++ = '\0';	/* terminate name */
 
 			debug("DELETE CANDIDATE: \"%s\"\n", name);
+			if (!process_var(name, nvars, vars))
+				continue;
 
 			if (hdelete_r(name, htab) == 0)
 				debug("DELETE ERROR ##############################\n");
@@ -732,10 +761,31 @@  int himport_r(struct hsearch_data *htab,
 		*sp++ = '\0';	/* terminate value */
 		++dp;
 
+		/* Skip variables which are not supposed to be treated */
+		if (!process_var(name, nvars, vars))
+			continue;
+
 		/* enter into hash table */
 		e.key = name;
 		e.data = value;
 
+		/* if there is an apply function, check what it has to say */
+		if (apply != NULL) {
+			debug("searching before calling cb function"
+			      " for  %s\n", name);
+			/*
+			 * Search for variable in existing env, so to pass
+			 * its previous value to the apply callback
+			 */
+			hsearch_r(e, FIND, &rv, htab);
+			debug("previous value was %s\n", rv ? rv->data : "");
+			if (apply(name, rv ? rv->data : NULL, value, flag)) {
+				debug("callback function refused to set"
+				      " variable %s, skipping it!\n", name);
+				continue;
+			}
+		}
+
 		hsearch_r(e, ENTER, &rv, htab);
 		if (rv == NULL) {
 			printf("himport_r: can't insert \"%s=%s\" into hash table\n",